-
Posts
5,034 -
Joined
-
Days Won
340
Everything posted by Robin S
-
It looks like PhpStorm doesn't let you override the variable type in a PHPDoc comment when it already knows the type based on the source code. When you get a field value via $page->field_name it is accessed via the __get() magic method, so what PhpStorm is telling you in the case of $this->paymentAmount is actually more accurate than for $payment->paymentAmount, where we are sort of tricking PhpStorm through PHPDoc comments into treating overloaded properties as "real" properties of the Page object. These things aren't fixable issues for the module but are about how your specific IDE understands the code.
-
Where are you typing "$this"? In a template file? If you have a custom Page class HomePage then in your "home.php" template file you put this line at the top: /** @var HomePage $page */ Then you access any fields or methods of the HomePage class from $page. AutoTemplateStubs gives you code assistance for the fields and the HomePage methods. In a template file $this refers to a TemplateFile object. It doesn't give you access to fields or methods of the HomePage class. If you are typing "$this" in the file for a class that extends Page (e.g. HomePage.php) then you are working in file that this module is not designed to support. But PhpStorm automatically gives you code assistance for methods in the class... ...and even though it wasn't something I had in mind when this module was developed (because custom Page classes didn't exist then) you do get assistance for field names too: If this doesn't answer your question please give me more explanation of what you're wanting to do. Maybe screenshots would help.
-
I'm not sure I understand. This module is specifically for code hints in template files - it doesn't do anything for any other files you might have in your site. If you are using custom page classes then see the notes in the readme about that, but again this only has an effect on the template file. When you are editing any other class file, module file, etc then this module isn't going to do anything. But PhpStorm should automatically understand the $this keyword in a class context anyway.
-
There's no built-in option for that, but nearly everything is possible in PW with hooks and some lateral thinking. ? Below is one way you could achieve the goal. In my example I'm using "country" pages under a "countries" parent but the same idea will work for your case of children under the home page. Create a "multiple pages" Page Reference field named "top_pages" and add it to the template of the parent page. The field should be limited to the selection of child pages, so in "Selectable pages" set the "Selector string" option like this: Here "page" is a special keyword that means "the page that is currently being edited". Now edit the parent page and select the child pages you want to be sorted at the top. On the Children tab I have this: So I want the children sorted by title, apart from the children selected in the top_pages field. In /site/ready.php I have the following hooks, which affect the paginated listing of child pages in ProcessPageList: // Before ProcessPageList::find $wire->addHookBefore('ProcessPageList::find', function(HookEvent $event) { $selector_string = $event->arguments(0); $parent = $event->arguments(1); // Return early if the parent page doesn't include the top_pages field, or if the field is empty if(!$parent->hasField('top_pages') || !$parent->top_pages->count) return; // Convert selector string to Selectors object to make it easier to examine and modify $selectors = new Selectors($selector_string); $start = $selectors->get('field=start'); $limit = $selectors->get('field=limit'); // Return early if Selectors object does not conform to what is expected for some reason if(!$start || !$limit) return; // Get start and limit as integers $start_value = (int) $start->value; $limit_value = (int) $limit->value; if($start_value === 0) { // This is the first pagination // Reduce the limit by the count of the top pages $limit->value = $limit_value - $parent->top_pages->count; // Set a custom property on the ProcessPageList object // to indicate that the top pages should be prepended to the children $event->object->add_top_pages = true; } else { // This is not the first pagination // Reduce the start by the count of the top pages $start->value = $start_value - $parent->top_pages->count; } // Set the selector string argument to the string value of $selectors $event->arguments(0, (string) $selectors); }); // After ProcessPageList::find $wire->addHookAfter('ProcessPageList::find', function(HookEvent $event) { $parent = $event->arguments(1); // If there are top pages to add... if($event->object->add_top_pages) { // Prepend the top pages to the children $children = $event->return; $children = $parent->top_pages->add($children); $event->return = $children; // Unset the custom property now that the job is done unset($event->object->add_top_pages); } }); Result: Note: with this approach you must not select more "top pages" than the pagination limit for ProcessPageList (the default is 50).
-
increment variable with each hannacode occurence
Robin S replied to froot's topic in General Support
Check the documentation: So it's an array of matched elements. But you don't need to do anything with it in your case - just return the replacement. You need to pass the variable that is holding the count by reference, as shown in my example. -
increment variable with each hannacode occurence
Robin S replied to froot's topic in General Support
I think Hanna Code is not a good candidate for solving this need. For a couple of reasons: 1. The Hanna Code textformatter does not necessarily only execute once when are outputting the field value in your template. It executes whenever the formatted value of the field is accessed. In practice I think you'll find this happens (or can happen) more than once in the same request (Ryan has pointed this out somewhere, and you can test it with Tracy Debugger) and so your counter incrementation is not going to be reliable. 2. You will be using the exact same tag [[nextimage]] multiple times within the field value. The Hanna Code textformatter uses a str_replace() to replace all matching tags in the field value. So it doesn't matter how you increment a counter within the Hanna tag code - all identical tags will get the same replacement value. Instead I think you should use your own placeholder and then do your own replacement (either in a template file or in a custom textformatter module). Example... In your field value, use the text {{nextimage}} inside a paragraph by itself. So the resulting markup would be <p>{{nextimage}}</p>. In your template file you can use preg_replace_callback(): $body = $page->body; $images = $page->images; $pattern = '/<p>{{nextimage}}<\/p>/'; $count = 0; $callback = function($matches) use (&$count, $images) { $out = ''; $image = $images->eq($count); if($image) { $out = "<img src='$image->url' alt='$image->title' title='$image->title'>"; } $count++; return $out; }; $body = preg_replace_callback($pattern, $callback, $body); -
My comments are about styling the admin, and that's done with CSS. I think you might be talking about making changes to the admin markup - or do I have that wrong?
-
Sure, the admin theme could make this sort of thing easier. But it's not excessively difficult to tweak the styling now if a person is motivated. When people make comments or requests about the admin theme styling (not just in recent topics but in the forum generally) I'm never sure if they realise that they don't need to wait for Ryan to do something in order to get what they want. It's CSS101 stuff.
-
Exactly. I doubt we're going to all agree on all details of how the admin theme should look. But I hope that nobody among us is sitting there gritting their teeth because the admin isn't looking how they want it to look. Because we're all website designers/developers and we know how Cascading Style Sheets work (especially the cascading part). And it's not a difficult task to add your own CSS to the admin and override the styling of elements as you like. The admin theme markup changes very rarely and so you can spend half an hour working out your overrides for colours or whatever and then reuse those styles on all projects going forward. If you compile your overrides from SCSS/LESS then it's really easy to tweak colours for specific projects via variables.
-
Are you doing something like adding the Justify plugin yourself? If so, you don't need to do that because it's already included in PW's InputfieldCKEditor by default. You can specify the individual justify toolbar items you want:
-
This post might help you: Specifically the Page::editable and Page::addable hookable methods.
- 1 reply
-
- 3
-
-
keeping backend data private from peer roles
Robin S replied to jon9china's topic in General Support
My understanding is that there are three hookable methods that you can use if you want detailed control of which pages are viewable, editable and "listable". Viewable = user may view the page on the front-end. Example hook in /site/init.php: $wire->addHookAfter('Page::viewable', function(HookEvent $event) { $page = $event->object; // Return early if PW has determined that the page is not viewable if(!$event->return) return; // Your test here... if($page->title === 'foo') { // User may not view the page $event->return = false; } }); Editable = user may edit the page in ProcessPageEdit. Example hook in /site/init.php: $wire->addHookAfter('Page::editable', function(HookEvent $event) { $page = $event->object; // Return early if PW has determined that the page is not editable if(!$event->return) return; // Your test here... if($page->title === 'foo') { // User may not edit the page $event->return = false; } }); Listable = user can see the page in ProcessPageList. Note: superusers are not affected. Example hook in /site/init.php: $wire->addHookAfter('Page::listable', function(HookEvent $event) { $page = $event->object; // Return early if PW has determined that the page is not listable if(!$event->return) return; // Your test here... if($page->title === 'foo') { // User may not see the page in ProcessPageList // And therefore may not see its descendant pages either $event->return = false; } }); There's a catch to be aware of with this last hook. Page::listable only affects ProcessPageList and not other parts of the admin. If the existence or title of the page must remain private then you'll need to handle the following separately: Admin search (AJAX results) Admin search (results page if user hits enter) Lister (aka "Find") Maybe other places such as Page Reference fields I think @adrian has some experience with hiding pages from these places and might have some suggestions. Edit: In my opinion it would be nice if PW used Page::listable to automatically restrict the visibility of pages throughout the admin. I opened a request here: https://github.com/processwire/processwire-requests/issues/379 Besides Page::viewable, Page::editable and Page::listable there are also the following hookable methods that can be used in a similar way to the examples shown above. All of these methods are in PagePermissions.module. Page::publishable Page::deleteable (aka Page::deletable) Page::trashable Page::restorable Page::addable Page::moveable Page::sortable -
Native Array of Objects to WireArray and WireData Objects
Robin S replied to Brian Scramlin's topic in API & Templates
@Brian Scramlin, to use WireArray::sort I think the items in the WireArray need to be Wire-derived objects, e.g. WireData. Relevant API documentation: https://processwire.com/api/ref/functions/wire-data/ https://processwire.com/api/ref/functions/wire-array/ Demo: -
Native Array of Objects to WireArray and WireData Objects
Robin S replied to Brian Scramlin's topic in API & Templates
The json_decode() function has an "associative" argument that you can set to true: $meevo_response_array = json_decode($meevo_response, true); Or you can use the core wireDecodeJSON() function which does this automatically. $meevo_response_array = wireDecodeJSON($meevo_response); -
Adding text titles from Page Reference fields to a Cache field?
Robin S replied to johnstephens's topic in Getting Started
I think you're better off not using FieldtypeCache. See this issue for some discussion: https://github.com/ryancramerdesign/ProcessWire/issues/1577 And I remember Ryan commenting somewhere that he's thinking of removing it from the core. The simplest thing if you want to merge multiple fields into a single field for search purposes is to use the SearchEngine module. Or if you want to go more hands-on it's not difficult to populate a hidden "index" textarea field from other field values using a Pages::saveReady hook. $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'your_template') { $index = $page->title; if($page->body) $index .= ' ' . strip_tags($page->body); foreach($page->tags as $tag) $index .= ' ' . $tag->title; $page->index = $index; } });- 1 reply
-
- 4
-
-
multilingual tags for images and files
Robin S replied to virtualgadjo's topic in Wishlist & Roadmap
I don't know much about multilingual websites, but I think Page Reference fields are multilingual. And Page Reference fields are the most powerful way to implement tags anywhere in PW. Now that have the custom fields for Files/Images feature it seems like this would be a good solution. -
The title field is already optional. You just need to make it non-global by editing the Title field and unchecking the Global checkbox on the Advanced tab. Then you can remove it from any templates where you don't need it. If you want to see the values of other fields (instead of Title) in Page List you can set that on the Advanced tab when editing the template.
-
@ryan, what follows is only about the idea of taking Repeater Matrix in a Bard-like direction for long-form content, as referred to in my earlier post. I don't have an opinion on the "builder" idea because it's not something I or my clients need. Looking at the Bard video you can imagine it as rich text field (i.e. CKEditor or maybe Editor.js) with Repeater Matrix elements distributed through it. You can add new Matrix items and edit them within the rich text interface. Here's a mockup of what a hypothetical "Repeater Matrix Bard" field might look like: But as far as I can see such an interface would be very difficult to implement. You'd have to somehow replicate the Matrix item interface inside CKEditor or Editor.js, maybe as plugins. [Actually, as soon as I made this mockup I suddenly had another idea for how it could be done, but I'll come back to that at the end of this post]. So when I first started thinking about this idea (back when Bard was introduced to Statamic) I wrote that option off as too difficult and turned to working with the existing CKEditor and Repeater Matrix fieldtypes. Of course this was going to involve compromises and the result was never going to be as slick as the Bard interface. My idea was to use placeholders for the Matrix items within the CKEditor field, in the form of CKEditor widgets. Each widget would correspond to a Matrix item, and a Textformatter module would replace the placeholders with rendered Matrix item output when the page is rendered for the front-end. This is easy to do via $matrix_page->render(). First I experimented with keeping the Matrix field visible in Page Edit, with the Matrix field in accordion mode. Hovering a widget placeholder in CKEditor highlighted the Matrix item (to help the user work out which placeholder is linked to which Matrix item) and clicking the widget scrolled to and opened the Matrix item for editing. But this takes the user away from CKEditor and disrupts the writing experience a bit too much. So then I changed to hiding the Matrix field in Page Edit so the user only sees the CKEditor field. When they add or edit a Matrix item a Magnific modal opens where they can work with the fields within the Matrix item. I added a dropdown to the CKEditor toolbar to let users add new Matrix items/widgets within the CKEditor field. This works okay but it's not fantastic - the main dissatisfaction I have is that my widgets are rather basic. This is because I'm no expert when it comes to CKEditor and its widget system. But looking at example widgets in a tutorial it seems that it's possible for them to have richer layouts and items like images (icons?) within them. I'm using the title attribute tooltip to show the text from the Matrix item header, but it would be great if the widget contained an icon corresponding to each Matrix type (sidenote: we really need a larger selection of icons available in the core) and perhaps some of the item content. Maybe the developer could specify code for each Matrix type that would render the HTML of the widget? I fear this is all beyond me but if you're interested maybe you could explore the possibilities of this? Or see if a similar approach would be more easily accomplished in Editor.js. A screencast of the system in action: Because the user doesn't see the Matrix field it would be possible for items to become orphaned there after their corresponding widgets are deleted from the CKEditor field. But it would be good to keep orphaned items for a short while to serve as disaster recovery. So perhaps orphaned Matrix items would be automatically removed after some period of time. Coming back now to the mockup screenshot and an idea of how to achieve it... What if there was a special rich text Matrix type available to be added to any Matrix field? This would consist of a CKEditor field in inline mode (to reduce the distraction of the toolbar) together with (optional) Files and Images fields to allow for linked files and embedded images (edit: it would be good if somehow a single Files field and a single Images field was shared between all rich text items). This matrix type would render differently within the Repeater Matrix inputfield - it wouldn't have a permanently visible header and the Files and Images fields wouldn't be permanently visible either. Instead a special toolbar would appear when the rich text item was hovered (probably at the bottom to avoid clashing with the CKEditor toolbar). This toolbar would include the standard Matrix icons (sort, copy, toggle, delete) and icons that make the Files and Images fields visible for when those need to be accessed. But when nothing is hovered it would render just as the rich text portions appear in my mockup. It would also be nice if the Matrix "add new" links were replaced by a "+" icon that appears when you hover between existing Matrix items, like in Bard. That would reduce some clutter in the inputfield and allow new items to be inserted in whatever position is wanted. This approach would not be quite as nice as a single rich text field containing Matrix items. Because I think the concept of multiple text fragments is not what users imagine for a long-form article. And it would result in more pages behind the scenes, although that probably isn't a big problem. But it seems like it might be relatively simple solution to the Bard idea.
-
I didn't know about adding custom links here, thanks. ? It's somewhat limited though because it can't handle URL segments or GET variables which are widely used in the admin, so you can't link to a module config for instance. My preference would be for a separate panel just for shortcut links, internal and external. The PageListSelect works well for pages but I think inputing URLs would be better because then it's one interface for entering any kind of link. Example: Just thinking out loud here, but when a link is added or changed it would be cool if... The root URL is removed from internal links so link becomes relative. If a URL is submitted without a label... For internal URLs, $pages->getByPath($url) is used, and if a Page object is returned the page title is used as the link label. For external URLs and internal URLs for which getByPath($url) returns a NullPage, attempt to get the title element using DomDocument and use it as the link label. libxml_use_internal_errors(true); $dom = new \DOMDocument(); $dom->loadHTMLFile($url); $list = $dom->getElementsByTagName('title'); $label = $list->length ? $list->item(0)->textContent : $url; These latter features aren't crucial, they're just so we have the option of being lazy and adding a URL only. ?
-
It wouldn't be a bad thing to have a filter box too, although I don't think I'm familiar enough with the input labels to use that much myself. The Perfmon module looks good - I hadn't seen it before. Honestly these features aren't something I need on a typical project - I just thought the timeline looked cool. If I needed to focus in on performance I would try Perfmon, and I have Profiler Pro but haven't actually explored its features yet. I do have another idea/request though... What do you think about adding a Shortcuts panel? This would be for custom internal or external links that a user finds they are needing to visit regularly during development. For instance, I often need to visit the LoginRegisterPro config screen during development. And you could add links to various external API documentation pages that you want to jump to quickly. Sure, you could use your browser bookmarks but mine are already an out-of-control mess, and by having the links in a Tracy panel it would keep them nicely connected to a project. I'm imagining an interface that lets you enter a label and URL for each shortcut - a textarea would do, or you could get fancy with some kind of repeater-like interface. It would be good if absolute internal links were converted to relative links (i.e. strip out the site root from the URL) so the links keep working if the root URL changes.
-
From an article @szabesz linked to earlier... No idea how difficult it would be to show a cool timeline like that, and probably something that would be better done in the Tracy core. But it looks nifty!
-
@adrian, how about this: By default all the config fields are displayed so you can use Ctrl+F, but when you click a quick link it hides all the config sections apart from the active one. This removes the clutter around the section the user wants to focus in on. Here is the CSS and JS if you want to play with it: #tracy-quick-links .InputfieldContent ul { list-style-type: none; padding: 0; overflow: hidden; } #tracy-quick-links .InputfieldContent ul li { float: left; padding: 0 5px 5px 0; } #tracy-quick-links .InputfieldContent ul li a { background: #e3e9ef; color: #333; display: block; padding: 1px 10px; border-radius: 3px; } #tracy-quick-links .InputfieldContent ul li a:hover { text-decoration: none; background: #d9e1ea; } #tracy-quick-links .InputfieldContent ul li a.active { background: #e83561; color: #fff; } $(document).ready(function() { var $quick_links = $('#tracy-quick-links'); var $config_fields = $quick_links.nextUntil('#wrap_uninstall'); $quick_links.on('click', 'a', function(event) { event.preventDefault(); if($(this).hasClass('active')) { $(this).removeClass('active'); $config_fields.show(); } else { $quick_links.find('a').removeClass('active'); $(this).addClass('active'); $config_fields.hide(); $($(this).attr('href')).show(); } }); });
-
Hi @adrian, You already kindly added some quick links to the Tracy config at my request, but I still find the config interface quite overwhelming. What do you think about implementing a tabbed interface so it's easier to focus on a subset of the config fields? I've posted a demo module that might be helpful: Depending on how you think it's best to divide up the config there would probably be more tabs than could fit in one row. Currently I don't think AdminThemeUikit handles this all that well... ...but seeing as Ryan has recently been working on AdminThemeUikit it might be timely to see if improvements can be made. I'm not sure but probably it would be good if the inactive tabs had some definition of their edge, maybe a pale grey background and white border for separation between the tabs. I'll have a play around with that. Edit: the visual metaphor of tabs is always going to break down a bit when you have more than one row of tabs, but I think the below would be an improvement on the current styling. Editing on tablets and phones is going to become more and more common and the PW admin should cater to these narrower screen widths.
-
If your module has a lot of config fields you might want to divide them into groups inside a tabbed interface. Here is a demonstration module showing how this can be done. https://github.com/Toutouwai/ModuleConfigTabs Thanks to @kixe for providing my starting point in this forum topic.