Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 09/24/2017 in all areas

  1. Thanks. Just to clarify, this is not a core module, and won't ever be. When it comes to the core, I think it's best to intentionally limit the front-end "inputs", and leave anything further to one's own template files or modules that you may install (like this one). That way, we can be certain that the common front-end inputs to ProcessWire sites never exceeds the actual needs of an individual site, which I think is good for security. It already supports multi-language. It uses scssphp and lessphp. People who have already rolled their own solutions may prefer to stick with what they have, since presumably you've customized it to your needs and workflow already. But the compilation in ProCache is definitely handy, and I think folks that haven't already settled on a workflow of their own may find the one built into ProCache very useful. ProCache has always monitored your CSS and JS files for changes (and now SCSS and LESS files) to determine when it needs to merge and minify them. So making scssphp/lessphp part of that process makes a lot of sense. No external watchers, editors or background processes are needed. It's also handy if you want a common solution between servers that works regardless of whether in the dev environment, staging environment, or directly on the server, etc. It's nice knowing that a change will get compiled regardless of how or where the file is edited. You could disable it by editing the module file. But I wouldn't recommend it. A form that allows one to create a new ProcessWire login account without validation would quickly get abused. Over time it would just fill up with millions of bot accounts.
    7 points
  2. Hi Ryan, Great to see the registration/login module - very appreciated. In the next version, could you make the createConfirmationCode() method hookable so we can supply our own generators? Actually, only the generation of the code needs to be hookable - the scaffolding in that method to store the generated code could stay as it is. Many thanks!
    4 points
  3. $yesterdayEvening = strtotime('yesterday 21:00'); $todayEvening = strtotime('today 21:00'); $latest = $pages("<your selector>, created>=$yesterdayEvening, created<=$todayEvening"); http://php.net/manual/en/datetime.formats.relative.php
    3 points
  4. That's a remnant from times with PHP < 5.4, where the register_globals setting in php.ini was still often set to true. This meant that every GET or POST parameter was added as a global variable of the same name. If programmers were just a tiny bit sloppy and forgot to initialize their global variables with reasonable default values, this lead to security issues since malicious visitors could set their desired values. A simple example would be a PHP script with an authorization check. Let's suppose our hacker calls it with the URL http://my.broken.site/page.php?auth=1 <?php // Authorization check if(is_user_authorized()) { // we only set $auth to a truthy value when the check was successful $auth = true; } if($auth) { show_sensitive_content(); } In that example, $auth isn't set to anything if is_user_authorized fails, so our hacker created a global variable $auth from the GET parameter with a truthy value (1) and that never gets overwritten. He can see our sensitive content. Ouch. To prevent these kinds of problems, it was good practice to remove all globals before populating your own.
    3 points
  5. Sorry to intervene with another topic but AOS stops Lister Pro from being able to list its own custom configured columns. With AOS enabled, its own "ListerTweaks" settings are enforced. It took me some time to figure out what is going on. @Rudy ran into the very same issue two weeks ago, and reported it in the Lister Pro forum as a "bug". These enforced "ListerTweaks" should be handled more gracefully I think. Fist of all, there should be an option to turn them off, letting Lister Pro do all this instead. Second, when it is turned on, there should be a notification for superusers above the listers in question as a reminder that AOS is "in effect". What do you guys think?
    2 points
  6. Cool. But I do think it makes sense for utilities like CodeMirror or Ace to exist as separate inputfield modules so that they can be used elsewhere in Page Edit, other modules, etc, rather that duplicated within every module that uses them. Things like this are not really dependencies (a plain textarea works fine without them) but more a progressive enhancement.
    2 points
  7. It's SO SO AWESOME! Million thanks, Ryan and Michael!
    2 points
  8. Wow, super update this week! The SCSS compilation feature in ProCache sounds great. Currently I have a roll-my-own solution using scssphp - does the new ProCache feature use scssphp or something different? The front-end users module is awesome news - it's one of those few missing pieces that PW has been really needing. Beginners especially will benefit from this, and because of the security considerations that come with a login system it's great to have a solution from PW's creator. I was expecting that such a module would be a "Pro" release, so big thanks for making this a free module! Can't wait to try it.
    2 points
  9. A fantastic upgrade to ProcessWire's core capabilities. Thanks for making our lives easier.
    2 points
  10. I was going to start working on a new site for myself and wife (a new hobby we have taken up), and had decided to try out Runcloud and Digital Ocean. I got my drop set up on digital ocean, as well as setting up various hooks/databases etc between github and run cloud. However, now I have hit a wall. I cloned my "blank" repository into my local host (managed through MAMP) and dropped in a fresh install of PW, but now I have no idea of how to move forward. Is it best to just work locally, and then push this into a branch, and when ready, change branches and commit all to run cloud? Run cloud gives me an IP address to use for the database, but I can't get my localhost setup to recognize (I just get "Connection refused"). I am also unsure how to actually get my commits to push to run cloud, and handling the new set up. I am probably in over my head, but I thought I would try something new as a good learning experience. However, now I am just drowning . Hopefully someone has some ideas on how to approach this, as I am very eager to get under way.
    1 point
  11. https://www.baumrock.com/portfolio/individuelles-crm-und-controlling-tool/ I'm happy to share my biggest and most interesting ProcessWire project so far with you It's a 100% custom office-management solution that helps my client to keep track of all their contacts, projects and finance/controlling stuff. Conception was done back in 2016 and the software is productive since begin of this year. My client is very happy with the result and so am I. Some technical insights: Everything is done inside the PW Admin. I'm using the Reno Theme with some custom colors. In the beginning I was not sure if I should stay with the pw admin or build my own admin-framework but now I'm VERY happy that I went with PW Almost all of my custom Process Pages use my RockDatatables module - there are still some limitations but without it, this project would not have been possible For the charts I used Google Charts and chartjs - both play well together with the datatables and make it possible to display filtered data instantly: also my handsontable module was created for this project to have a nice and quick option for matrix data inputs: Lister and ListerPro were no options as i needed much more flexibility regarding data presentation (like colorization, filtering and building sums of selected rows): invoices are highly customisable as well and easy to create. PDFs are created by php and mPDF by the way: all data is dummy data populated via my Module RockDummyData have a nice weekend everybody
    1 point
  12. The automatic backup that occurs when you run an Admin Action is probably best restored with the "Restore" option from the Setup > Admin Actions > Restore menu item. That way you are restoring from just before the action was run giving the best chance of a clean undo. You're welcome - thanks for helping to improve it - hopefully now it will be better for others also.
    1 point
  13. Thanks @adrian! I have not yet tried your restore feature, I just made backups with ProcessDatabaseBackups and used those to restore the DB. Anyway, your action helped me a lot as I did not have to write a single line of code and all the users are imported Thank you!
    1 point
  14. From the top menu > modules > refresh Or go to setup > modules > refresh (the button on top right) http://processwire.com/blog/posts/processwire-core-updates-2.5.14/#multiple-copies-of-the-same-module
    1 point
  15. Thanks @szabesz - I have fixed the username issue in the latest version. I am not sure what to do about the timeout - I used PHP's set_time_limit to remove the time limit - maybe it's a weird MAMP thing? Not sure about the backup restore - I am using the core WireDatabaseBackup class to run the restore. Maybe let me know if you come across this again and I'll try to replicate. Thanks!
    1 point
  16. @adrian I had some time to test the new version. My findings are: usernames with space make the import fail with error (Unknown Selector operator). Previous version worked by trimming space from the beginning and from the end, and at the same time converting spaces to dash found in-between. I did not notice the latter until now, so last time I got two users with dashes in them. At least now I know I need to fix those manually I still got timeout issue with 134 users on MAMP Pro but 32 user were ok to import. Note that current version of MAMP is rather buggy, it might be related to that or it might not. I do not really know. Otherwise duplicate user warnings were ok. For the first time (and only for the very first time) I had an issue reverting back to a database backup after the failed user import because of spaces. I used the core Revert to Backup feature and afterwards the – local staging – site was throwing a lot of: Warning: Invalid argument supplied for foreach() in .../site/assets/cache/FileCompiler/site/modules/TracyDebugger/TracyDebugger.module on line 1257 I tried clearing the cache directory but it did not help, things got worse, the site was brought down by: User Error Exception: You do not have permission to execute this module - ProcessPageView (in .../wire/core/Modules.php line 1236) #0 .../wire/core/Modules.php(1141): ProcessWire\Modules->getModule('ProcessPageView') #1 .../index.php(53): ProcessWire\Modules->get('ProcessPageView') I replaced the database with the one from the production site and all was good afterwards. As I said, it happened only the first time, subsequent reverts in the admin did not produce this.
    1 point
  17. Thanks for your reply. Indeed there was some misunderstanding. I got your solution working now and should be fine for now. Thanks @horst .
    1 point
  18. Running a little autumn sale, so if you haven't tried or bought Padloper yet, now is good time! https://www.padloper.pw/buy/ 30 day money back (no questions asked) if it doesn't fit your needs.
    1 point
  19. Hey, thanks for the input. I was putting my head into it quite a few time yesterday, and messed up something. Took a while to figure it all out today. It can get complicated. You refactor stuff, then suddenly it all messed up. I commited a new version with some of your input and various fixes. https://github.com/somatonic/Aligator/commit/dc4d8aa19ff665e24aa07ccba65fd3aff0d4e002 The static level I also recognized that it gives problem when using more than one menu. Also the default options now carry over all levels. I don't think a "all" array is needed just for that, since it was the intention to have a default that is the fallback. I added a $states variable to callback (third argument) that returns a string with classes for the different states. You can enable it and configure it too. Something like this was my testing scenario: /** * load Alitgaor module * -------------------------------------------------------------------------------- */ $nav = $modules->Aligator; /** * first menu * using PageArray for first level and prepend root page * -------------------------------------------------------------------------------- */ $menuPages = new PageArray(); $home = $pages->get("/"); $menuPages->add($home->children("template=basic-page")); $menuPages->prepend($home); $nav->enableStates = true; // enable states ("parent current has_children first last") $nav->levels = 3; // set max levels to render // the default options for all levels $nav->setDefaultOptions(array( "selector" => "template=basic-page", "callback" => function($item, $level, $states){ // $states is a string of item state classes to insert somewhere $classes = $states ? " class='$states'" : ""; return array( "item" => "<a href='$item->url'>$item->title</a>", "listOpen" => "<li$classes>", "listClose" => "</li>", "wrapperOpen" => "<ul class='dropdown'>", "wrapperClose" => "</ul>", ); } ) ); // render the menu $content .= $nav->render($menuPages, array( array( // level1 "selector" => "template=basic-page", ), array( // level2 "selector" => "template=basic-page|article" ) )); /** * render different menu with default options and using a root page * -------------------------------------------------------------------------------- */ $nav->levels = 4; $nav->collapsed = true; $nav->setDefaultStates(array("is_current" => "active")); $nav->setDefaultOptions(array( "selector" => "template=basic-page", "callback" => function($item, $level, $states){ return array( "item" => "<a href='$item->url'>$item->title</a>", "listOpen" => "<li class='$states'>", "listClose" => "</li>", "wrapperOpen" => "<ol>", "wrapperClose" => "</ol>" ); } ) ); $content .= $nav->render($pages->get("/")); I'm not sure, there's possibly still something that isn't covered or I missed but seems working fine here. Thanks
    1 point
  20. Refresh the module cache, it should ask you which copy of the module to use.
    1 point
  21. Posting some more stuff while it is fresh in my mind... I made a new commit here. Changes... 1. Fix for selector not falling back to what is defined in the default options. 2. Allows menu options to be defined for all levels by using "all" as the options array key. Example: $menuOptions = array( // use these options for all levels in this menu "all" => array( "selector" => "template=basic-page|domain_root", "callback" => function($item, $level){ $class = $item === wire("page") ? " current" : ""; $class .= wire("page")->parents->has($item) ? " parent" : ""; $class .= $item->numChildren("template=basic-page") ? " has_children" : ""; return array( "item" => "<a href='$item->url'>$item->title $item->template</a>", "listOpen" => "<li class='level$level$class'>", "listClose" => "</li>", "wrapperOpen" => "<ul class='mainnav'>", "wrapperClose" => "</ul>", ); }, ) ); Setting an explicit array key also made me think of something else that it would be good to mention in the module readme. If you want to set options only for level 3 (for example) it isn't necessary to include anything for the other levels. Instead of... $menuOptions = array( array(), // level 1 array(), // level 2 array( // level 3 "selector" => "template=basic-page", ), ); ...you can do... $menuOptions = array( // options for level 3 (array keys are zero-indexed) 2 => array( "selector" => "template=basic-page", ), ); And an issue to report: there is a problem when using Aligator to render more than one menu - the $level variable in the render() method can be incorrect for any menus after the first menu. This is because $level is declared as a static variable, so after the first menu is rendered $level can retain its value when it should be reset to zero for each menu that is rendered. Not sure of the best way to fix that (the whole static variable / recursive function thing makes my head spin). Edit: In this commit I changed from the static variable to passing $level as an argument to render() and it seems like an okay solution.
    1 point
  22. Thank you, Robin S, for the response. I must have missed your first one, so I apologize for not reporting the issue myself. But, thanks for the assist. It seems to me that you have represented my problem accurately with your example. The problem arises with multiple selectors and because it looks like the code does the actual filtering (destructive) as soon as it finds a match as it loops through the array of selector items parsed from the selector as a whole. Thanks again. I appreciate your response.
    1 point
  23. You can upload your site files after zip, via scp also scp local_site.zip runcloud@server-ip-address:webapps/your-web-app-path/ If you read documentation, database section you can see the answer : https://runcloud.io/docs/server/database.html#rc-docs-scroll You need to add 3306/tcp port, like here. after add port to your firewall settings, you can connect your database with your server ip from anywhere. You can use Sequel Pro app for connect to your database. After you done with database, don't forget to remove 3306/tcp port!
    1 point
  24. From the top of my head: I've built a small schema for OSS that has the following additional fields: PW language name groups (multivalued) page id type indicator field for file or page to limit results to one of those if required an additional file classification field to search for special documents (e.g. process instructions, sales catalogs...) In a save handler, I call my search update routine that: removes all entries in OSS for the current page id includes the search engine update logic for the current template that in turn: extracts the content extracts information on all files that should be in the search adds a search entry through OSS' REST API for each of those for each language with page id, language, type and all permitted groups My search routine then only needs to pass the current user's groups (from @apeisa's essential UserGroups module) and optionally the language to the search API as facet filters to get permission-filtered results. I'm in the process of moving the actual update action to background batch jobs since the number of files and their sizes are constantly growing, slowing down page editing. This will have the nice added effect that I can run the updating logic on one or more different servers by sharing the file system between them. And, of course, there's a script for worst cases that runs through all pages and builds the search index from scratch.
    1 point
  25. Why isn't it WordPress?
    1 point
  26. Wonderful to see a native Login script. I'd say it's in the top 5 queries I have when I show PW to another designer/developer.
    1 point
  27. If you mean what I think you mean, then you can hook before InputfieldSelect::renderValue and change option labels depending on a field value. Haven't tried this, but it's a good start. $this->addHookBefore('InputfieldSelect::renderValue', function (HookEvent $e) { /** @var $select InputfieldSelect */ /** @var $page Page */ $select = $e->object; $page = $select->hasPage(); $options = $select->getOptions(); $options['myOption'] = $options['myOption'] . " -- " . $page->myStatusField; $select->set('options', $options); });
    1 point
  28. Cloudinary.com seems to offer everything you need and some more. You can get it to fetch images from your server on the fly and serve the right size image to visitors device without uploading images beforehand. Free tier is quite generous, too. https://cloudinary.com/features
    1 point
  29. You can use localStorage to save and restore scroll position. Something to start with: (not tested) function saveScroll(href) { // save current scroll position for this page localStorage.setItem('scroll__' + href, window.scrollY); } function restoreScroll(href) { // restore previous scroll or scroll to top let scroll = localStorage.getItem('scroll__' + href); $('html, body').animate({ scrollTop: scroll ? scroll : 0 }, 10); } window.addEventListener('beforeunload', function (e) { // remove scroll position localStorage.removeItem('scroll__' + location.pathname); }); $(document).on('click', 'a:not(.external)', function (e) { saveScroll(this.href); history.pushState(null, null, this.href); replacePage(this.href); e.preventDefault(); }); $(window).bind('popstate', function () { replacePage(location.pathname); restoreScroll(location.pathname); }); https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage
    1 point
  30. MySQL usually listens to loopback interface (127.0.0.1) and only responds to requests coming from the machine itself, like PHP or NodeJS etc (unless you're using a convoluted multi-server DB architecture and have configured PW to connect another machine on the network). So you dont have to change 127.0.0.1 to localhost. In fact leaving it that way will eliminate a (non-zero but very small) delay caused resolving host names to their IP addresses.
    1 point
  31. wow you should take a break ... glad to hear you're ok, watch on tv Irma was really bad
    1 point
  32. 1 point
  33. Have done this for image fields, it adds a button to the end of the inputfield, code below. Checks for ZipArchive class before installing. Now that I read the code it should work for files but haven't tested! It's got configuration options too, to enable per field basis, either way should it should be super quick to edit if something is not working. <?php class ExportFieldImages extends WireData implements Module, ConfigurableModule { static public function getDefaultConfig() { return array( "includeFields" => '' ); } public static function install(){ $session = wire("session"); if(!class_exists('\ZipArchive')){ throw new WireException("ZipArchive is required to create the zip file"); } } public static function getModuleInfo() { return array( 'title' => 'ExportFieldImages', 'version' => 0.1, 'summary' => "Adds a button bellow images field to download a zip containing files.", 'author' => 'Eduardo San Miguel Garcia', 'singular' => true, 'href' => '', 'autoload' => true ); } public function init() { $this->addHookAfter('InputfieldImage::render', $this, 'afterInputfieldImageRender'); $this->addHookAfter("ProcessPageEdit::execute", $this, "pageEditExecuteBefore"); } public function pageEditExecuteBefore(HookEvent $event){ $session = wire("session"); $input = wire("input"); $page = wire('pages')->get($input->get->id); $name = $page->name; $zip = $config->paths->cache . "${$name}.zip"; if($input->get->downloadImages == "true"){ wire("log")->save("custom", "excecuted page edit!"); $array = wire('files')->zip($zip, $page->get($input->get->field)->explode("filename"), array("overwrite" => true) ); if(!empty($array["errors"])){ foreach($array["errors"] as $error){ $this->error($error); } return; } else{ header('Content-Type: application/zip'); header("Content-Disposition: attachment; filename='{$name}.zip'"); echo readfile($zip); return $this->halt(); } } } public function afterInputfieldImageRender(HookEvent $event){ $field = $event->object; $input = wire("input"); $configData = wire('modules')->getModuleConfigData($this); $out = $event->return; if(in_array( $field->name, $configData['includeFields'])){ $button = wire('modules')->get('InputfieldButton'); $button->class = $button->class . " ExportFieldImages"; $button->icon = 'download'; $button->href = "./?downloadImages=true&field={$field->name}&id={$input->get->id}"; $button->value = "Download Files"; $btn .= "<span style='display:block; position:relative; float:right;' class='InputfieldPageTableButtons'>" . $button->render() . "</span>"; $out .= $btn; } $event->return = $out; } public function getModuleConfigInputfields(array $data){ $modules = wire("modules"); $fields = wire('fields'); $defaults = self::getDefaultConfig(); $data = array_merge($defaults, $data); $form = new InputfieldWrapper(); $field = $modules->get("InputfieldAsmSelect"); $field->name = "includeFields"; $field->label = __("Fields to enable download button"); $field->description = __("Choose the image fields where download button should appear"); foreach($fields as $f){ if($f->flags & Field::flagSystem) continue; if($f->type == "FieldtypeImage" || $f->type == "FieldtypeFile"){ $field->addOption($f->name); } } $field->value = $data['includeFields']; $form->add($field); return $form; } }
    1 point
  34. I'm interested to learn how this all works. Please nudge me to the right direction, with links perhaps, or examples specific to PW :).
    1 point
  35. We started using mustache template engine with PW. Since mustache is implemented in various languages. Currently I can render anything either server side or client side with js or php and both share the same code base. Data can be either objects arrays or json whatever you like. We also use patternlabs node mustache version for prototyping and so all patterns can be used 1:1 in PW later using some simple controller system based on Classes that extend PW WireData so all API can be used. We also use terrificjs for easy modular js components. So no vue or react but just to mention that there's everything possible in PW.
    1 point
  36. In recent PW3 versions you can prepend "http" and get absolute urls like this: $config->urls->httpTemplates
    1 point
×
×
  • Create New...