Jump to content


Popular Content

Showing content with the highest reputation since 09/19/2019 in all areas

  1. 7 points
    @pwired — there was a time when I'd agree with you, but there are quite a bit of options for I ❤️ PW devs out there - for flat file CMS at least. So in the end I'd say that ProcessWire and its community are better served by focusing at its one thing.
  2. 6 points
    @bernhard's post gives you the clue - it's to do with PW's built-in caching. $page->children() is a method that queries the database. You want to minimise the number of requests to the database because going to the DB is a lot slower than working with objects in memory. In your code you call $page->children() five times, so the expectation is that this would mean five trips to the DB... except that PW tries to help you out and caches the results to avoid unnecessary DB queries. But the exact workings of this caching are undocumented (as far as I know) and so I'd say it's best practice not to rely on it. It would be better to consciously minimise the DB requests in your code - it would make things clearer (i.e. avoid the confusion you're getting from the behind-the-scenes caching) and it's a good habit to get into for when you're working with other PHP projects that might not cache DB query results like PW does. You could rewrite your code like this: $layout->setTemplate('sidebar'); $selector = [ 'template' => 'product', 'sort' => 'title', 'categories' => page('id'), 'limit' => 9 ]; // Just get the children from the DB once // I assume you need all the children at some point later in the code because you dump page()->children() in your example. // If you don't need all the children then just get the categories directly with page()->children('template=category') $children = page()->children(); // Get the categories from the children PageArray (happens in memory) $categories = $children->find('template=category'); // If there are any categories then modify $selector if($categories->count) { $categories->add(page()); $selector['categories'] = $categories; } bd($children); bd($categories); And this might be getting into the zone of micro-optimisation but you could consider if you actually need full Page objects in a PageArray or if you only need the IDs (reduces the memory footprint): $category_ids = page()->children('template=category', ['findIDs' => 1]);; if(count($category_ids)) { $category_ids[] = page()->id; $selector['categories'] = $category_ids; }
  3. 5 points
    @wbmnfktr thanks for the tips 👍 Version so old, cache had only one folder LOL Tested in a staging environment. Upgrade of PW core - almost 150 versions from 2.3.0 to 3.0.141 - worked first time. Gotta love it! Couple of modules needed upgrading and most went smoothly. Solved issues with ProcessCustomAdminPages. Couldn't upgrade so recreated the admin pages and assigned the necessary templates Now resolving a few hiccoughs with custom template code and confident I'll get through
  4. 5 points
    Actually I came to a pretty handy solution with my co-dev! Images have information about their modification time saved within them, so using that I came up with following code: $img = $page->image; // check if image exists if($img) { // fetch cropped images' modification timestamps $tsNormal = filemtime($img->getCrop('normaali')->filename); $tsHigh = filemtime($img->getCrop('korkeampi')->filename); $tsLow = filemtime($img->getCrop('matalampi')->filename); // check if they have the same modification time => user hasn't cropped the image, so use the original if(!($tsNormal == $tsHigh && $tsNormal == $tsLow)) { // stamps are not equal => check which is highest aka last modified switch(max($tsNormal, $tsHigh, $tsLow)) { case $tsNormal: $img = $img->getCrop('normaali'); break; case $tsHigh: $img = $img->getCrop('korkeampi'); break; case $tsLow: $img = $img->getCrop('matalampi'); break; } } } Seems to work quite nicely for my purpose 🙂Thought it would be nice to share, if anybody else wants to achieve similar effect!
  5. 5 points
    *pops head up* I seem to be getting a few more ecommerce enquiries nowadays so happy to test when you're at that stage.
  6. 4 points
    These threads discuss similar issues: While developing you might want to disable fingerprinting from within config.php - it's explained and discussed in the threads above. Another thing you can and might want to doublecheck: CDNs can be sometimes an issue as well; saw this with Cloudflare CDN a few times some browser extensions (privacy and adblock-related ones) can cause those issues as well Pi-Hole can be an issue too Operas built-in-VPN causes these conflicts/problems (especially in tools like Asana and Slack - and PW) And those things are just the few I remembered from similar situations I had to deal with on my own.
  7. 4 points
    You have to hook before the input is processed and make those fields not required. Example: $wire->addHookBefore('ProcessPageEdit::processInput', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->arguments(0); // Only for the ProcessPageEdit form if($form->name !== 'ProcessPageEdit') return; $page = $event->object->getPage(); // Use $page to check for specific templates here... // Check field values in POST $input = $event->wire('input'); if($input->post->delete && $input->post->delete_confirm === 'DELETE') { // Get normally required fields and make them not required $first_name = $form->getChildByName('first_name'); $first_name->required = false; // Repeat for other required fields... // Do your delete/notification/redirect actions here // Or if you need the page to actually save when deleting then do actions in separate Pages::saved hook or similar } });
  8. 4 points
    There is another option to use Processwire explode. As example: $selectors = "parent=$parent,template=page_car,dealer={$dealer_id}"; $cars = $pages->findMany($selectors); $manufacturers = $cars->explode("manufacturer"); Also later you can do and other things, $manufacturers->sort("title") etc... And there are and other nice WireArray methods like implode, filter, and many others... Regards.
  9. 3 points
    Thank you for that suggestion. However the headache is part of learning the platform, so I'm accepting it.
  10. 3 points
    You may want to revise this line. 'get' will return only the first match. To return a page array, you need $pages as well. Try: <?php $children = $pages->find('template=onecolumn|twocolumn, sort=sort');
  11. 3 points
    echo $page->render; Just take into account that this will render the header and footer if you have included them on the child pages templates.
  12. 3 points
    Try hooking after ProcessPageEdit::buildForm. ProcessPageEdit::buildFormContent only contains the page template fields and not the fields from the Children, Settings, etc tabs. Another hurdle is that the value of InputfieldPageAutocomplete is always an array, and ProcessPageEdit expects the value of the parent_id field to be an integer. This seems to be working: $wire->addHookAfter('ProcessPageEdit::buildForm', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->return; $orig_pi_field = $form->getChildByName('parent_id'); $attrs = [ 'collapsed', 'required', 'label', 'icon', 'id', 'name', 'value', ]; $new_pi_field = $event->wire('modules')->get('InputfieldPageAutocomplete'); $form->insertAfter($new_pi_field, $orig_pi_field); $form->remove($orig_pi_field); foreach($attrs as $attr) { $new_pi_field->$attr = $orig_pi_field->$attr; } $new_pi_field->maxSelectedItems = 1; }); $wire->addHookAfter('ProcessPageEdit::processInput', function(HookEvent $event) { /* @var InputfieldWrapper $form */ $form = $event->arguments(0); if($form->id !== 'ProcessPageEditSettings') return; $pi_field = $form->getChildByName('parent_id'); if(!$pi_field || !$pi_field->isChanged()) return; $parent_id = $pi_field->value; $parent_id = (int) reset($parent_id); /* @var Page $page */ $page = $event->object->getPage(); $page->parent_id = $parent_id; });
  13. 3 points
    Updates 🙂 https://2017.stateofjs.com https://2018.stateofjs.com/ https://2019.stateofcss.com/
  14. 3 points
    Go to /processwire/module/edit?name=TracyDebugger edit Tracy's settings: Check this option That way only Superusers can see Tracy on the live site. Hope that helps
  15. 3 points
    AdminBar 2.4.0 is out and adds support for the "data-adminbar-adjust" attribute. The idea here is to automatically modify (or adjust) certain CSS properties whenever the height of the Admin Bar is recalculated. Note: AdminBar already automatically adds "padding-top: [Admin Bar height in px]" to the <html> element, so this feature mainly applies to elements with "position: fixed". Assuming that Admin Bar is displayed and is 100px tall at the moment, the following markup... <div data-adminbar-adjust="top max-height"></div> ... would result in this: <div style="top: 100px; max-height: calc(100% - 100px);" data-adminbar-adjust="top max-height"></div> Thanks to @Fokke for the idea 🙂
  16. 2 points
    As you can read in the previous posts there are some issues with the module right now. There haven't been any updates so far in the official repository. So you might have to dig through errors and fix them. Right now I wouldn't recommend this module in any project unless you want to take care of all possible issues. What's the main feature you are looking for? There are several other modules out there so maybe we can find a solution for your needs.
  17. 2 points
    In my case, sessions were not handled correctly. In order to fix it: 1. I installed the core module Session Handler Database (SessionHandlerDB) locally, 2. Create a mysqldump of my local database 3. Imported the mysqldump to my online environment 4. Voila!
  18. 2 points
    Somehow I didn't consider this option at all! Thanks @dragan, I decided to implement this with cookies 🙂 And thanks to you too @horst, I'm sure this will come handy at some point!
  19. 2 points
    It looks like a hook to ProcessPageList::find is working. Here is the code $this->addHookAfter('ProcessPageList::find', function(HookEvent $event) { // Get the object the event occurred on, if needed $ProcessPageList = $event->object; // An 'after' hook can retrieve and/or modify the return value $return = $event->return; // Get values of arguments sent to hook (if needed) $selectorString = $event->arguments(0); $page = $event->arguments(1); $excludePagesByTemplate = array( "newsletter-clinic", "sender_2016", "sender_2016_collab", "inside-news-folder", "basic-page", "event-clinic", "domain_root", "brandportal-index", "key-figures", "jobs", "news", "media-mirror", "worker", "xmlexport", "weekly-menu", "intranet_domain_root", "weekly-menu-index", "daily-menu", "daily-menu-index", "benefit", "benefits-index", "pdiatres-de-garde-index", "xml-feed-index", "courses-index", "help-doc", "stocks-index", "dictionary", "iPad-PDF-Index", "pkb-pikettdienst-index", "heisser-stuhl-index", "heisser-stuhl" ); if($return instanceof PageArray){ foreach($return as $p){ if(in_array($p->template->name, $excludePagesByTemplate)){ if(!$p->editable() && !$p->addable()) { $return->remove($p); } } } } $event->return = $return; }); KR Orkun
  20. 2 points
    @Noel Boss I'm using this code in hooks to Templatefile::render and didn't have any issues with it. if (strpos($_SERVER['REQUEST_URI'], $this->wire('config')->urls->admin) === 0 || $this->wire('page')->template->name == 'admin') return;
  21. 2 points
    Doesn't this work? if ($this->page->template == 'admin') { echo "in admin"; } else { echo "not in admin"; } It surely works in ready.php. (Maybe you'd have to alter the syntax a bit... wire instead of this) Just tried this inside one of my modules, and it works as expected: public function init() { parent::init(); if ($this->page->template == 'admin') { $this->wire->message("in admin"); } else { $this->wire->message("not in admin"); } }
  22. 2 points
    Looks like you need to include jquery in your page (see point 4 in the lightbox2 getting started docs).
  23. 2 points
    It seems that the website is very simple in its structure: lists/details structure.. maybe even with the ProcessBlog module and using categories you can make the whole site. If I had to do it, I would do the following process without having to study another platform or make new code: - I would use a scrapper software on the current site and export the data to a csv file with the fields and names I want. - I would create the templates in PW for the parent listing page / child detail page for each data model or use only one for all with tags/categories, depend on your idea - I would use the ImportPagesCSV module to create all pages in only one step All this you can do without having the html+css design implemented. I think that having the idea of fields and templates, this would not take me more than 4 hours of work. If you don't have access to a scrapper software, there are some extensions for chrome that can help you, or you can make a small code and use https://github.com/paquettg/php-html-parser. The idea with this is to avoid understanding CodeIgniter or the database. I have done this before for marketing affiliate pages = 100% Guaranteed 🙂
  24. 2 points
    I doubt Tracy is the problem, but to disable Tracy you can rename it to .TracyDebugger. Just FTP into the server and rename the folder in site>modules>.TracyDebugger Hope that helps
  25. 2 points
    Assuming the categories are assigned to locations by a Page Reference field named "categories": $locations = $pages->find("template=location"); foreach($locations as $location) { foreach($location->categories as $category) { echo "<marker title='$location->title' category='$category->title'/>"; } }
  26. 2 points
    Actually, it's pretty nice running your API call through the Tracy Console - save it as a snippet so you always have it on hand. This way you can easily see the results of the selector as well as the SQL query used to generate them. PS I think this is the thread that was mentioned regarding teppo's version: https://processwire.com/talk/topic/9408-is-there-a-way-to-convert-a-selector-in-sql-using-pw-engine/ although I think it's actually longer.
  27. 1 point
    I'm using ->url in several spots in my projects and it works. Maybe he messed up something else or maybe our setups are just different. The screenshot looks like he is already using a full disc path /var/www/... and not an url site/assets/... @August Make sure the file exists on your server and then just try different paths/urls and see which one works for you. Start doing it manually without using pw variables and once you have one working example expand on that one.
  28. 1 point
    Well, is there a logic behind it? Icons per page-tree / category? How do you plan to use icons? Inline SVGs? With :before or :after pseudo-selectors in CSS? Icon-fonts? The easiest is to use your own classes and then style items with pseudo-selectors. Or you could use attribute selectors: https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors e.g. .nav a[href^="https://mysite.tld/blog/"]:before {}
  29. 1 point
    I'm getting this error too but it doesn't go away. I had to change static public function getModuleConfigInputfields(array $data) to public function getModuleConfigInputfields($data)
  30. 1 point
    @bee8bit the TFA class is kinda a secret outside of that API page XD I think I am the only 3rd party dev to use the TFA class also. Annoyingly the is a TFA category on the modules directory. but I cant add my module to said category. so the is a link somewhere in processwire that takes you to http://modules.processwire.com/categories/tfa/ where you only see Ryan's own modules. its a shame that the TFA module has so much potential but it feels kinda like something that was developed then hidden away from devs and users
  31. 1 point
    @bee8bit The are ways to call it from the API https://processwire.com/api/ref/tfa/ I have no idea how your custom login form works but I assume your going to need to do some modifications. it will need to check that TFA is active, build the form and process the TFA request. Or if its something another user has created maybe just pester them a lot to update their module to support the TFA class that has been out for like a year already
  32. 1 point
    Put this code inside your ready.php which you will find inside your site/templates/ folder. If there is no such a file then create one (site/templates/ready.php)
  33. 1 point
    @David Karich & @kalimati Which PW version(s) do show this behave? AND: which ImageSizerEngine(s) have you enabled there? (GD | IMagick) We had a change in what image types are supported by IMagick and need to revert back some sorts of PNGs, especially 8bit PNGs are not correct supported by IMagick, and in very rare cases there also was wrong handling for some 8bit-PNGs in GD-Engine. Maybe you can provide the informations plus one or two of the (original uploaded) images in a ZIP to me?
  34. 1 point
    This is exactly what I want to do 🙂 I will try to do it with ajax, thanks for your suggestions!! Right now Iam busy with other projects, but I will try this as soon as I can get back to it. I will keep you posted.
  35. 1 point
    Looks like the plain _() translation method is not available anymore for some reason (perhaps something to do with the changes in the function API that I didn't catch). Could you try out the version at this link and let me know whether that fixes it for you?
  36. 1 point
    using trim() is considered good practice whenever you deal with user input or import/export stuff, so yes: definitely make it a habit.
  37. 1 point
  38. 1 point
    Here is a crazy one for me. I've worked with ProcessWire for years and I have never come across this. I had my website installed on one sub-directory and I moved it to a different one, but all the links in the admin panel other than the home and edit page buttons are linking to the old sub-directory. I always believed that the urls were relative. Has anyone come across this before? I don't know where to look to fix this as the url isn't anywhere like it would be in WordPress for example. I've tried refreshing my cache. EDIT: Nevermind, tried incognito and it worked fine, so it must be a caching issue.
  39. 1 point
    To report back: The modules Page Protector and Protected Mode solve all my riddles. Thanks to @adrian for these fine tools!
  40. 1 point
    Sorry for keeping you in suspense... but crazily I can confirm this works! Thanks for your help 😄
  41. 1 point
    Thank you for sharing with the community. Bummer your client went under 😞 but YAY for a cool profile for us 🙂
  42. 1 point
    New Release 0.6.3 – Codename »hehehe« The last release with a "fix" to the login screen actually broke stuff more than fixing it (thanks @johndoe for reporting this). So this is a fix for the fix… Sorry about that. And some improvements to the login screen on mobile devices. Support Forum ProcessWire Modules Repository Gitlab & Issues Added Fullscreen login screen on mobile 📲 Improved notifications on login screen Fixed Fixed Login screen design 🤯
  43. 1 point
    In PW you cannot have multiple sibling pages with exactly the same name. That's why the pages are automatically renamed - otherwise you would see an error message.
  44. 1 point
    You can check whether page rendered in admin if so, do nothing. if (strpos($_SERVER['REQUEST_URI'], $this->wire('config')->urls->admin) === 0 || $this->wire('page')->template->name == 'admin') return;
  45. 1 point
    The easiest I could think of is to export your models into CSVs using this exporter app or by code with this library, and then upload them using ProcessWire's CSV import module. It would require some planning on how you would map your existing data into ProcessWire tree, and its field/template/page paradigm, but it shouldn't be too hard once you've figured that out.
  46. 1 point
    While working on the comments form of my blog, I thought to add an honeypot field in comments form to reduce spam. 🤨 Honeypot is simply an hidden field added to a form. Honeypot field can have any name and is made invisible normally with a css directive {display: none}. Web users, being unable to see the field, will not fill it, while spam bots majority will not detect its invisibility and will populate the field. Once the form is submitted with a not-empty honeypot field it is very likely we are dealing with spam. 😜 In this post you can find more details about honeypot technique. While studying FieldtypeComments module and in particular CommentForm.php, to my great surprise 👀 I realized that PW already supports honeypot for Comments Form. 🍾🍾 This feature has been introduced with PW 3.0.40. Normally this honeypot field is disabled, so it was enough to understand how to enable it! And as often is the case with PW ... it is super easy. 😎 If in your profile you are directly working with CommentArray, you will just have to enable honeypot passing it as an option to the renderForm() function of CommentArray class, example below: $comments->renderForm(['requireHoneypotField' => 'email2']); And .. we are done! 🍾🍾 If you will look at the html of your Comment Form you will see an additional line CommentFormHP, that's the hidden honeypot field. In case you are using the Uikit 3 Site/Blog Profile, the renderForm() function is called in _uikit.php, ukCommentForm() function. If you wish that honeypot field is applied to every comment form of your site, just add the requireHoneypotField option to the list at the function start: ... 'errorMessage' => __('Your comment was not saved due to one or more errors.') . ' ' . __('Please check that you have completed all fields before submitting again.'), requireHoneypotField' => 'email2', // >>>>> ADD THIS LINE ); ... Otherwise if you wish to add honeypot in comment form on selected templates only, do not modify ukCommentForm(), but pass the option requireHoneypotField when calling the function in your template: ukCommentForm($comments, ['requireHoneypotField' => 'email2']); Now that we enabled it, let test if honeypot works. 🧐 In the browser development section let's select the honeypot field and disable css {display:none} to show it. A new field will appear: If the spam bot is going to fill the field with a value and submit the form, an error is returned and comment will not be submitted 😎 That approach is great as spam comments will not be even saved inside the table field_comments. 🤪 I hope this can be of help if somebody needs to enable this PW comments feature.
  47. 1 point
    UPDATE OK, after I've faced that for and against again, I've decided to make the module freely available. If you are interested, you can test the current state of development. I already put the module on GitHub. Please note that the software is not yet intended for use in a production system. (Alpha version). For example, the configuration and handling of the VAT rates are still missing. Also the dashboard is still incomplete. And many other things needs to be improved and implemented... 🙂 If you like, you can also submit feature requests and suggestions for improvement. I also accept pull requests. https://github.com/gadgetto/SnipWire
  48. 1 point
    What @BitPoet said. In other words, PHP is fast, MySQL is fast. So, there is no guarantee that you will have only 1 page created per second (your date), or even per microsecond! That leaves you with uniqueness dependent only on the customer ID ($client->CustomerCode). If you can guarantee that customer IDs are unique and that they only appear once per data set, (your JSON array) then you would be fine. The fact that you are getting a SQL error tells us that either your customer IDs are not unique and/or one customer ID is appearing more than once in your data set (i.e., it may be uniqe to the customer, but not the data set). If the database says so, then it must be so . Let me illustrate (non-unique customer ID and/or replicated customer ID): $clientCustomerCode = 12345;// replicating repeated use of customer ID $p = $pages->get(1722); for ($i=0; $i < 30; $i++) { // Create new page $new = new Page(); // Create unique hash {no guarantee this will be unique if same customer ID used} $unique = md5(date("Y-m-d H:i:s") . "-" . $clientCustomerCode); // even these (microseconds) do not guarantee uniqueness throughout #$unique = round(microtime(true) * 1000) . "-". $clientCustomerCode; #$unique = microtime(true) . "-". $clientCustomerCode; #$unique = microtime() . "-". $clientCustomerCode; echo $i . ': ' . $unique . '<br>';// display 'uniqueness'; you should see duplicates here // Set some variables for the new page //$new->setOutputFormatting(false);// not needed for a new page (I think) $new->template = "basic-page"; $new->parent = $p; // Create hash $new->title = "Title " . rand(5,15);// just for testing $new->name = $unique;// not really unique! // Save the page #$new->save();// you'll get PDO error here within a second } Using the above code, you'll be hit by the duplicate entry violation error within a second...
  49. 1 point
    Just a short update: if MySQL (or the OS it's running on) and PHP are configured with different time zones, results will be wrong. You'll likely not notice anything off on local dev environments where everything is configured with the same time zone, but to prevent issues on deployment, MySQL needs to be made timezone-aware and PW's database connections need to tell MySQL which timezone to use for conversions, which should IMHO be done through a not-yet-existing $config property. That's why I've filed feature request #19. I'm now holding my fingers crossed and waiting to hear if it gets considered. This will mean that, assuming it does, the module will require at least the PW version that gets the new $config property.
  50. 1 point
    One thing I'm going to be working on soon is adapting Trellis to ProcessWire. If any of you saw my video on adapting Sage for ProcessWire, Trellis is a project by the same group of people (Roots) which allows for you to setup an excellent development + staging + production environment using Ansible (and Vagrant for the development environment). Because of the similarities between WordPress and ProcessWire (well, in terms of the server stack required and the fact that they are both CMSes), a lot can be borrowed from their setup in terms of approach and techniques. They use WP-CLI for some things, but Wireshell can be swapped out for that nicely from what I've researched. I'm really excited to see how it turns out because this has been a huge missing piece to my workflow. This approach would replace things like Capistrano and any other deployment methods, assuming you use a dedicated VM for a site. I highly recommend checking out Trellis to see how it's done. It's thought out very well.
  • Create New...