Jump to content

Robin S

Members
  • Posts

    4,928
  • Joined

  • Days Won

    321

Everything posted by Robin S

  1. Yes, I get an out of memory error with this simple test module: <?php namespace ProcessWire; class ProcessTest extends Process { public static function getModuleInfo() { return array( 'title' => 'Process Test', 'version' => 1, 'page' => array( 'name' => 'test', 'parent' => 'setup', 'title' => 'Test', ), ); } public function ___execute() { $form = $this->modules->get('InputfieldForm'); $f = $this->modules->get('InputfieldButton'); $f->value = 'foo'; $form->add($f); $f = $this->modules->get('InputfieldButton'); $f->value = 'bar'; $form->add($f); return $form->render(); } }
  2. Yes, I get the same error. Seems to be caused by two button inputfields being rendered in the same form. I have created a simple test case and have opened a GitHub issue: https://github.com/processwire/processwire-issues/issues/653
  3. You have to save a newly created page (including a repeater page) before you can add files or images to it. $added = $p->member_mx_images->getNew(); $added->save(); $added->member_images->add($responseAdded['imageURL']); $added->crm_products_sold = $products; $added->save(); $p->of(false); $p->member_mx_images->add($added); $p->save();
  4. Hi Adrian, what do you think about adding a db() method/shortcut? So just like bdb() but for use (mainly) in the Tracy Console?
  5. Thanks for the new updates @ryan! Do you think for the next week or two the focus could be on bringing the Selectors documentation up to date? This is a really important part of the documentation, especially for new users. New API methods get added to the API documentation automatically which is great, but that doesn't happen for new selector features because the documentation for Selectors isn't derived from code comments in the core. I went back through previous blog posts and compiled a list of things that it would be nice to have covered in the Selectors docs. has_parent now supports multiple values: https://processwire.com/blog/posts/processwire-core-and-profields-updates-2.5.22/#has_parent-selectors-now-support-multi-value The ~= operator now supports words with fewer than 4 characters: https://processwire.com/blog/posts/merry-christmas-heres-processwire-3.0.3-and-2.7.3-and-some-more/#improvements-to-the-operator-in-page-finding-operations Nested sub-selectors are now supported: http://processwire.com/blog/posts/processwire-3.0.6-brings-pages-upgrades-and-link-abstraction/#support-for-nested-sub-selectors It is now possible to sort by custom fields of a parent page: https://processwire.com/blog/posts/processwire-3.0.7-expands-field-rendering-page-path-history-and-more/#whats-new-in-3.0.7 New selector array syntax: https://processwire.com/blog/posts/processwire-3.0.13-selector-upgrades-and-new-form-builder-version/#selector-engine-array-support It would be good to explain about the verbose option for selector arrays too and what circumstances that is needed in. And perhaps some mention of using the Selectors class to merge different types of selector together: https://processwire.com/talk/topic/16651-merge-selectors/?do=findComment&amp;comment=146890 Multiple dot selectors: https://processwire.com/blog/posts/pw-3.0.25/#syntax-and-examples Negative start and limit, and matching by index: https://processwire.com/blog/posts/pw-3.0.46-stocking-stuffers/#support-for-negative-limit-and-start-values-in-selectors Use Fieldtype in selectors: https://processwire.com/blog/posts/processwire-3.0.91-core-updates/ Owner selectors: http://processwire.com/blog/posts/processwire-3.0.95-core-updates/ Use field tags in selectors: https://processwire.com/blog/posts/pw-3.0.106/#a-new-way-to-search-with-upgraded-tags-for-fields If anyone knows any other new selector features not included in the Selectors documentation maybe they could post a reminder about them here? Another thing it would be good to cover in the Selectors docs are the differences between what is supported in a PageFinder selector and what is supported in an in-memory selector. I mentioned a few differences that I know about in a comment here: https://processwire.com/talk/topic/18343-selector-filter-for-multiple-dates/?do=findComment&amp;comment=160451 And perhaps there is a way to bring support for some of those things to in-memory selectors to reduce the differences between the two types of selector?
  6. If I understand right you want to get all the pages that are selected in a given Page Reference field, site-wide. To do this efficiently you do need to use a SQL query - Ryan has shared a code snippet:
  7. That would be difficult to do as it goes against the way ProcessPageEdit works normally - when PPE loads, the values shown in the inputfields are the values stored in the database. So it also raises the question of even if you could do it (maybe save the $input->post data to $session and then hook the inputfield render to load custom content to the inputs) whether it would be a good idea given that it goes against what PW editors will be used to. You might be better to disable the save button with Javascript if the required fields are not filled out. Note also that for text fields there is a setting to use the HTML5 required attribute which has the effect of preventing a page save when the required field is not filled out. With either of these approaches though you should consider how you will handle an attempted save from a PPE tab other than Content (e.g. an attempted save from the Settings tab).
  8. Potentially related issues: https://processwire.com/talk/topic/16685-images-are-not-saved-permanently-with-ajax-upload/ https://github.com/processwire/processwire-issues/issues/132 https://github.com/processwire/processwire-issues/issues/42 https://github.com/processwire/processwire-issues/issues/41 In one of the issues Ryan said that the 1970 timestamp is something that PW does to indicate that the image has not yet been saved, but this should be updated when the page is saved. The first of those GitHub issues suggests that the problem was related to a specific PHP version, and upgrading PHP fixed the issue. So that could be something to try.
  9. Check out the created dates on the copies. There's obviously something not right there, but not sure what exactly. Hopefully someone who knows more about these things can shed some light. Would be worth seeing if you get the same issue with a new clean PW installation. Here is how my table looks for comparison:
  10. Is the cropped copy still there after you save the page? If so then I don't understand how that's possible, because the inputfield gets the images it displays from the field value (in the database), so if you see two images in the inputfield then there should be two images in the field value. Have you had a look in phpMyAdmin to see if you can see the copy in the field table?
  11. Works for me also. Screenshot below has crop saved from the first image: And if I try cropping an image in a field with max files = 1 then there is no "save copy" option in the cropping dialog (as expected).
  12. @adrian, I think there might be an problem with the "Initial differences protected" option when changing the title of a page via the API (and assuming the "Enable for API" option is checked). My understanding is that the initial differences protected option means that the page will not be renamed if it already has a name that is different from the name that would be automatically derived from the title. So if I have a page titled "Foo" and named "bar", and I change the title to "Baz" then the page keeps the name "bar" rather than changing to "baz". But if my page is titled "Foo" and named "foo" and I change the title to "Baz" then the name changes to "baz" because there was no initial difference between title and name. Is that right? The issue is that in renameOnSave() here your test to see if the page should be renamed will fail when it shouldn't because if the title is being changed via the API then in saveReady it will (almost) always be different than the existing page name. I think instead you would need to compare if the existing page name is different than the previous value for the title before it was changed, as only that would constitute an initial difference.
  13. Check that you have AdminThemeDefault set as the default admin theme in /site/config.php $config->defaultAdminTheme = 'AdminThemeDefault';
  14. You are hooking Module::saveConfig instead of Modules::saveConfig.
  15. Try hooking after Pages::added, but you'll need to add a line to save $page within your hook when hooking that method. There's an open issue about that problem: https://github.com/processwire/processwire-issues/issues/648
  16. It's actually not as practical an idea as I first thought because PageRenameOptions mostly works via Javascript, as @adrian explained in the support thread. But for the purposes of your module you probably don't need all the config options that PageRenameOptions provides. The "initial differences protected" option would be the main one and I think it will be possible to achieve that in PHP with the API. I'll give it a try and post something later. I see this the other way around - I think it would actually be better if PW moved to a PHP/API implementation for setting the page name. It's a bit of a problem IMO that there is no API method that provides identical naming to the JS naming in ProcessPageAdd. And I don't think the approach of requiring users of languages other than English to enter potentially thousands of character transliterations into the InputfieldPageName config is ideal. Although I don't work on non-English sites myself I think it would be good to have something like EasySlugger in the PW core, with the InputfieldPageName config only used for custom overrides. So the user only enters a title in the first step of Page Add and the page name is derived from the title in PHP. The user can easily change to a custom page name after that if need be, so it's not much of a sacrifice in return for a more consistent naming system that requires less configuration.
  17. I've always found that the easiest way to store site settings is with a dedicated template/page. I'm a bit confused by your code because it looks like the module doesn't have any config fields, but generally speaking you can get your module config data after it is saved by hooking after Modules::saveConfig (or Modules::saveModuleConfigData if you need to support older versions of PW). You hook will run after the config is saved for any module, but you can use the first argument to compare against your module classname and return early if it doesn't match.
  18. Oh right, I never looked into how the module does its work. My idea isn't practical then. Just curious: does setting the page name via JS have an advantage over hooking saveReady and setting it via the API? Do you do it that way to distinguish between title changes made in Page Edit versus the API (in case a user wants to exclude title changes made via the API)?
  19. @Sten, I was thinking that it would be good to have some configurable options in the module to determine when a page's name is set via EasySlugger. That is what the Page Rename Options module provides, so to avoid recreating all of that I've asked in the support thread if @adrian would consider adding a hookable method to his module. I think it might be better to bundle EasySlugger in with your module because it will have a wider audience that way - a lot of people are on shared hosting that doesn't include Composer. You could use Composer locally to pull in EasySlugger updates (it actually hasn't received any updates in the last 3 years) and then push them out to your module repo.
  20. Hi Adrian, @Sten is working on a module that uses EasySlugger to set better page names from titles that use non-latin alphabets. I was thinking that it would be cool if that module (and potentially others) could build on the features that Page Rename Options provides to select what pages are automatically renamed. What do you think about separating off the line that determines the new page name into a hookable method? Then other modules could hook into that to set a custom page name.
  21. There are a number of screenshots in the blog post that introduced the inline editing. You can see multi-language fields in those. https://processwire.com/blog/posts/inline-ajax-page-editing-comes-to-listerpro-processwire-2.6.6/
  22. @Sten, your module looks like it is missing the required getModuleInfo() method. Check the Module docs for what is required in a module. The Hello World module is a good one to learn from too. And Tracy Debugger is a must-have for debugging modules or anything else (the Tracy bd() method is all you need to learn to begin with). Also, when you want to make changes to a Page in a Pages::added hook you need to do a $page->save() in order to save the changes. Not wanting to hijack your module or anything but when you first posted this topic I was interested in EasySlugger and put together a simple module to test it out. I've added a couple of comments to the code that might help you. <?php namespace ProcessWire; class Slugger extends WireData implements Module { /** * Module information */ public static function getModuleInfo() { return array( 'title' => 'Slugger', 'version' => '0.1.0', 'autoload' => true, ); } /** * Ready */ public function ready() { // You would generate the slug/name after saveReady or added, but not both $this->addHookAfter('Pages::added', $this, 'afterAdded'); // $this->addHookAfter('Pages::saveReady', $this, 'afterSaveReady'); } /** * After Pages::added * Set the page name using EasySlugger only once when the page is first added * * @param HookEvent $event */ protected function afterAdded(HookEvent $event) { require_once __DIR__ . '/EasySlugger/SluggerInterface.php'; require_once __DIR__ . '/EasySlugger/Utf8Slugger.php'; $page = $event->arguments(0); $page->of(false); $page->name = \EasySlugger\Utf8Slugger::slugify($page->title); $page->save(); } /** * After Pages::saveReady * Set the page name using EasySlugger every time the page is saved, in case the Title was changed * You could add a condition to set the name only if the Title changed if you like * * @param HookEvent $event */ protected function afterSaveReady(HookEvent $event) { require_once __DIR__ . '/EasySlugger/SluggerInterface.php'; require_once __DIR__ . '/EasySlugger/Utf8Slugger.php'; $page = $event->arguments(0); $page->name = \EasySlugger\Utf8Slugger::slugify($page->title); } } Slugger.zip Note that there is a minor core issue with warning notices from ProcessPageAdd that will hopefully be fixed soon: https://github.com/processwire/processwire-issues/issues/648
  23. The PW issues repo is a bit of a cause for concern I think. Issues are added much more frequently than they are solved, so the collection of open issues is just going to grow and grow over time unless something changes to accelerate the rate at which they are addressed. At the end of the day, it seems the volume of issues is too great to deal with by just a single person with limited time. And a comment Ryan made in a blog post a while ago left me a bit puzzled: Maybe I'm reading that wrong, but it sounds like Ryan believes that almost all significant issues are already solved. I wouldn't agree with that as I think the majority of the open issues are valid ones that affect multiple people. Maybe the fact that there are quite a few issues that have been solved but are still left open is obscuring the fact that a significant number of unsolved issues exist, some dating back a long while. So I would support the idea of closing issues marked solved if it also meant taking a fresh look at the ones not yet solved.
  24. Update... The above works okay but it seems that the match callback only fires when CKEditor loads, so to be sure that any disallowed content resulting from the current page edit is removed you have to save the page twice. After a bit more hunting I think I've found a better approach that uses CKEditor's DTD object. It's not quite as straightforward as you'd expect at first because element objects within the DTD object are not fully independent (e.g. CKEDITOR.dtd['h2'] seems to refer to the same object as CKEDITOR.dtd['p']). This SO post helped me find a solution. In /site/modules/InputfieldCKEditor/config.js: // For numbers 1 to 6 for(var i = 1; i <= 6; i++) { // Create the tag name from 'h' plus the number var tag = 'h' + i; // Create clone of DTD heading object so it can be modified individually CKEDITOR.dtd[tag] = Object.assign({}, CKEDITOR['dtd'][tag]); // Disallow strong element from being contained within heading element CKEDITOR.dtd[tag]['strong'] = 0; }
  25. A pet hate of mine is when an editor uses a paragraph of bold text for what ought to be a heading. When I need to tidy up poorly formatted content like this I will quickly change such lines of text into the heading of the appropriate level, but that still results in markup like... <h2><strong>Some heading text</strong></h2> The <strong> has no business being there, but it's a bit of a hassle to remove it because you have to drag a selection around the exact text as opposed to just placing your cursor within the line. That gets tedious if you have a lot content to process. I figured there has to be an easier way so started looking into the ACF (Advanced Content Filter) features of CKEditor. What I wanted is a rule that says "strong tags are disallowed specifically when they are within a heading tag". (I guess there could occasionally be a use case where it would be reasonable to have a strong tag within a heading tag, but it's so rare that I'm not bothered about it). With the typical string format for allowedContent and disallowedContent there is no ability to disallow a specific tag only when it is within another specific tag - a tag is allowed everywhere or not at all. But I found there is an alternative object format for these rules that supports a callback function in the "match" property. So I was able to achieve my goal with the following in /site/modules/InputfieldCKEditor/config.js: CKEDITOR.editorConfig = function(config) { config.disallowedContent = { // Rule for the <strong> element strong: { // Use "match" callback to determine if the element should be disallowed or not match: function(element) { // Heading tag names var headings = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6']; // The parent of the element (if any) var parent = element.parent; if(typeof parent !== 'undefined') { // If there is a parent, return true if its name is in the heading names array return headings.indexOf(parent.name.toLowerCase()) !== -1; } else { // There is no parent so the element is allowed return false; } } } } }; Another tip: if you want to debug your allowedContent or disallowedContent rules to make sure they are being parsed and applied successfully you can log the filter rules to the console. For convenience I used /site/modules/InputfieldCKEditor/config.js again. // Get the CKEditor instance you want to debug var editor = CKEDITOR.instances.Inputfield_body; editor.on('instanceReady', function() { // Log the disallowed content rules console.log(editor.filter.disallowedContent); });
×
×
  • Create New...