Leaderboard
Popular Content
Showing content with the highest reputation on 12/27/2022 in all areas
-
Hello all, I wanted to share a proof of concept approach on how we can have an infinite scroll pattern without writing Javascript. We can achieve this with htmx. What you will get An overview page with a list of posts (PW pages). On initial page load 5 posts will be shown. When scrolling down and reaching the last post, another 5 posts will be loaded via AJAX in the background and appended after the last post until no more pages are found. Prerequisites You are using the delayed output strategy, with a _main.php appended. Just like using the default site profile when installing ProcessWire You are using markup regions, in my _main.php I have a div#content that will be used for the output of the posts Inside site/config.php $config->useMarkupRegions = true; Inside site/templates/_main.php <!-- main content --> <div id='content'> </div> For script loading I am using a custom $config->bodyScripts FilenameArray Inside site/config.php $config->bodyScripts = new FilenameArray(); Inside site/templates/_main.php before the closing </body> tag <?php foreach ($config->bodyScripts as $file) : ?> <script src="<?= $file ?>"></script> <?php endforeach ?> </body> PW page structure for this tutorial In the page tree I have a parent page "Posts" with template "posts". All child pages of that page have template "post" In the template "posts" settings in the "URLs" tab, check "Allow Page Numbers" and save. Needed for pagination. When viewing the page "Posts" all logic happens inside site/templates/posts.php site/templates/posts.php <?php namespace ProcessWire; // posts.php template file // add htmx js from site/templates/scripts $config->bodyScripts->add($config->urls->templates . 'scripts/htmx.min.js'); $limit = 5; $posts = $pages->find("template=post, limit={$limit}"); $lastPost = $posts->last(); $nextPageUrl = $page->url . $input->pageNumStr((int) $input->pageNum() + 1); $hxAttributes = array(); $hxAttributes[] = 'hx-get="' . $nextPageUrl . '"'; $hxAttributes[] = 'hx-trigger="revealed"'; $hxAttributes[] = 'hx-swap="afterend"'; ?> <?php if (!$config->ajax) : ?> <section pw-append="content" class="posts" hx-headers='{"X-Requested-With": "XMLHttpRequest"}'> <?php endif ?> <?php foreach ($posts as $post) : ?> <article class="post" <?php if ($post == $lastPost) echo implode(' ', $hxAttributes) ?>> <header> <h3><?= $post->title ?></h3> </header> </article> <?php endforeach ?> <?php if ($config->ajax) return $this->halt() ?> <?php if (!$config->ajax) : ?> </section> <?php endif ?> And that is all there is to it. Not a single line of Javascript, thanks to htmx. I followed the infinite scroll pattern from the official htmx examples. Now let's break the code down into easily digestible chunks // add htmx js from site/templates/scripts $config->bodyScripts->add($config->urls->templates . 'scripts/htmx.min.js'); This adds site/templates/scripts/htmx.min.js to our custom $config->bodyScripts FilenameArray so it will be loaded in _main.php. You can get the script here from unpkg.com. $limit = 5; $posts = $pages->find("template=post, limit={$limit}"); Sets our pagination limit to 5 and loads the correct set of posts. $lastPost = $posts->last(); Saves the last post of each set. We use this later to determine whether the htmx attributes should be rendered. $nextPageUrl = $page->url . $input->pageNumStr((int) $input->pageNum() + 1); We are building the link to the next "page" with the next set of posts. Will result in something like "/posts/page2", "/posts/page3" etc. $hxAttributes = array(); $hxAttributes[] = 'hx-get="' . $nextPageUrl . '"'; $hxAttributes[] = 'hx-trigger="revealed"'; $hxAttributes[] = 'hx-swap="afterend"'; Define our htmx attributes as an array. They will be added to every last post's HTML. Note the hx-get attribute which will be the URL for the AJAX call in the background. That request is triggered whenever the last post becomes visible inside the viewport while scrolling down. hx-swap afterend tells htmx to append the next batch of posts after the last post. <?php if (!$config->ajax) : ?> <section pw-append="content" class="posts" hx-headers='{"X-Requested-With": "XMLHttpRequest"}'> <?php endif ?> // and <?php if (!$config->ajax) : ?> </section> <?php endif ?> Renders the wrapping section tag only on initial page load which is a none AJAX request. Note the hx-headers='{"X-Requested-With": "XMLHttpRequest"}'. This adds an additional header to all AJAX requests with htmx. We need this header so ProcessWire understands that it is an AJAX request. Otherwise $config->ajax would always return false. See https://htmx.org/attributes/hx-headers/ for more info <?php foreach ($posts as $post) : ?> <article class="post" <?php if ($post == $lastPost) echo implode(' ', $hxAttributes) ?>> <header> <h3><?= $post->title ?></h3> </header> </article> <?php endforeach ?> Render each posts's HTML. If it is the last post, also render our htmx attributes. For brevity in this example I only output the post title. <?php if ($config->ajax) return $this->halt() ?> For AJAX requests stop execution of the template file and everything that follows. This prevents appending of _main.php for ajax calls. So we only get the desired HTML for the list of posts and no head, footer etc. Summary Compared to other approaches, htmx lets us control all our AJAX logic with a few html attributes. Really neat and concise. Easypeasy. I like that and will surely use an approach like this in future when infinite scroll is needed. What I like in particular is how easy this is implemented with ProcessWire's powerful pagination capabilities. If you have the same page structure, the code in site/templates/posts.php is working out of the box as is. I have this running on a standard PW multilang site profile with additions/amendments mentioned above under "Prerequisites". Here's a visual of the result:13 points
-
Merry Christmas, Happy Hanukkah, and Happy Holidays! The plan is to release a newyear main/master core version. I'm not currently aware of any showstopper issues specific to the current dev branch, but if you are aware of any, please report them in the GitHub issues repo (or reply to an existing issue report), as the dev branch will soon become the master branch. There's not yet a hard deadline, so whether it's end of December or the 1st week of January, we'll have a new release out shortly. The dev branch is very stable right now (likely more stable than the master branch) so it's a good time to get a new version out. I've also been holding off on several larger updates to the dev branch in anticipation of this merge to master and new release, so I've likewise been holding back on any commits that would add more to test. Once we get a new main/master release out there, the dev branch will then get InputfieldTinyMCE merged into it and there will be some JS library updates, along with other larger updates, and those that would need dev branch testing. Thanks for reading and I hope that you have a great holiday weekend and week ahead3 points
-
The TinyMCE 6 rich text editor opens up a lot of new and useful abilities for ProcessWire users. In this post, we'll take a look at a few of them, and how you can start using them now, with a focus on those that are unique to ProcessWire's implementation of TinyMCE— https://processwire.com/blog/posts/using-tinymce-6-in-processwire/1 point
-
Looks like https://processwire.com/modules/profields-table/ could be a good candidate for your use case.1 point
-
1 point
-
1 point
-
@bernhard Yes, so far it sounds like that would work. I might be forgetting something, but I will definitely look into adding that, thanks!1 point
-
1 point
-
Hey @ryan I've managed to find a way to get a minimal tinymce field using this very simple json: { "menubar": false, "toolbar": "bold", "toolbar_sticky": true } Result: This is very nice and what I want! The problem: I need to set the JSON globally for ALL tinymce fields: Would it be possible to add an option to set the defaults.json file on a field level? This would be extremely helpful (necessary) for module development where one wants to ship fields with a custom set of options. It's also a lot easier to create fields where the settings are defined in code (GIT!) rather than via gui. Another benefit would be that the core (or a module) could ship different versions of defaults (eg minimal.json, simple.json, default.json) that a field could use and extend on them rather than on global defaults. Thx!1 point
-
I'm testing TinyMCE and it looks absolutely brilliant! I'll report my findings as they occur ? @ryan it seems you are still not on PHP8? Could you please have a look at DDEV for local development? Using DDEV you can simply switch PHP and DB versions and do "ddev restart". It's such a great tool, it has saved me so much time and headache since I installed it on my laptop one year ago! I've not had a single situation that ddev wasn't able to handle. Want to setup a new project? "ddev config" is all you need to do! You want to test something that sends emails? DDEV has mailhog on board and you can simply launch it via "ddev launch -m" You want to have local dev using HTTPS? ddev creates certificates for you! You want to create JPGs from PDFs on page save? You can add poppler-utils to your web-container config and have the same environment as on the remote server. You can even share your projects with clients using ngrok. You can share your project on the local network to test it on mobile devices. Want to import a db dump? You can import it simply by doing "ddev import-db -f site/assets/backups/database/db.sql".1 point
-
I'm coming in late to this discussion sorry. A huge thank you to @Christophe for bringing this thread to my attention. I had a strong need for the Schedule Pages module but was hesitant to use it on my PW 3.x site as the documentation was unclear whether it is compatible for 3.x. But the comments above from @3fingers, @teppo, and @Zeka seemed encouraging about the safety of using Schedule Pages on a 3.x site. So finally I decided to install it on one of my 3.x sites and I can attest it worked perfectly! Be aware that my test case is a simple one: my site GoodKidsClothes.com doesn't have anything unusual about it from a development perspective - it's a blog that has been going for several years and has a decent amount of content, but there's nothing complex. It displays articles I've written. Extra details about my experience installing and testing Schedule Pages are shown below. Firstly I do want to point out that the manual solution of clicking the publish button on the page on the correct day is technically do-able, but is not ideal in many situations, and certainly not in the situation where I would use it. On those occasions, which fortunately are not frequent, this has entailed me getting up at 3am to press the "Publish" button (explanation below). So yes, it's do-able, but not ideal. Here is the real-life use-case I'm talking about: a brand I am promoting wants my article to come out as early as possible on day x. This means timezone has an effect. "As early as possible on day x" for a U.S. brand really means 3:01 a.m. US Eastern Time (= 12:01am US Pacific time) on day x. I cannot just publish the minute it turns to the next day here on Eastern Time because that is still the day before on Pacific Time. For brands that have time-sensitive news and deals, I am not allowed to leak it the day before, even if I'm in another time zone than the leak. A breach in trust like that is serious and would result in the brand severing any relationship with my site. So it's not just the day, but also the time, that is critical here. I can attest that Schedule Pages works fine on all counts. When I installed the SchedulePages module, it did come up with a warning: However, I carried on with the install and it all went fine and the module worked perfectly. A huge thank you to all of those who posted above, and especially the people I mentioned personally in my comment here, as it inspired me to try the SchedulePages module. You've all literally saved me from a 3am wakeup next week for a post that needs to be scheduled ??? I'm sure all the other solutions people mentioned would have worked fine too, but I like to use modules to limit the amount of custom coding I need to add on my own. A couple of points to note about SchedulePages (besides what others have said): For first-time users, while the date picker is straightforward, the time entry part of it to schedule the post might be a little bit confusing. It certainly took me a few tries to work it out. The default time on the field says something like hh:24:11:ss , but basically you should just enter whatever 24-hour time you want like this: 14:34 (I didn't worry about adding seconds, and it just set seconds to zero). For others such as myself who have time-critical needs, SchedulePages seems to take it from timezone of the site (site/config.php ?), which is what you'd typically want, and not from the server time. I tested out the module using same-day and next-day scheduling. My server time is US Central Time, and my site is in US Eastern Time according to site/config.php. Based on setting my LazyCron to 5 min intervals and testing my schedule pages publication times, it looks like the time is being taken from my site time (US Eastern), which is exactly what I want, and not from my server time (US Central time).1 point
-
Hi, I just uploaded the first version of the SchedulePages module to Github: https://github.com/f...r/SchedulePages This plugin module allows you to schedule (un)publication of pages. I hope you guys will like it. //Jasper Usage: ====== Place the SchedulePages.module file into the site/modules folder and install the plugin from the admin area. Install/activate the LazyCron module (if you haven't already). This module is part of the Processwire core, but it isn't activated by default. Add the following date fields to your template: publish_from publish_until Note: the fields are already created during the installation of the module That't all. LazyCron will run take care of (un)publishing your pages that have a the publish dates set. It will run on every hour. Please note: LazyCron hooks are only executed during pageviews that are delivered by ProcessWire. They are not executed when using ProcessWire's API from other scripts. Edit: Changed the name of the module and function as Ryan suggested below. Edit 2: Updated instructions. Required fields are now automatically created and from now it runs every hour. Edit 3: Added module dependency. The updated module is on Github1 point
-
Hi @saschapi! I'm not aware of a module that enables this along with lazyCron but you could try placing something like this under site/ready.php $wire->addHook('LazyCron::everyDay', function($e){ $posts = $this->pages->find('status=unpublished, template=post'); foreach($posts as $post){ if($post->schedule_publish_date <= time()){ $post->of(false); $post->status([]); $post->save(); } } }); The page template you want to publish, would have a schedule_publish_date field, where you can set a publish date and time.1 point
-
Thanks @arjen that's a decent explanation but I'm still not 100% clear on this. I think it would be helpful if we could define what is meant by a user (or use different terminology to show what type of user they are). This confuses me a bit when people talk about 'users'. To me, there are different types of users (of the logged in to your site variety). For example, an admin could have superuser role, staff could have a 60% permissions client role (maybe excluding config/permissions sections or something), and members (i.e. people who are a member of your site, who can only change their email/password/avatar) with a member role. So in the above case, how would you handle something like this: 1) An admin may only need name, email, password. 2) Staff may have fields, email, phone, address, department, name, email, password. 3) A member may have avatar, email, social media profiles, name, email, password. Is it just a case of putting EVERY possible required field onto the user template, then users (I mean anyone who logs in) would just fill in the fields they require? Or did I just describe an edge case? I've seen situations on the forum which describe having users as part of the page tree. Would this be a normal way to do things if you had 100,000 members? Or would they all be listed in '/access/users/'? I've set up a local site in which I am going to experiment with user profiles to see if I can get this sorted in my head.1 point
-
You assign the fields where they need to be stored. For example: Save every field which should be connected to the user to the user template (for instance: an address field, since every user will have their own address) Go to Setup > Templates ... Filters > Show system templates. When you need to add logic to a role 99% of the time it makes sense to use permissions. For instance create permissions so show specific parts of the layout like a comment box for a specific type of user. I have seen rare edge cases where it would make sense to add other fields to a role. See permissions and user. Role are used to store permissions, but since they are pages you can assign any field which makes sense. See point 2 ProcessProfile is where the superuser defines which fields the user is allowed to change on their profile page (/processwire/profile/). ProcessUser is the process module for the users page (/processwire/access/users/).1 point