Jump to content

Robin S

Members
  • Posts

    4,928
  • Joined

  • Days Won

    321

Everything posted by Robin S

  1. I use the following in /site/modules/InputfieldCKEditor/config.js to disallow inline styles. CKEDITOR.editorConfig = function( config ) { config.disallowedContent = '*{*}'; // All styles disallowed };
  2. Yes, the handling of form errors is great now, thanks.
  3. Thanks for the info. Hooking ProcessPageView::execute and calling getPage() seems to have negligible effect on response times. The method only executes once per page view, and getting the page object with getPage() method took an average of 0.0015 seconds in my tests. So I'm not too worried about that aspect. I'm not sure what you mean here - it might return the page object for a different page? Or some aspect of the page can be different? This gave me the same ID each time: $wire->addHookBefore('ProcessPageView::execute', function(HookEvent $event) { /* @var ProcessPageView $ppv */ $ppv = $event->object; for($i = 0; $i < 50; $i++) { $page = $ppv->_callMethod('getPage', []); bd($page->id, 'page->id'); } });
  4. @pwFoo, if your page/template/file exists only to give some AJAX response then another approach you could consider is to hook ProcessPageView::pageNotFound. Then you don't need the page/template/file. In /site/init.php: $wire->addHookBefore('ProcessPageView::pageNotFound', function(HookEvent $event) { $url = $event->arguments(1); if($url === '/your-special-url/') { $event->replace = true; $event->return = 'your response'; } });
  5. @pwFoo, note that you will also need to disable FileCompiler for the template. That's because FileCompiler forces the $config->paths->templates path at the start of the filename you set for the template, resulting in an invalid path if you used a full path outside of the templates folder for the filename. See here, here and here. You could open a GitHub issue for this - Ryan may or may not agree that it constitutes a bug.
  6. I'm wondering about the intended or correct use of Wire::_callMethod(). I was tying out a hook to ProcessPageView::execute(), and I wanted to get the Page object that execute() was being called for. ProcessPageView has a getPage() method for that purpose, but it's a protected method so this doesn't work: $wire->addHookBefore('ProcessPageView::execute', function(HookEvent $event) { /* @var ProcessPageView $ppv */ $ppv = $event->object; $page = $ppv->getPage(); // ... }); But then I found Wire::_callMethod(), and this does work: $wire->addHookBefore('ProcessPageView::execute', function(HookEvent $event) { /* @var ProcessPageView $ppv */ $ppv = $event->object; $page = $ppv->_callMethod('getPage', []); // ... }); Is this a correct use of _callMethod()? Is this what _callMethod() exists for? The code comment for _callMethod() is... /** * Call a method in this object, for use by WireHooks * * #pw-internal * ...so the "for use by WireHooks" part sounds like my usage is okay, but the "#pw-internal" and the underscore prefix made me wonder if this method is only intended for use by the core. I couldn't find any mentions in the forum of anyone using it in their own code.
  7. Is this custom login page for front-end users or for users who need to access the PW back-end? If it's for front-end users then I think you don't want them knowing about the core login page at all. You get a bit of extra security if you use a login page name that is not easily guessable (e.g. not "admin" or "processwire") and do not provide links to the core login page from the front-end. Then you only reveal the core login page to users who need to access the back-end. If the login page is for back-end users then I'm not sure why you would not want to use the admin-styled form given that the user is about to be working in the rest of the admin, but you could redirect away from it to your custom login page with a hook in /site/ready.php $wire->addHookBefore('ProcessLogin::execute', function(HookEvent $event) { $this->session->redirect('/your-login-page/'); });
  8. The same code will work in a hook to Pages::delete. Adapted to keep it DRY: // Prevent the trashing/deleting of pages referenced by other pages $pages->addHookBefore('trash', null, 'protectReferencedPages'); $pages->addHookBefore('delete', null, 'protectReferencedPages'); function protectReferencedPages(HookEvent $event) { $page = $event->arguments(0); // Find non-system Page Reference fields $pr_fields = wire('fields')->find("type=FieldtypePage, flags=0"); // Implode for selector string $pr_fields_str = $pr_fields->implode('|', 'name'); // Find any referencing pages $referenced_on = wire('pages')->find("$pr_fields_str=$page->id, include=all"); if($referenced_on->count) { // Replace the trash/delete method $event->replace = true; // Link markup for referencing pages $referenced_on_str = $referenced_on->implode(', ', "<a href='{editUrl}'>{name}</a>"); $plural = $referenced_on->count > 1 ? 's' : ''; // Trigger an error message (using $session in case a superuser is trashing/deleting from ProcessPageList) wire('session')->error("You cannot $event->method page $page->name because it is referenced in a Page Reference field on page$plural $referenced_on_str.", Notice::allowMarkup); // Don't allow the trashing/deleting of this page $event->return = false; } }
  9. A hook for anyone still wanting a solution for this: // Prevent the trashing of pages referenced by other pages $pages->addHookBefore('trash', function(HookEvent $event) { $page = $event->arguments(0); // Find non-system Page Reference fields $pr_fields = $this->fields->find("type=FieldtypePage, flags=0"); // Implode for selector string $pr_fields_str = $pr_fields->implode('|', 'name'); // Find any referencing pages $referenced_on = $this->pages->find("$pr_fields_str=$page->id, include=all"); if($referenced_on->count) { // Replace the trash method $event->replace = true; // Link markup for referencing pages $referenced_on_str = $referenced_on->implode(', ', "<a href='{editUrl}'>{name}</a>"); $plural = $referenced_on->count > 1 ? 's' : ''; // Trigger an error message (using $session in case a superuser is trashing from ProcessPageList) $this->session->error("You cannot trash page $page->name because it is referenced in a Page Reference field on page$plural $referenced_on_str.", Notice::allowMarkup); // Don't allow the trashing of this page $event->return = false; } }); When attempting to trash a referenced page from ProcessPageList the page will at first appear to be trashed but in fact it is not, and on the next admin page load a notice will be displayed explaining the situation. I don't think this detail matters much because it only affects superusers.
  10. Yep, that's the only way I know of to customise the comments module.
  11. Hi @ryan, The new field tag features are cool, thanks! It's not quite the same, but in some ways being able to use a different name (tag) to refer to a field in a selector is similar to a request I raised a while ago about an idea for field aliases. So for example if I have a field with a generic name like text_1, when it is in my employee template I can use it in my template file and selectors as first_name. That would help a lot with code readability and encourage more efficient field re-use. Could the new field tag features be leveraged in some way to add support for field aliases? Probably as a separate thing to tags, but perhaps building on some of the same code you added this week?
  12. Hi @adrian, I'm still experiencing the issue below in the latest Tracy: I can fix it with the CSS I mentioned earlier... ...but it would be handy to have that as an option built into the module so no custom CSS is needed. Thanks!
  13. Batcher is actually @Wanze's module - I just forked it to fix a couple of PW3 compatibility issues. Glad to hear that it's working for you now.
  14. @OviS, I just tested the module in PW 3.0.104 and it is working fine. I think perhaps you have something configured wrong - double check that you are using the format virtual_parent_template=virtual_child_template in the module config and that both your virtual parent page and your virtual child pages are at the same level in the tree when the module is disabled. Virtual Parents disabled: Virtual Parents enabled: Or else perhaps another module or custom hook is interfering with the Virtual Parents module? You could test the module on a clean PW installation and see if you still have the same issue.
  15. You could try out the idea for "Dynamic parent and/or template for pages created from the inputfield" outlined in this post:
  16. You already have part of the logic for this - now you just need the else. I would tend to flip the logic around the other way though... if($p->id) { // $p is an existing page, so prepare it for saving new field values $p->of(false); } else { // No existing page so create one $p = new Page(); // ... } // Now set the field values of $p Keep track of the job ids in the RSS feed using an array. Then find any pages with job ids that are not in the array and delete them. $job_ids = []; foreach($rss as $item) { $job_ids[] = $item->id; // The rest of your code... } // Implode for use in selector string $job_ids = implode('|', $job_ids); // Find pages for deletion $delete_pages = $pages->find("job_id!=$job_ids"); foreach($delete_pages as $delete_page) { $delete_page->delete(); }
  17. Thanks for adding this feature! It might be good (just to avoid any confusion) to exclude the skip trash option on the delete tab of ProcessUser because the deletion there is permanent by default.
  18. You can do it without having to save the page using the (undocumented) core dependent selects feature. There are some requirements for it to work. More info:
  19. The core inputfield dependencies feature doesn't support this. It works via Javascript and can only read field values that exist in Page Edit - the published status is not one of those field values. But the Custom Inputfield Dependencies module can help you out here.
  20. Yes, it can be done. The documentation for the Repeater fieldtype shows API code for adding repeater items. The general approach is that for every row you will look for a "group" repeater item by title and if no item matches that group name you create one. And for every row you create a "photo" repeater item inside the relevant group item. Not tested but it should work once you have changed $page and any field names to suit your setup: // Parse the CSV data $handle = fopen('/path/to/your/file.csv', 'r'); while(($row = fgetcsv($handle)) !== false) { // Columns (maybe there are actually more of these) list($group_name, $image_name, $price) = $row; // Get the group item for this $group_name /* @var RepeaterPage $group_item */ $group_item = $page->groups->get("title=$group_name"); // If no such item exists, create one if(!$group_item->id) { $group_item = $page->groups->getNew(); $group_item->title = $group_name; $group_item->save(); $page->groups->add($group_item); $page->save(); } // Create a photo item for this row /* @var RepeaterPage $photo_item */ $photo_item = $group_item->photos->getNew(); $photo_item->title = $image_name; $photo_item->price = $price; // If there are more columns deal with them here $photo_item->save(); $group_item->photos->add($photo_item); $group_item->save(); // Perhaps not needed, but save the page for good luck $page->save(); }
  21. I agree. Please create an issue for it on GitHub: https://github.com/processwire/processwire-issues/issues
  22. The InputfieldImage::getAdminThumb() method with the "remove legacy thumbnail file" argument is what you want to use. You'd loop over all the images in your site and call that method on each one. I think this will do the job... $if_image = $this->modules->InputfieldImage; foreach($fields->find('type=FieldtypeImage') as $field) { foreach($pages->find("{$field->name}.count>0") as $p) { foreach($p->getUnformatted($field->name) as $image) $if_image->getAdminThumb($image, false, true); } }
  23. Speaking of deleting pages, what do you think about the idea I raised a while back... Sometimes when testing you want to permanently delete a page after you have created or edited it, so it would be handy to be able to do that from the Delete tab rather than going back to the tree. Instead of another checkbox inside the "Move to Trash" inputfield like I showed in my earlier suggestion (I don't think it's even possible to do that with the forms API) it would be better to have a separate "Delete permanently" inputfield added to the Delete tab.
  24. I think the Connect Page Fields module will be suitable for this. You would create two new Page Reference fields for your Skyscraper template: interior_photos and exterior_photos. The visibility of these fields could be set to hidden if you don't want to see them in Page Edit. Then you would connect those fields to the corresponding fields on the Photo template. In terms of matching skyscrapers with or without interior or exterior photos you would then match against the count of the Page Reference field rather than a boolean.
×
×
  • Create New...