Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 02/22/2021 in all areas

  1. Thank you so much @Robin S and @Jan Romero for your detailed answers including full code, I would not have been able to come up with that on my own with my current coding ability, I only deal with my own sites and I have not figured out hooks on my own yet, so your code that I can copy and paste into my files is much appreciated. Sorry about the late reply - I had meant to get back to both of you much earlier. Likewise to your concerns, I did not want to derail this thread with my question. But to get back to the OP topic at hand, which is possible future changes for PW, specifically the admin panel, I feel that there is some relevancy for considering additional/dual sort order options built into the core. Maybe an option such as "sort children first by ..., next by ....." could be a possible feature for consideration in the PW core? This is because I feel like perhaps one thing that could have a bit of emphasis in PW is the experience for the admin. If a designer is handing over a site to an admin, the admin is the one who will be adding more and more pages to the site, and ultimately they (hopefully) will wind up with hundreds of pages of content, some of which needs to be updated more frequently than others. In this case, having the page tree displayed by sorting by 2 different options could be very helpful. For example, in my case I'd like to sort by custom field "sticky" first, and then by "date published, reverse". I'm not trying to derail this thread into my use case, but I'd like to point out the general use case of a PW page tree of hundreds of pages, of which some will be more important/significant to quickly locate than others. The use case where all pages fit on one page of the page tree should be considered as an edge case rather than a typical use case in terms of the admin UX experience. All of that said, I love the admin panel menu Find, and I love than I can narrow down to the pages I want there by selecting the combinations of templates and/or fields that are relevant. So that is a way of finding specific pages without looking manually at the many screens of page tree. Indeed, this Find menu itself can be used in combo with Jan Romero's custom "sticky" field, where any pages labelled "sticky" can be found easily. The existing Find menu as it stands is admittedly much better than any equivalents in other CMS's that I'm aware of. But I would love to see a dual way of sorting children in the admin page tree, I mean sort first by.... and next by..... To be fair, I'm not sure if that's a feature that others see as important. Site admins who have hundreds of pages may well feel the need for something like this though.
    3 points
  2. At the risk of derailing this thread, here is the simplest way I know to get sticky pages in the admin page tree. @Violet 1. Set up a checkbox field called “sticky”. 2. Add this hook at the top of /templates/admin.php (since it’s admin specific, but ready.php will work, too): $this->addHookBefore("ProcessPageList::find", function(HookEvent $event) { $selectorString = $event->arguments('selectorString'); if ($event->arguments('page')->sortfield() === 'sort') //if manual sorting is on for the children of this page, don’t do anything. return; //just add your checkbox to the start of the selector. it will sort by this first, and additionally by the usual sort field. $event->arguments('selectorString', 'sort=-sticky, ' . $selectorString); }); 3. Check the sticky box on pages you want to see at the top. It might make sense to make the field global, but the selector won’t care even if a page doesn’t have it. Or rather, Ryan probably went to great lengths to handle such cases ?
    2 points
  3. If you don't like to use a hook for this, there is a module: https://processwire.com/modules/process-page-list-multiple-sorting/
    1 point
  4. Once you've created your $year_overview PageArray, does the template use custom fields from the pages to generate the output? If so, it may be that the slowness is due to multiple calls back to the db during loops to get the custom fields' data. Try including the custom fields in the initial selector with 'auto-join' or using the new methods released by Ryan. https://processwire.com/blog/posts/find-faster-and-more-efficiently/#boost-performance-with-new-programmatic-autojoin-options
    1 point
  5. I have this issue on 2 sites so far - not sure how to fix it – do i need to manually create a dumps.json file in the site/assets/cache/TracyDebugger/ directory? Warning: PHP Warning: file_put_contents(.../public/site/assets/cache/TracyDebugger/dumps.json): failed to open stream: No such file or directory in .../modules/TracyDebugger/includes/TD.php:154
    1 point
  6. From cursory googling it seems jquery doesn’t support modifying the headers sent by load() specifically. This answer on SO has a somewhat messy solution that is discouraged by the jquery docs: https://stackoverflow.com/a/20067394/. Probably best to just use ajax() and select the elements yourself.
    1 point
  7. I think it might help to know what exactly you’re requesting. Some admin pages respond to ajax-requests with JSON and some with partial HTML. I just tested /processwire/access/users/edit/?id=40, which gives the full HTML page without ajax and a partial with ajax. As you said, PW detects ajax requests by the X-Requested-With header, so if you don’t send it or set it to something other than XMLHttpRequest, it should give you the same response you would get when navigating to the url in your browser. So, for example on the url I mentioned this works for me: $.ajax(window.location.href, { headers: {'X-Requested-With': 'justgivemethedanghtml'}, success: function (result) { console.log(result); } }) I suspect commenting out the line in ProcessWire.php didn’t help because the header is checked again in other places. The culprit is probably ProcessController.php: https://github.com/processwire/processwire/search?l=PHP&q=XMLHttpRequest. But obviously you can’t just comment that stuff out in production anyway. Just make your request pretend it isn’t ajax.
    1 point
  8. 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.mp4
    1 point
  9. The last 5 projects all needed some kind of API endpoint. Over time, I've settled for a custom "api" page under home. In two projects, this is a very simple piece of code with a switch statement, in others it looks for individual templates under templates/api. I'm not completely happy with any of them, though, and I've often wished for something akin to hooks with enough boilerplate to avoid repetitive code. I do concur that Laravel has some very nice and expressive features. I could picture a WireApi singleton class with which modules could register, and a fixed "api" page that is by default not much more than <?php namespace ProcessWire; wire('api')->handleRequest(); WireApi may or may not route to matching PHP files under templates/api by default. Autload modules could register their routes in their init() method. Just a rough example with one or two Laravel niceties stirred into the usual PW awesomeness to get a nice declarative approach to api route definitions: <?php namespace ProcessWire; class ApiExampleHandler extends ApiRoute { public static function getModuleInfo() { return [...]; } public function init() { parent::init(); # hand GET requests to /api/users/USERID/profiledata off to our getUsrProfileData method # and pass the value in place of USERID as the first parameter $user to the method. # Use $sanitizer->intUnsigned on $user to make sure it is a valid page id. $this->api->get('/users/{user}/profiledata', $this, 'getUserProfileData')->whereSanitized('user', 'intUnsigned'); } public function getUserProfileData($user) { $u = $this->users->get($user) ?: $this->api->notFound(); $p = $u->profilepage ?: $this->api->notFound(); # Set Content-Type header, set json_encode return value and output it $this->api->jsonResponse([ 'nickname' => $p->nick, 'hobbies' => $p->hobbies, 'membersince' => $p->joindate ]); } } Something along those lines could go a long way to making endpoint implementation easier. I don't know how often I've checked for isAjax et al, called json_decode and json_encode, checked the request method, sanitized and compared urlSegement1 and urlSegment2 and urlSegment3 (and sometimes even urlSegement4) in nested conditionals... For quick and dirty solutions, api route registration could go into api.php before handleRequest() is called, or even into site/ready.php. With a bit of creative magic, a nice PWish equivalent to Laravel's model binding should also be in the realm of possible things.
    1 point
  10. 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).
    1 point
  11. Suggested roadmap candidates to improve core: One-step Page Creation: Skip "Add New" and go directly to the resulting page. Better un-global Title fields. Page urls with auto-incrementing IDs (and without Page Name parts). Easier Permissions for Users, Roles, Templates & Pages
    1 point
  12. Thanks for a great module Teppo. I don't suppose anyone has had success recording version control changes with front-end inline editing? I'm using inline editing on a personal project with just one specific field which is a large textarea (the rest use dialogue editor - works great). Edit: Silly me, Version Control changes are indeed recorded with in-line editing. The field is within a repeater, so the front-end editor only saves changes to the repeater ID. It's still saved to the appropriate Version Control database tables.
    1 point
×
×
  • Create New...