Jump to content

Robin S

Members
  • Posts

    4,928
  • Joined

  • Days Won

    321

Everything posted by Robin S

  1. I discovered that when you rename a Repeater or RepeaterMatrix field, the template and fieldgroup used for the Repeater items keep the old name. So I wrote a little function for renaming a Repeater field including the associated template and fieldgroup. To be clear, you do not need to use this function to rename a Repeater field in normal circumstances. The Repeater template is a system template so it's not something you see normally, and as for the fieldgroup... what on earth is a fieldgroup, right? So this is just for perfectionists. Or if you are doing something like checking the template name in some hook and you don't want to have to deal with the old field name. /** * Rename a Repeater / RepeaterMatrix field, including template and fieldgroup * @param string $old_name The existing name of the Repeater field * @param string $new_name The new name for the Repeater field */ function renameRepeaterField($old_name = '', $new_name = '') { // Both arguments are required if(!$old_name || !$new_name) { wire('log')->error('renameRepeaterField(): Both $old_name and $new_name arguments are required.'); return; } // Rename repeater field $f = wire('fields')->get($old_name); if(!$f) { wire('log')->error("renameRepeaterField(): Field '$old_name' not found."); return; }; if(!$f->type instanceof FieldtypeRepeater) { wire('log')->error("renameRepeaterField(): Field '$old_name' is not an instance of FieldtypeRepeater."); return; } $f->name = $new_name; $label = str_replace('_', ' ', ucfirst($new_name)); $f->label = $label; $f->save(); // Rename template $t = wire('templates')->get('repeater_' . $old_name); $t->flags = Template::flagSystemOverride; $t->flags = 0; $t->save(); $t->name = 'repeater_' . $new_name; $t->flags = 8; $t->save(); // Rename fieldgroup $fg = wire('fieldgroups')->get('repeater_' . $old_name); $fg->name = 'repeater_' . $new_name; $fg->save(); } // Use the function in a one-off operation like this renameRepeaterField('sucky_old_name', 'shiny_new_name'); The function derives a label for the field by replacing underscores with spaces and capitalising the first letter of the field name. If you want a different label you can just edit the field in admin afterwards.
  2. I have puzzled over this too, but I think the confusion comes from a non-standard use of the word "absolute" in relation to the URL. So ProcessPageEditLink never inserts an absolute URL in that it never includes the protocol or domain. But I think the absolute option means absolute relative to the site root. So the link URL starts with '/' as opposed to the two relative options which can give a link URL like '../some-page/'. The current behaviour is a good thing, because otherwise all links would break when the root domain changes (e.g. going from dev to live environment). But it would help if the meaning of the absolute option was clarified.
  3. Yeah, I think this was in an earlier version of the regions spec and I just got used to using it (so always identifying the region you are modifying with the id attribute, and then adding pw-append / pw-prepend separately when needed). But I see now that it isn't mentioned in the most recent description of the spec. So maybe a bug/oversight that this functionality isn't working with pw-append="some-id". The main bug to watch out for though is this one: https://github.com/processwire/processwire-issues/issues/302 I really hope that it gets fixed sometime soon.
  4. Adding classes with pw-append / pw-prepend is working for me... <body id='html-body' class='bgimage' pw-append></body>
  5. You're probably right. It won't hurt to add the feature and users can make up their own mind what they find easiest to use. The $page argument for that method actually is the page being edited.
  6. @tpr, I guess the question is "Why use ini format in the AOS config when you can just as easily use a hook?" The hook equivalent of the first two items in your screenshot is: $wire->addHookBefore('Field::getInputfield', function(HookEvent $event) { $field = $event->object; $page = $event->arguments(0); // Add word counter for the "title" field for non-superusers if($field->name == 'title' && !$this->user->isSuperuser()) { $field->showCount = 2; } // Set year range for a date field, if template is "news" if($field->name == 'date_created' && $page->template == 'news') { $field->yearRange = '-3:+3'; } }); Comparing the hook option to the AOS config option my thoughts are: Once the hook function is in place and the $field and $page variables defined, the code for each field override is not significantly longer. It's plain PHP, so we're already familiar with the format. It's easier to read the conditionals. It's file-based. It's easy to dump/log within the hook. It saves any additional complexity being needed in AOS.
  7. Okay, big flip-flop ahead... ...thinking some more, maybe this isn't such a good thing to add into AOS. It introduces another "language" to learn for doing something that is already possible with hooks. And @abdus has recently posted a tutorial for how to add other field settings into the template overrides that allows the admin GUI to be used. And I can see these ini-style settings being difficult to debug. Don't know, I'm really in two minds about it. Be good to hear what others think.
  8. Awesome! I can see this being really powerful, and a nice alternative to working with hooks. What do you think about adding an option for using a file to define these settings? For anything but the briefest snippets I much prefer working in my IDE (version control, etc). It could be a checkbox to activate the file-based option, or just check if "field-overrides.ini" exists in /site/modules/AdminOnSteroids/.
  9. @Violet, I just made a fix to the code snippet... // Return if body field absent or unchanged if(!$page->body || !$page->isChanged('body')) return;
  10. I might be wrong, but my understanding is that the ACF/Purifier settings for a CKEditor field only affect content that goes through the CKEditor inputfield and is then saved to the database. A textformatter on the other hand never saves its changes to the database and it isn't involved with the inputfield - it just makes changes on-the-fly as the content is output to the front-end. Another thought: if you have multiple textformatters applied, check to see if the order they are applied makes a difference.
  11. Child pages can be good when: You think it will be helpful for the relationship to be shown in the URL to the pages: /manufacturers/dodge/challenger/ Although it is also possible to 'fake' a page URL using URL segments. The child will exclusively belong to that parent (it doesn't belong to multiple categories). If either of these is not the case then you are better off with Page Reference fields. So in your example, you have fish in an aquarium. If by "fish" you mean "species of fish" then you wouldn't want to have these as child pages of an aquarium, because multiple aquariums might have the same species of fish and you don't want to duplicate the species pages.
  12. There shouldn't be any iframe tags involved - you simply insert the URL to the video (not an embed snippet or anything like that) in a new paragraph in your CKEditor field.
  13. This module is a textformatter, so it doesn't write anything to the CKEditor field. As long as you can insert a link URL into your field as text without interference from HTML Purifier then there shouldn't be any problem.
  14. @Macrura if $widget is a page, then try this... $widget->getFormatted('dw_color')
  15. Another option which avoids the need to parse and modify the links on every frontend page load (as a textformatter does), you could just do it once when a page is saved. The example below (add to /site/ready.php) uses Simple HTML DOM as the parser: // Change 'body' to whatever your CKEditor field is named $wire->addHookAfter('Pages::saveReady', function(HookEvent $event) { $page = $event->arguments(0); // Return if body field absent or unchanged if(!$page->body || !$page->isChanged('body')) return; // Load Simple HTML DOM from site root require_once $this->config->paths->root . 'simple_html_dom.php'; // Create DOM from body field $html = str_get_html($page->body); // Get all the links $links = $html->find('a'); foreach($links as $link) { $href = $link->href; // For any link that is not relative and does not start with the site httpRoot... if(strpos($href, '/') !== 0 && strpos($href, $this->urls->httpRoot) !== 0) { // Set rel and target attributes $link->rel = 'nofollow'; $link->target = '_blank'; } } // Set the results to the body field $page->body = $html->save(); });
  16. Hi @adrian, Might be a silly question, but just wondering why the dump output doesn't appear in the same order that the dumps occur in. So if I do... ...how come the output order is reversed?
  17. The GitHub readmes that are used in the modules directory have become a bit messed up recently. Example: https://modules.processwire.com/modules/tracy-debugger/ Not sure who manages this section of the website. @ryan?
  18. This is a topic that comes up quite commonly on the forums - search for "blocks" and you'll probably find a bunch of topics. Short answer... No cost: PageTable Some cost, but very much worth the investment: Repeater Matrix (in the ProFields bundle)
  19. Thanks for the update! A few little things... 1. $debug variable has been left behind in the module and may be undefined. 2. The default selector should be an empty string. 3. Wouldn't it be more efficient to set is_first and is_last according to array key like you did in MarkupSimpleNavigation? In terms of understanding the module, I find the way that $defaultOptions, $defaultStates, $enableStates, $levels and $collapsed are set to be a bit counter-intuitive. To my way of thinking, you only want to set properties to the module itself for settings that are intended to be global (applying to all menus in your site). Because when these options are set as properties of the module they persist for all subsequent menus unless you explicitly change them. But things like $levels and $collapsed are things that you want to set individually for a single menu - you don't want these settings affecting other menus. So I'd rather be passing these settings in as arguments to the render() method - that way I don't have to keep track and reset them for menus that are rendered subsequently. Similar for setting menu options for all levels of a menu - that's why I thought something like a specific array key 'all' could be used when passing in the menu options. So I'm just setting default options for that one menu and not affecting other menus. To be clear, I still like the idea of setting some global $defaultOptions, $defaultStates, etc - but for things like setting a levels limit or setting options for all levels of a specific menu it's less error-prone if these don't affect other menus.
  20. 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.
  21. 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.
  22. Nice one. How about using InputfieldAceExtended for the configuration textarea if it is installed? if($this->modules->isInstalled('InputfieldAceExtended')) { $f = $this->modules->get('InputfieldAceExtended'); $f->mode = 'ini'; $f->modes = array('ini'); $f->theme = 'twilight'; } else { $f = $this->modules->get('InputfieldTextarea'); } $f->attr('name', 'CKEaddons_toolbar'); //...
  23. One more thing: I think that here and here Aligator should fall back to the selector defined in the defaults rather than an empty string. $selector = isset($options[$level-1]['selector']) ? $options[$level-1]['selector'] : $this->defaultOptions['selector'];
  24. Me again. Is there a way I can set options for all levels of a particular menu without changing the default options? Suppose I have several menus in my site and I have defined some default options for Aligator that suit most of these menus. Now on one of these menus I want to exclude a particular template from all levels in the menu. I don't know how many levels will be in this menu (users may add pages creating additional levels of nesting). So I can use the "selector" setting for this, but do I use this in the default options or the options for that specific menu? It seems like there are catches either way. Default options: works for all levels (good), but affects all the menus in my site (bad). Menu options: limited to this specific menu (good), but I have to repeat the setting over and over some arbitrary number of times to account for all the levels that might exist in the menu (bad). Seems like there should be some way to set default options (all levels) but just for this one menu. Or am I missing something?
×
×
  • Create New...