Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/05/2022 in all areas

  1. In this post we cover the details of a new module (ProcessLanguageFieldExportImport) that enables export and import capabilities for multi-language fields in ProcessWire— https://processwire.com/blog/posts/language-field-export-import/
    10 points
  2. Modules Directory: https://processwire.com/modules/rock-frontend Github: https://github.com/baumrock/RockFrontend
    8 points
  3. I'll share my youtube videos in this thread and if you have questions this is the place to ask. You can also subscribe to this thread to get notified when I post new videos ? Here is the link to my channel: baumrock.com/youtube --- Hey! I've just published my very first ProcessWire video. It's about RockFrontend: https://processwire.com/talk/topic/27417-rockfrontend-??-take-your-processwire-frontend-development-to-the-next-level/#comment-225666 Here is the video: What do you think? Do you understand what I'm trying to explain (despite the many ääähms und öööhms...)? ? What about the length?? I really didn't plan do get to 40mins... Did anybody even watch it till the end? ? Would it be easier to follow when having a small thumbnail in the bottom corner when working on the code? Or better without? Is it worth the effort of creating a video or would a readme be just as good? ? Any tips for better sound/lighting? I'm not really knowing what I do, so any ideas for improvements are very welcome ? Better with or without background music? So many questions... So much to learn... ? But it's fun and I'm a bit proud ?
    7 points
  4. ProcessLanguageFieldExportImport is a multi-language field export/import tool for ProcessWire This is a general support thread for the multi-language field export/import module in the modules directory here and as described in this blog post. This module is also designed to work with several of the ProFields multi-language types. VIP support for this module is available in the ProFields and ProDevTools support boards.
    3 points
  5. BOOOOOOM ???? Bernhard dropped the bomb. I'm halfway through the video and so far love everything about it. Nice video setup and editing there too. Going back to the video now ? ------------------- Edit: Okay, I'm through and this is definitely super cool. Looking forward to trying it out. There are two things though that I'm not sure about and wanted to mention: 1. The name Alfred. While you've found a sweet acronym it (in my opinion) has the huge drawback that new developers looking at the code and seeing alfred($page, ['fields' => 'gallery']) will have absolutely zero clue what's going on. Most of us love ProcessWire because it's intuitive. With this name you have to first learn that alfred is an inline editor to understand what the code is supposed to be doing. 2. I'm not sure about this one, but adding assets to the header through hooks reminds me of dark Wordpress times. I like that with ProcessWire you are able to to see where things are coming from and you have total control over what's happening.
    3 points
  6. Brilliant! Since i am involved in multilanguage projects most of the time, this will become very handy. And i use/like the combo fieldtype a lot. So it would be great to see the module supports this fieldtype!
    2 points
  7. Perfectly understandable! I have learned the bad way (writing docs that no one reads lol) that some people just prefer videos! So I think it's a really good resources despite the effort it requires! They give so much information that might be taken for granted in a text documents. So rather than one or the other I think both tackle different "moments" throughout a person's learning process and also preferences. I prefer without music, but that's just a preference I guess?? It is a REALLY great video!! I skipped a few parts, but watched around 50% of it, will watch it fully later. Not sure if you have previous experience recording/editing etc, but nonetheless this video is RockSolid (...?)! Also the audio is really good! Not an expert myself, but no noise or anything distracting on this end. I guess each topic on video production is a rabbit hole!
    2 points
  8. A new tab isn't a new session - just like having PW frontend and backend open in different tabs - you stay logged into both, and any further tabs you might open. A new window might be (I haven't tested) but surely a user savvy enough to do that will be savvy enough to expect adverse consequences (I would have thought anyway...).
    2 points
  9. Hey folks! Took a couple of late nights, but managed to turn this old gist of mine into a proper module. The name is SearchEngine, and currently it provides support for indexing page contents (into a hidden textarea field created automatically), and also includes a helper feature ("Finder") for querying said contents. No fancy features like stemming here yet, but something along those lines might be added later if it seems useful (and if I find a decent implementation to integrate). Though the API and selector engine make it really easy to create site search pages, I pretty much always end up duplicating the same features from site to site. Also – since it takes a bit of extra time – it's tempting to skip over some accessibility related things, and leave features like text highlighting out. Overall I think it makes sense to bundle all that into a module, which can then be reused over and over again ? Note: markup generation is not yet built into the module, which is why the examples below use PageArray::render() method to produce a simple list of results. This will be added later on, as a part of the same module or a separate Markup module. There's also no fancy JS API or anything like that (yet). This is an early release, so be kind – I got the find feature working last night (or perhaps this morning), and some final tweaks and updates were made just an hour ago ? GitHub repository: https://github.com/teppokoivula/SearchEngine Modules directory: https://modules.processwire.com/modules/search-engine/ Demo: https://wireframe-framework.com/search/ Usage Install SearchEngine module. Note: the module will automatically create an index field install time, so be sure to define a custom field (via site config) before installation if you don't want it to be called "search_index". You can change the field name later as well, but you'll have to update the "index_field" option in site config or module settings (in Admin) after renaming it. Add the site search index field to templates you want to make searchable. Use selectors to query values in site search index. Note: you can use any operator for your selectors, you will likely find the '=' and '%=' operators most useful here. You can read more about selector operators from ProcessWire's documentation. Options By default the module will create a search index field called 'search_index' and store values from Page fields title, headline, summary, and body to said index field when a page is saved. You can modify this behaviour (field name and/or indexed page fields) either via the Module config screen in the PocessWire Admin, or by defining $config->SearchEngine array in your site config file or other applicable location: $config->SearchEngine = [ 'index_field' => 'search_index', 'indexed_fields' => [ 'title', 'headline', 'summary', 'body', ], 'prefixes' => [ 'link' => 'link:', ], 'find_args' => [ 'limit' => 25, 'sort' => 'sort', 'operator' => '%=', 'query_param' => null, 'selector_extra' => '', ], ]; You can access the search index field just like any other ProcessWire field with selectors: if ($q = $sanitizer->selectorValue($input->get->q)) { $results = $pages->find('search_index%=' . $query_string . ', limit=25'); echo $results->render(); echo $results->renderPager(); } Alternatively you can delegate the find operation to the SearchEngine module: $query = $modules->get('SearchEngine')->find($input->get->q); echo $query->resultsString; // alias for $query->results->render() echo $query->pager; // alias for $query->results->renderPager() Requirements ProcessWire >= 3.0.112 PHP >= 7.1.0 Note: later versions of the module may require Composer, or alternatively some additional features may require installing via Composer. This is still under consideration – so far there's nothing here that would really depend on it, but advanced features like stemming most likely would. Installing It's the usual thing: download or clone the SearchEngine directory into your /site/modules/ directory and install via Admin. Alternatively you can install SearchEngine with Composer by executing composer require teppokoivula/search-engine in your site directory.
    1 point
  10. This module is an optional (and still somewhat experimental) add-on for SearchEngine. It adds support for indexing file contents, replacing earlier SearchEngine PDF indexer module. Features SearchEngine by itself will only store the name, description, tags, and custom field values for file/image fields. This module, on the other hand, attempts to extract human-readable text from the file itself. As for file types, at least in theory this module supports any filetype that can be reasonably converted to text. It has built-in support (mostly via third party libraries) for... office documents (.doc, .docx, .rtf, .odf), pdf documents (.pdf), spreadsheets (.xls, .xlsx, .ods, .csv) and plain text (.txt). The module also ships with a FileIndexer base class and exposes the SearchEngineFileIndexer::addFileIndexer() method for introducing indexers for file types that are not yet supported. Links GitHub: https://github.com/teppokoivula/SearchEngineFileIndexer Composer: composer require teppokoivula/search-engine-file-indexer Modules directory: https://processwire.com/modules/search-engine-file-indexer/ Getting started install and configure SearchEngine (version 0.34.0 or later), install SearchEngine File Indexer, install third party dependencies — if you installed SearchEngineFileIndexer via Composer you should already have these available, otherwise you'll need to run "composer install" in the SearchEngineFileIndexer module directory, choose which file indexers you'd like to enable. The rest should happen automagically behind the scenes. Additional notes The important thing to note here is that we're going to rely on third party libraries to handle parsing (most) files, and things can still go wrong, so please consider this a beta release. It did work in my early tests, but there's little guarantee that it will work in real life use cases. Just to be safe it is recommended to back up your site before installing and enabling this module. Another thing to keep in mind is that indexing files can be resource intensive and take plenty of time. As such, this module provides some settings for limiting files by size etc. Regardless, this is something that likely needs further consideration in the future; some future version of this module, or an additional add-on module, may e.g. add support for indexing pages/files "lazily" in the background.
    1 point
  11. Following up on my July 15th post, I've been working on converting ~1600 reviews from a 3rd party service (BazaarVoice) into ProcessWire for a client's website. That conversion is pretty much done now, here's an example page that has a few reviews (click on the Reviews tab). As you can see, we're using the ProcessWire comments field to store not just the review, but also 15 other details and up to 6 photos, per review. This was all done using the new "meta" features of ProcessWire's comments, mentioned in that post linked above. Though I didn't have an example to show you at the time, so wanted to link it here. Here's another example of how someone can submit a review here. This form is built in FormBuilder and uses an updated FormBuilderFile Inputfield module which will be bundled in the next version of FormBuilder. This new version of InputfieldFormBuilderFile adds a few useful features such as: The ability to show a preview image (when uploading photos). The ability to show just one file input at a time, and reveal additional ones as needed. The ability to include a text or textarea description with each file upload. These are all optional and can be enabled or disabled in the field settings. If none of the options are enabled when the output is exactly the same as before, meaning the upgrade should be seamless for existing forms already using the files input. The way that a submitted review goes from FormBuilder into a comment is automated with a hook to FormBuilder's "saveForm" method. When the form is submitted, it creates a new pending comment, translating most of the fields into 'meta' data in the comment, there's really not much to it. If you ever have a similar need, be sure to let me know and I'm happy to share the hook code that worked for me. In addition to those updates for FormBuilder, this week I've also worked on some related updates to ProcessWire's comments field, especially with improvements to the ProcessCommentsManager module. The module now has a separate dedicated comment editor where you can edit existing comments, and add new comments or replies. Previously you could not add new comments/replies in the comments manager. In the case of the site linked above, they use this particular feature for adding staff replies to reviews. I think this comments stuff is largely done now so next week I'll likely be back to working on other parts of the core and modules. Thanks for reading and have a great weekend!
    1 point
  12. This is awesome! I will try it with our https://www.across.net/ translation tool
    1 point
  13. Neither am I. ? It was just a thought that came while watching your video. rockFrontendEditing for example wouldn't sound as catchy, but would be clearer for newcomers. I really like the new syntax. I wanted to suggest a Latte attribute first, but then decided to keep it simpler. Your approach looks nice. Imo it would b good to explain why and when this is needed instead of just using $page->edit('myfield') Perfect! So you get the best of both worlds. I'm sick at home this weekend, hopefully I will find time to give it a try already.
    1 point
  14. Wow! In general I think it's a huge benefit for the community to have a more opinionated way of doing frontend, so congrats on this is amazing module! I have no further comments until I try it fully but from what I see in the video it looks fantastic.
    1 point
  15. I guess this is largely a matter of personal preference. My personal preference is for a written description that can be accessed other than just while coding. This means that one can get an at-a-glance overview and dip in for more detail, without having downloaded the module and fired up the IDE. Call me sad, but I sometimes read this stuff sat in an armchair, not at the workstation ?. I gave the example above of the readme for FieldtypeMeasurement. Perhaps the ideal approach is to have all the documentation in PHPDoc. This is pretty much the approach of PW, so that then the help documentation (API ref) can be generated automatically from the code. If that approach is chosen, then a bit more explanation in the PHPDocs would be helpful. For example, the PHPDoc for alfred is /** * ALFRED - A Lovely FRontend EDitor * @return string */ There is no description of the options and their defaults (although these can be seen by inspecting the code). PW PHPDocs tend to include option descriptions. See $pages->find for a (very full) example /** * Given a Selector string, return the Page objects that match in a PageArray. * * - This is one of the most commonly used API methods in ProcessWire. * - If you only need to find one page, use the `Pages::get()` or `Pages::findOne()` method instead (and note the difference). * - If you need to find a huge quantity of pages (like thousands) without limit or pagination, look at the `Pages::findMany()` method. * * ~~~~~ * // Find all pages using template "building" with 25 or more floors * $skyscrapers = $pages->find("template=building, floors>=25"); * ~~~~~ * * #pw-group-retrieval * * @param string|int|array|Selectors $selector Specify selector (standard usage), but can also accept page ID or array of page IDs. * @param array|string $options One or more options that can modify certain behaviors. May be associative array or "key=value" selector string. * - `findOne` (bool): Apply optimizations for finding a single page (default=false). * - `findAll` (bool): Find all pages with no exclusions, same as "include=all" option (default=false). * - `findIDs` (bool|int): 1 to get array of page IDs, true to return verbose array, 2 to return verbose array with all cols in 3.0.153+. (default=false). * - `getTotal` (bool): Whether to set returning PageArray's "total" property (default=true, except when findOne=true). * - `loadPages` (bool): Whether to populate the returned PageArray with found pages (default=true). * The only reason why you'd want to change this to false would be if you only needed the count details from * the PageArray: getTotal(), getStart(), getLimit, etc. This is intended as an optimization for $pages->count(). * Does not apply if $selector argument is an array. * - `cache` (bool): Allow caching of selectors and loaded pages? (default=true). Also sets loadOptions[cache]. * - `allowCustom` (boolean): Allow use of _custom="another selector" in given $selector? For specific uses. (default=false) * - `caller` (string): Optional name of calling function, for debugging purposes, i.e. "pages.count" (default=blank). * - `include` (string): Optional inclusion mode of 'hidden', 'unpublished' or 'all'. (default=none). Typically you would specify this * directly in the selector string, so the option is mainly useful if your first argument is not a string. * - `stopBeforeID` (int): Stop loading pages once page matching this ID is found (default=0). * - `startAfterID` (int): Start loading pages once page matching this ID is found (default=0). * - `lazy` (bool): Specify true to force lazy loading. This is the same as using the Pages::findMany() method (default=false). * - `loadOptions` (array): Optional associative array of options to pass to getById() load options. * @return PageArray|array PageArray of that matched the given selector, or array of page IDs (if using findIDs option). * * Non-visible pages are excluded unless an "include=x" mode is specified in the selector * (where "x" is "hidden", "unpublished" or "all"). If "all" is specified, then non-accessible * pages (via access control) can also be included. * @see Pages::findOne(), Pages::findMany(), Pages::get() * */ I use PHPStorm, not VSCode. It has a structure view similar to VSCode's outline. However, that just lists the method names etc. - I assume VSCode is similar* - so you need to go to the actual code to get the PHPDoc. In any case, you do need to be at the workstation and to have downloaded the module to see this. As I said, I appreciate that this is a personal thing, so please don't take it as a criticism, but you did ask whether a readme would be just as good, to which my answer is The video is very useful to give an introduction, but is longer than it would take to view a readme. Ideally there would be both, but the readme would be more complete, but less wordy (as described above). *PS I downloaded VSCode and I see that the outline does give variables as a drop-down, but not PHPDoc. Perhaps I should investigate it a bit more...
    1 point
  16. Your IDE should also have an outline view that is built for this purpose: Does that help? Or are you meaning something Else? ?
    1 point
  17. Thanks for the tip. Is there any chance to auto-switch spellcheck language when switching between languages in Processwire?
    1 point
  18. Great video Bernhard! As always, very informative. I watched to the end. The only thing I would suggest is to bump up your font size a little bit more in your code editor while recording. In general, I prefer to not have background music in coding videos when the person is talking. Looking forward to any other future videos you publish.
    1 point
  19. This is a killer module. Outstanding work and great features. Will definitely use RockFrontend on some upcoming projects.
    1 point
  20. Well done on your first video! I can certainly appreciate the time that's gone into it, and has better quality than some others I've seen. I didn't watch all of it to the end (sorry) but I did feel that I got a good introduction to RockFrontend, and knew that if I wanted to fully utilise it on a project, I could watch it all to get a better idea of how to integrate it. Sometimes videos are great for showing how to use something in the context it's meant to, and to follow along all the steps; but I don't think videos are a complete replacement for READMEs or text-based documentation. I usually prefer shorter and more specific videos, rather than long ones covering a wider range of steps. As an example, I've recently watched a few videos on the BugBytes channel and feel they're about the right length and style (for me!), and they're usually 15-30 minutes. I don't have any advice on lighting or music, but the sound seems fine and clear to me ?
    1 point
  21. I have tried that twice. The first try was for a client and I implemented everything in PHP. That kind of worked and it still works... But I don't really like the solution because it feels very old-school. The second one was a great implementation using alpinejs for reactivity for the cart, very similar to snipcart. Very nice gui and look and feel (using uikit). I wanted to use snipcart first, but I was not able to get that running with things that seemed to be quite common requirements. So I started building my own solution. But the project was never finished. So we kind of failed with that second try. What I realized: I totally underestimated all the things that are necessary to build such an "easy cart + checkout" thing... And I guess it was the same thing for padloper1 (which was abandoned) and padloper2 (which was delayed for a year or so?). That's no offense in any way, it's just a warning that you might be underestimating things as well ? Take the screenshot below: What if the user wants to change the cart at that step? What if he/she enters wrong details? What if you need coupons? What if the payment fails? What if you need multiple languages? etc etc... But if you want to build it, go ahead. I'm always a fan of doing things on your own. I just have a feeling that this statement is a little... underestimating things... that's all ? I guess that both snipcart and padloper are easily worth their price ?
    1 point
  22. I don't suppose there's any chance of getting these juicy forum board solutions added to related module documentation as Examples, could we? These are great starting points to common scenarios! The downside would be maintaining them for compatibility, but perhaps explicit notices with dates that the examples were created? So often I end up searching the website for answers to questions, but they're all over the place - the blog, documentation, api, forum (and not always the module forum). ? Just a thought. That said, loving these examples you're providing from actual client work you're doing. Thanks, Ryan!
    1 point
  23. @MrSnoozles Yes you can do this, but not directly. There aren't any file/image functions in comments, but you can use $comment->setMeta('name', 'value'); to store whatever you'd like. So in my case, when someone submits a review with photo attachments, I create a directory /site/assets/comments/[page-id]/[comment-id]/ and then copy the files into it. To do this, take the saveForm() hook code I posted above and append this into it. Note that 'photos' refers to the name if my files field in FormBuilder, but it's also the name I'm using to store an array of photo files (basenames) in my comment meta data: $entry = $processor->getEntry(); if($comment->id && !empty($entry['photos']) && $entry['id']) { $meta = $comment->getMeta(); $path = $processor->entries()->getFilesPath($entry['id']); $meta['photos'] = addCommentPhotos($comment, $entry, $path); $field->updateComment($page, $comment, [ 'meta' => $meta ]); } The snippet above got the meta['photos'] from an addCommentPhotos() function. Here's an example of that function below. It copies the photo files out of the entry, validates them, and places them into the /site/assets/ directory I mentioned above. Note that it requires the FileValidatorImage module. function addCommentPhotos(Comment $comment, array $entry, $sourcePath) { $files = wire()->files; $sanitizer = wire()->sanitizer; $validator = wire()->modules->get('FileValidatorImage'); /** @var FileValidatorImage $validator */ $page = $comment->getPage(); $targetPath = wire()->config->paths->assets . "comments/$page->id/$comment->id/"; $photos = []; // create target directory for files if(!is_dir($targetPath)) $files->mkdir($targetPath, true); foreach($entry['photos'] as $filename) { $sourceName = basename($filename); $sourceFile = $sourcePath . $sourceName; if(!is_file($sourceFile)) continue; // file not found if(!$validator->isValid($sourceFile)) { // photo not valid $processor->addWarning("Error adding photo $sourceName - " . $validator->getReason()); continue; } $sourceExt = pathinfo($sourceFile, PATHINFO_EXTENSION); $sourceName = pathinfo($sourceFile, PATHINFO_FILENAME); $n = 0; // ensure filename is unique do { $targetName = $sanitizer->fieldName($sourceName); if(empty($targetName)) $targetName = 'photo'; $targetName .= ($n ? "-$n" : "") . ".$sourceExt"; $targetFile = $targetPath . $targetName; $n++; } while(is_file($targetFile)); // copy file to target location if($files->copy($sourceFile, $targetFile)) { // populate file basename in $photos $photos[] = $targetName; } } return $photos; } That takes care of getting the photos to the right place. When you want to output then with your comments, here's roughly how you might do it: foreach($page->comments as $comment) { $cite = $comment->getFormatted('cite'); $text = $comment->getFormatted('text'); $when = wireRelativeTimeStr($comment->created); echo "<div class='comment'>"; echo "<p>Posted by: $cite ($when)</p>"; echo "<p>$text</p>"; $photos = $comment->getMeta('photos'); if(!empty($photos)) { $dir = "comments/$page->id/$comment->id/"; $url = $config->urls->assets . $dir; $path = $config->paths->assets . $dir; echo "<ul class='comment-photos'>"; foreach($photos as $basename) { $fileName = $path . $basename; $fileUrl = $sanitizer->entities($url . $basename); if(file_exists($fileName)) { echo "<li><img src='$fileUrl' alt='' /></li>"; } } echo "</ul>"; } echo "</div>"; } But wait, what about when you do things like delete a page, or an individual comment, and want to make sure the photos are deleted too? You can do this by adding hooks into your /site/ready.php file: /** * After page deleted, delete comment files * */ $pages->addHookAfter('deleted', function(HookEvent $event) { $page = $event->arguments(0); /** @var Page $page */ $path = $event->wire()->config->paths->assets . "comments/$page->id/"; if(is_dir($path)) { $event->wire()->files->rmdir($path, true); $event->message("Deleted page comments files path: $path"); } }); /** * After individual comment deleted, delete comment files * */ $wire->addHookAfter('FieldtypeComments::commentDeleted', function(HookEvent $event) { $page = $event->arguments(0); /** @var Page $page */ $comment = $event->arguments(2); /** @var Comment $comment */ $path = $event->wire()->config->paths->assets . "comments/$page->id/$comment->id/"; if(is_dir($path)) { $event->wire()->files->rmdir($path, true); $event->message("Deleted comment files path: $path"); } });
    1 point
  24. @Kiwi Chris Let's say you've got a FormBuilder form named "review" and it has these fields, all of which are required: reviewed_page (Page) where user selects what page they are reviewing reviewer_name (Text) reviewer_email (Email) review_text (Textarea) star_rating (Integer) recommend (Toggle Yes/No) Your comments field is named "comments". We have a template named "form-reviews" where we output this form using FormBuilder embed method C. Above the embed C output code, in that file we have a hook which takes the submitted review and converts it to a pending comment: $forms->addHookAfter('FormBuilderProcessor::saveForm', function(HookEvent $event) { $processor = $event->object; /** @var FormBuilderProcessor $processor */ $form = $event->arguments(0); /** @var InputfieldForm $form */ $field = $event->wire()->fields->get('comments'); /** @var CommentField $field */ $page = $form->getValueByName('reviewed_page'); /** @var Page $page */ $errors = $processor->getErrors(); if(count($errors)) return; // if there were errors, do not create a comment yet $comment = new Comment(); $comment->status = Comment::statusPending; $comment->cite = $form->getValueByName('reviewer_name'); $comment->email = $form->getValueByName('reviewer_email'); $comment->text = $form->getValueByName('review_text'); $comment->stars = $form->getValueByName('star_rating'); // example of using meta data $comment->setMeta('recommended', $form->getValueByName('recommended')); if($field->addComment($page, $comment, true)) { // pending comment added successfully } else { // failed to add comment $processor->addError("Error adding review/comment"); } }); That's basically it. In my case, I have a lot more "meta" fields, so my hook is longer than this. This hook could also be to FormBuilderProcessor::formSubmitSuccess but I choose the saveForm instead because at this point I can still add my own error messages that will be displayed to the user. This gives you the opportunity to do additional validation, should you want to. By the time the formSubmitSuccess method is reached, it's already been determined there were no errors, so at that point you couldn't refuse the form submission if you can't convert it to a Comment for one reason or another. Let's say your Comments field is named "comments", then $page->comments->stars() will return the average of all star ratings on $page (floating point number between 0 and 5.0). For more details, arguments, options see: https://processwire.com/api/ref/comment-array/stars/ https://processwire.com/api/ref/comment-array/render-stars/ https://processwire.com/api/ref/comment-stars/ For rendering stars it'll use ★ but if you want it to use a different icon you can use CommentStars::setDefault() i.e. CommentStars::setDefault('star', '<i class="fa fa-star"></i>')); There are lots of other things you can specify to setDefault() so it's worth looking directly in the file if you decide to use it.
    1 point
  25. hi, just my two cents ? like @Gideon So says, the created on field in pw is called "created" (you can see this having a look at the bdd tables) something i often do when i need a peculiar sorting for a repeater is using this famous hook in the site ready.php file $this->addHookAfter('FieldtypeRepeater::wakeupValue', function($event) { $field = $event->arguments('field'); if($field->name !== 'your_repeater_name') return; // in order to sort only a specific repeater $pa = $event->return; $pa->sort("sorting_field"); // the field you want the repeater to be sorted by $event->return = $pa; }); this way, the repeater is also sorted the way you want in the admin in case it may help have a nice day
    1 point
  26. Hi @Lumi There is no ctime field in processwire. Please follow my example or Bernahrd's example and use created instead. Gideon
    1 point
  27. In recent PW versions it's possible to insert new repeater items at any position, so if your customer wants to insert an item at the top they can click the "Insert new item before this one" button on the first repeater item. See the video at the top of this blog post: https://processwire.com/blog/posts/new-repeater-and-repeater-matrix-features/ Though I'm not sure why new repeater items added this way are not expanded when they are added, so I've opened a GitHub issue about it: https://github.com/processwire/processwire-issues/issues/1596
    1 point
  28. No. The point about repeaters is to give you the ability to input repeatable content. The sort order in the backend can be but does not have to be the defining factor for the sort order in the frontend. You can either use the sort order of the backend or you can reverse it. Or you can sort by another property (like created timestamp). Or you can filter content etc etc... $page->your_repeater_field->each('title'); // sort order like in the backend $page->your_repeater_field->sort('-sort')->each('title'); // reverse sort order $page->your_repeater_field->sort('-created')->each('title'); // newest first
    1 point
  29. Hi @Lumi You can use the sort function. https://processwire.com/api/ref/fieldtypes/sort/ Something like the following I believe would work. $your_repeaters = $page->your_repeater_field->sort('created'); foreach($your_repeaters as $your_repeater) { //Your stuff goes here } Gideon
    1 point
  30. Ah I see, I have a hook that auto generates names for these pages so that was the culprit. Checking for status 'trash' before doing the name change solved this problem.
    1 point
  31. I think you have to hook into Page::viewable, then detect if user has role reviewer and page is unpublished. If yes, you can change the return to true. Please search for hook examples with Page::viewable here in the forums. There will be some available. Or you look into existing modules how it is done there, like this one: https://github.com/Sebiworld/PageAccessReleasetime/blob/master/PageAccessReleasetime.module.php#L182-L201 and here https://github.com/Sebiworld/PageAccessReleasetime/blob/master/PageAccessReleasetime.module.php#L241-L254 And you don't need to build a module, you can write the hook into the site/ready.php file.
    1 point
  32. $pf = $pages->getPageFinder(); $selector = new Selectors($selector); $query = $pf->find($selector, ['returnVerbose' => true, 'returnQuery' => true]); # Show sql $query->getQuery(); # Modify query $query->where($sql); # Run query $query->execute();
    1 point
×
×
  • Create New...