Leaderboard
Popular Content
Showing content with the highest reputation on 03/01/2021 in all areas
-
Thanks @teppo - hooking into Renderer::renderResult worked great! Gotta say, this is a really well thought out, and well coded module. Cheers!2 points
-
I'd recommend hooking into Renderer::renderResult or Renderer::renderResultDesc, depending on your needs. Both are related to rendering a single result and have access to the Page object in question, as well as the Data object containing predefined template strings etc. Let me know if you run into any trouble. As for whether this might be a good feature addition — perhaps, though I've only had need for this once so far, so I'm not certain yet. If it's easy to add via hook and a relatively rare need, then it's probably best to leave it at that ? I'll take a closer look at the apostrophe issues later!2 points
-
I have the messaging module ready to go if anyone is interested in Beta testing it (then please message me) and ill get the shop up and running to sell it from (unless the PW market place is willing to have it of course???).2 points
-
This week I've been developing a client site, but also working through some of the feature requests. I'm going through them in order of "thumbs-up" on GitHub and trying to focus more on those that I can get through reasonably quickly. For a summary of what's been added, be sure to see the dev branch commit log. There's still a few more I'd like to add before bumping the version to 3.0.173, so will save that for next week. One of the requests was for the ability to add custom after-save actions in the Page editor. These are the "Save + Exit", "Save + Add New", etc., dropdown actions that you see on the Save button in the page editor. This is something that's already supported, but not formally documented. So I wanted to quickly go through a couple examples of how to do that here, as it is kind of useful and fun. Let's start with a "hello world" example to keep it simple, then we'll move on to a more practical example. Say we want a "Save + Say Hello" dropdown action in our page editor Save button. We need one hook to add the action, and another to process it. These hooks could go in your /site/ready.php file or your /site/templates/admin.php file, or in a module. First we'll want to hook ProcessPageEdit::getSubmitActions() to add our custom "hello" action: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array of actions indexed by name $page = $event->object->getPage(); // page being edited // add a new action that says hello after saving page $actions['hello'] = [ 'value' => 'hello', // value for action that you will check 'icon' => 'hand-spock-o', // icon to show in action, excluding the 'fa-' part 'label' => '%s + Say Hello', // the '%' is replaced with 'Save' or 'Publish' 'class' => '', // optional class if you need different styling for button/link ]; $event->return = $actions; }); To process our action, we'll need to add a hook to ProcessPageEdit::processSubmitAction(): $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function($event) { $action = $event->arguments(0); // action name, i.e. 'hello' $page = $process->getPage(); // Page that was edited/saved if($action === 'hello') { $notice = new NoticeWarning("Hello! You edited page $page->path"); $notice->icon = 'hand-spock-o'; $event->notices->add($notice); } }); That's all there is to it. That part where I created the $notice above could just as easily been $this->warning("Hello!..."); but I wanted to add a custom icon to it, which is why I created the Notice manually. Many of the built-in after-save actions perform a redirect to another location, such as adding another page, exiting back to the page list, viewing the page on the front-end, etc. If you have a need to perform a redirect after the save, use the $event->object->setRedirectUrl($url); method. This is preferable to calling $session->redirect(); yourself, as it is handled by the page editor after it has finished everything it needs to do. What if you just want to remove one of the existing actions? For instance, maybe you want to remove the "Save + Add New" action. That action has the name "add", so we can remove it like this: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array of actions, indexed by name unset($actions['add']); $event->return = $actions; }); If there's another you'd like to remove, I'd recommend using TracyDebugger and bd($actions); so you can see and identify all the actions that are present from your hook. Now let's get to a more practical example. Let's say that you are using ProCache and you want to add a save action to automatically prime the cache after performing the save. By "prime the cache" I mean have it perform a page-view on the front-end that makes it save a new cache file for the page. Here's how you could do that: $wire->addHookAfter('ProcessPageEdit::getSubmitActions', function($event) { $actions = $event->return; // array $page = $event->object->getPage(); // page being edited $procache = $event->wire('procache'); if(!$procache) return; // if procache not installed, do not add action if(!$page->isPublic()) return; // page not public is also not cacheable if(!$page->viewable()) return; // page not viewable has no template file if(!$procache->isPageCacheable($page)) return; // page not setup for cacheing $actions['cache'] = [ 'value' => 'cache', 'icon' => 'fighter-jet', 'label' => '%s + Cache', // Save + Cache 'class' => '', ]; $event->return = $actions; }); …and our hook to process the action: $wire->addHookAfter('ProcessPageEdit::processSubmitAction', function($event) { $action = $event->arguments(0); // action name, i.e. 'cache' $page = $process->getPage(); // Page that was edited/saved if($action === 'cache') { $http = new WireHttp(); $response = $http->get($page->httpUrl); if($response) { $size = wireBytesStr(strlen($response)); $event->message("Cache primed for page $page->path ($size)", "nogroup"); } else { $this->warning("Error caching page: " . $http->getError()); } } }); Note that we don't have to clear the cache file here because that's something that ProCache has already done prior to our hook above being called. Thanks for reading and have a great weekend!1 point
-
Excited to be learning REACT/NextJS. It's so 'on-trend'. I can double my hourly rate, take 3x as long to deliver a website with 2/3 of the Google Lighthouse results and who doesn't love the spinner while the component content loads? Doing a well optimised PW site with minimal JS, fast page loads, accessibility, SEO and more built in is so old hat. And even better, with JS frontends, the code maintenance goes on and on. No end to revenue possibilities. FML1 point
-
1 point
-
The only thing what I remember is a login throttle module. Maybe you can copy this and adapt it for your use case, or borough some pieces of code from there?1 point
-
If you have a single page reference field called “author” on book pages (would probably recommend this way, even if you allow multiple authors per book): $book = $pages->get('template=book, title="The Hitchhiker’s Guide To The Galaxy"'); $author = $pages->get('template=author, title=Douglas Adams'); $book->of(false); $book->author = $author; $book->save(); If you have a multi page field called “books” on author pages: $author = $pages->get('title=Douglas Adams'); $books = $pages->find('title="The Hitchhiker’s Guide To The Galaxy"|"Life, the Universe and Everything"'); $author->of(false); foreach ($books as $book) $author->books->add($book); $author->save();1 point
-
Sorry, I don't get what you mean by "programmatically" and I don't get your example. Maybe others can help ?1 point
-
Hi Tobias, welcome to the forum! Sorry, I have no answer for you, but I can just tell you that I've never had any problems using $page->trash() in any of my projects. So your tricky part should really not be tricky at all ? Maybe there's something else going on...1 point
-
I've looked at quite a few other CMS/CMFs and most of them fall down in some respect compared to ProcessWire, whether it be documentation, community, or ease of use. That doesn't make ProcessWire perfect, and given the diversity of usage scenarios there will always be things that could be done differently. The admin certainly can be a mixed blessing. It's so easy to use, that it's tempting to rely on it at least to start with, but then when you need to maintain changes, it can get complicated. I think what could be quite nice, if it's possible, would be to have the ability to enable change tracking for templates and fields, when they're modified via the admin. It's already possible to export and import field and template definitions as JSON, so combine this with the ability to track what's changed, and something like @bernhard's migrations module, and it could be easier to combine the ease of using ProcessWire admin to make changes, and the need to be able to roll out changes from development to production sites.1 point
-
@thetuningspoon After save actions don't participate in a delete action. But I can add a hook for that purpose: ProcessPageEdit::redirectAfterDelete(). I'll have it in there in 3.0.173 and you can hook before that method to perform your own redirect before the page editor does.1 point
-
The page path is in the title attribute, so you can hover on results to see the path in the browser tooltip: PW doesn't make it easy to manipulate the markup of admin search results. You could try the hook below in /site/ready.php to append the root parent title to the result title: $wire->addHookBefore('ProcessPageSearchLive::execute', function(HookEvent $event) { $event->wire()->addHookAfter('FieldtypePageTitle::wakeupValue', function(HookEvent $event) { $page = $event->arguments(0); // Limit by template or some other property of $page if($page->template == 'basic_page' && !$page->get_original_title) { $root_parent = $page->rootParent; // Set custom page property to avoid affecting root parent title $root_parent->get_original_title = true; // Append root parent title $event->return .= " (Root parent: {$root_parent->title})"; } }); });1 point
-
Would showing the path instead of the title be okay ? I thought of a hook first but you could do the trick with a bit of CSS ul.pw-dropdown-menu-shorter li.ui-menu-item a::before { content: attr(title); margin-right: 3px; } ul.pw-dropdown-menu-shorter li.ui-menu-item a span { display: none; } (hopefully it doesn't target anything else, but from my quick testing it looks ok !) Before: After:1 point
-
Long time no post. Here's my latest: https://maisliberdade.pt/ Mais Liberdade is a liberal think-tank in Portugal, promoting the values of liberal-democracy, individual freedom and free market economy. It's a non profit that gathers collaboration from people from multiple portuguese political parties, members of the european parliament, economists, professors, etc. During development, an announcement page was set up with a registration form for founding members. In that period of about a month, around 200 subscriptions were expected, but in the end we got over 6000 subscribers. This website features essays, events, videos and a free library that, at the time of this post is counting 400 books. The frontend was built using web components (Stencil js). Basic pages are built with a modular approach, I'm attaching a video of how they are created. The approach is a simple repeater with a custom block type selector interface. That selector is basically a modified version of FieldtypeSelectFile. I've hacked that module to expect a PNG to be available for each PHP file in the blocks folder, and modified the input field to generate a button grid after the select. This is lovely to use from the editor's perspective, but it's something to improve for the developer experience, because in the end this is a repeater, that has to contain all fields that each type of block needs, and for each of those fields I have to set it to show only if the blockType field equals X, Y or Z. With a lot of different block types this takes some planning and easily becomes hard to manage, but it's the best approach I found yet and the benefit for the editor's experience is well worth it. covered-compressed.mp41 point
-
Hi @Ralf, sorry for the delay. Instead of checking for the $input->post->submit, you should check if the response from the ReCaptcha is green. So, instead of : // form was submitted so we process the form if($input->post->submit) { // Do cool stuff here <<<<-------- I cannot get in here } Do : // form was submitted so we process the form if($captcha->verifyResponse() === true) { // Do cool stuff here <<<<-------- you will get here now } Also, try to call the getScript() method on the end of your main markup page. I mean, just before the </body></html> tags. And to avoid calling the module every page request, you can for exemple, check if the current page's template is the contact one and then call the module's getScript() method : <html> <head> </head> <body> ... <!-- other tiers scripts exemple --> <script src="jquery.js"></script> <script src="anotherscript.js"></script> <?php if($page->template->name === 'contact-tpl') { // google recaptcha required script echo $modules->get("MarkupGoogleRecaptcha")->getScript(); } ?> </body> </html> Ping me if you need further help.1 point
-
May be a dumb question in the end but I normally use `$config->urls->root;` when creating a 'return to homepage' link but what do I do when I'm using multi-language? I thought `$user->language->root;` but this seems to return the current page (albeit localised). Any thoughts?1 point
-
$pages->get(1)->url; This returns the Home page url.1 point
-
You can check this by enabling "view system templates" in the template overview. This should show those automatically created templates. Edit: you need to literally add "repeater_" in front of thr name.1 point
-
You can actually select repeater pages by their template: $pages->find("template=repeater_fieldName");1 point