Leaderboard
Popular Content
Showing content with the highest reputation on 09/17/2023 in all areas
-
If you are concerned with file size like that then you can use CDN (https://unpoly.com/install/cdn) conditionally: load local files when CDN is not available. Unpoly also have advanced caching, so by using that properly your site can behave more like an application then a website by providing (almost) instant responses. (As a related side-note, I also agree with this certain forum user on this forum: https://forum.bootstrapstudio.io/t/bootstrap-css-and-cleanup/10578/2?u=szabesz) As for my own experiences, I have not yet implement the conditional usage of CDN but the e-commerce site I developed using Unpoly for its frontend JS magic is loved by customers, partially because of the easy to use user interface I crafted for them, and partly because of the speed of the site, even though it loads full Bootstrap 5, full jQuery and also Unpoly (plus my CSS and JS, of course). Sure, browser and Unpoly caching helps a lot! About half of the users use their mobile phones to place orders and they are equally satisfied. I just cannot showcase the site because currently it is for contracted customers only. There are plans to open it up for the average retail customers as well (on a different domain) so when that is in production, I will probably provide this forum with my very first showcase. (In 1 or 2 years... as I have loads of other projects to finish before I can start working on that.)3 points
-
This week I've been finishing updates for many of the Pro modules with new versions posted today for the following modules: FormBuilder (v55) ProCache (4.0.5) ProMailer (v13) ProDrafts (v10) ProDevTools Form Auto Saver and Reminder, also posted in FormBuilder (v3) ProDevTools Page Auto Saver and Live Preview (v8) ProFields Combo (v12) ProFields RepeaterMatrix (v11) ProFields Table (v25) ProFields Verified URL (v6) ProFields Textareas (v10) ProFields Multiplier (v15) These new versions don't necessarily contain new features, with a few exceptions. But they do contain maintenance updates for PHP 8.2+ and jQuery 3.6+ where needed. They also contain various small fixes, improvements or documentation adjustments. Pro modules not mentioned above will also receive updates in the coming week (or weeks). I thoroughly tested all of these modules with ProcessWire 3.0.227 before posting. But all of these versions are posted as "dev" or "development" versions. What does that mean? It means that that at the time it was uploaded, I was the only one using it so far, and thus they've only been tested thoroughly by me, today at least. The term "dev" doesn't mean that the version isn't stable. In fact, often times the dev version may be more stable than the last posted non-dev version. (Kind of like how the core dev branch is often more stable than the master branch). The dev designation just means that I can't claim it to be the most stable version until it's been out for a little while longer, with more people testing it. If you see a dev version posted that has been out for several weeks, then you can usually consider that the current stable version. The exception would be if it also says "beta", or something else to indicate it's a testing version. Early this week the core master/main branch was also updated to version 3.0.227. This version contains fixes for bugs reported since 3.0.226 master/main was released. A 3.0.228 bump is also in the works for the core master/main branch. I'll likely be working on Pro module updates for another 1-2 weeks here, along with issue fixes to the core. As a result, the 3.0.228 version will likely be merged to the master/main branch in the next couple weeks as well. I figure we might as well keep updating the main/master branch with small fixes and such until we get into more major dev branch updates. Thanks for reading and have a great weekend!2 points
-
You all are such professional designers that I hesitate sharing my site here, but it might show what Processwire can do even for 'average' users. I created this site with Processwire for the County of Ventura's Assessor's Office. It is a redo of the previous site done in ASP that was showing it's age. The goal was to provide a more modern design that would work with desktop or mobile while at the same time providing more features for the taxpayers to access data and communicate with us. While most of the County Government sites use WordPress (or similar) they graciously allowed me to give Processwire a try. I think it performs admirably, is easy to maintain, very fast, and actually fun to work with (most of the time....?). http://assessor.countyofventura.org Most of the site is handled by two main templates, one for the summary pages, and one for the detail pages. I also created a 'dummy' template to act as a folder to hold the pages for each category (to make a manageable hierarchy) . This made it easier for me to find things on the back end and mimics the front end nicely. On the back end there are several templates that hold things like forms (pdf downloads), links, glossary terms, frequently asked questions, form responses, and more. All of these are dynamically included into the front facing pages based on their content and how they relate to the individual pages. Fillable forms were the hardest part for me. I tried working with some of the free modules for this sort of thing but I could never wrap my head around them. In the end, I just did it by hand with standard PHP forms combined with using the Processwire API to save the results to the database. It works fairly well but I'm sure there is a better way. A big thank you to everyone on this forum for their help and tips both directly and indirectly, and to Ryan who makes this fabulous software available to us. Any suggestions on the site are welcome.1 point
-
I think that as long as the field keeps the Hanna code text formatter, you shouldn't have any issues. About Hannah code insertion in the field, take a look at this: https://github.com/BitPoet/InlineCompleteTinyMCE1 point
-
Just for thoose who also need a hook to make the title non-editable. This line: <?php // check if the page has the desired template if ($page->template != 'your-template') return; Must be: <?php // check if the page has the desired template if ($page->template->name != 'your-template') return; So the whole hook is: <?php // hook to make the title field non-editable $wire->addHookAfter("ProcessPageEdit::buildFormContent", function ($event) { // get the page being edited $page = $event->process->getPage(); // check if the page has the desired template if ($page->template->name != 'your-template') return; // check if the user has the desired role if (!$this->wire->user->hasRole('admin')) return; // get the form that was built in buildFormContent() method $form = $event->return; // make the title field non-editable $f = $form->get('title'); $f->collapsed = Inputfield::collapsedNoLocked; }); Thank you very much for your help, @bernhard ?1 point
-
1 point
-
1 point
-
That's why Softaculous announced a new version in their installer. Until this moment I thought they'd support the DEV versions now and was totally thrilled... but ok. I'm totally for it. That signals ProcessWire is alive and well (see the Softaculous post above) and people can see it. To be honest here: we all should push way more details about your and the overall work on and the features of ProcessWire to the outside world. But that's another topic for another day. Have a great weekend, @ryan!1 point
-
Nice site, congrats! Tip for everyone outside the US: Try visiting with the Tor browser. I could access it without problems from Switzerland. re: forms I can highly recommend the Pro module FormBuilder from Ryan. Well worth the money.1 point
-
@OllieM Not long at all. Following the steps above (which is basically just doing the smart thing and backup up old files) it took me a couple of minutes at most.1 point
-
@zota Hi, our little conversation hit a zone in my old brain and i ended creating a little plugin that may be useful for your need https://github.com/virtualgadjo/pw-tinymce-div-plugin just in case ? have a nice day1 point
-
unpoly is good! I used it in some of my project and I really love it. The tailwindcss standalone CLI is another wonderful tool, too. Gideon1 point
-
Hi, What's it all about I'd like to share some thoughts and approaches i took to meet the customers requirements when i built the website. Maybe someone has (or will have) similiar needs and can benefit from it, hopefully. I will focus mostly on technical stuff. And because of that i am not sure, if the showcase section is the place to post it (?). Its more like a testimonial. About the organisation/website https://vdp-ev.de (german language only) The Verband Deutscher Puppentheater e.V. (VDP) is the cultural policy respresentation for professional puppet stages in Germany. The VDP gives advice, shares knowledge and represents currently 140 member stages. They publish a magazine frequently, giving awards, workshops and organize events for their members. As the VDP was founded many years ago, they have lots and lots of contents, each with individual structural needs . So the first goal was to pack the vast of content in a good structure and make sure visitors has access to it as straight as possible. Therefor the grafical presentation is rather plain, not really stand out or comes with fancy stuff ?. Some random screens of the public website: Some random screens of the (secured) members marketplace (explanation s. below): Seeing no way to set skip links, here is a short plain TOC: 1. Building a marketplace for VDP members 1.1 Requirements and conceptual thoughts 1.2 Building the menu 1.3 Keep it maintainable 2. Publish selected members content on the public website 2.1 Clients request 2.2 Starting, first approach 2.3 Solution 1. Building a marketplace for VDP members 1.1 Requirements and conceptual thoughts Before the relaunch, members (they have a special user role) yet could login into the backend and edit their contents (data for their stage + add/edit productions). With help of @adrians AdminRestrictBranch they only see their own stage and productions. Those users have no access to other menu trees. With the relaunch the VDP wants to have something different/more elaborated: A secured member area (e.g. marketplace) where all members can share and swap ideas, informations, leading discussion related to their profession, offer or search for profession related material (like puppets, technical gear, services etc.) and some more. Just like some kind of a simple forum (with maintaining their own entries, s. below), but without the overhead of a standalone forum software. There was a (only grafical) approach how to do this by the former developer. His idea was to establish a secured member frontend where the loggedin user have (frontend) presentations to manage their own marketplace content, their stage and productions and even their profile a least. Well, some kind of reinventing the backend... Beside the fixed budged, i thought of a better way to do this. First, i wanted to seperate the marketplace output from the input strictly. Without real advantage member users shouldn't be forced to learn something they're already familiar with (Backend login and add/edit their stage and productions). Second, all marketplace content should live within the PW ecosystem, e.g. are template base pages that lives in the page tree. At least for administrators to see/edit... (s. below also). So, where to establish the CRUD actions for the members content of the marketplace section for each member user (with that special user role)? It all leads to adapt the PW Backend Menu. The Module CustomAdminMenus by @Robin S seems to give a good start for this. The setup for static pages is rather simple. But for my use case i had to deal with a much more dynamic approach. Luckily the module is hookable... I wanted to have two Menus: Mein Markplatz which displays all CRUD actions for the sections (Figuren, Bühne, Material, Tipps & Tricks a.s.o., s. image above) and Zum Markplatz Portal which links to the members marketplace overview page. 1.2 Building the menu First we get the current user content, populate the dynamic menu and build two menus at least. /** * Build Marketplace Admin Menu * * Backend interface for vdp members to add/edit pages marketplace * sections. * * Each member only will see entries that they created. */ $wire->addHookAfter('CustomAdminMenus::getMenuChildren', function(HookEvent $event) { // The menu number is the first argument $menu_number = $event->arguments(0); // Handle Menu 1 if($menu_number === 1) { // Get the current user $user = $event->wire()->user; // Hide admin menu except for vdp members if ($user->isSuperuser() || !$user->hasRole('theater')) { // Do not show the menu $event->return = false; } else { // init $hints_children = []; $offers_children = []; $blog_children = []; $discussions_children = []; // Get all hints for current user $hints = $event->wire()->pages->findRaw("template=members-marketplace-hint, created_users_id=$user.id", ['title', 'url', 'id']); // Allow to add a new hint // Adapt values to fit your environment $hints_children = [ [ 'icon' => 'plus-circle', 'label' => 'Neuen Eintrag anlegen', 'url' => $event->wire()->config->urls->root.'vdpadm/page/add/?parent_id=4232', 'newtab' => false, ] ]; // Build from results // Adapt values to fit your environment foreach($hints as $hint) { $hints_children[] = [ 'icon' => 'file-text-o', 'label' => $hint['title'], 'url' => $event->wire()->config->urls->root.'vdpadm/page/edit/?id='.$hint['id'], 'newtab' => false, ]; } // ... repeat for other marketplace sections ... // Build the menu $menu1 = [ [ 'icon' => 'thumbs-up', 'label' => 'Tipps und Tricks', 'url' => '', 'newtab' => false, 'children' => $hints_children, ] // ... repeat for other marketplace sections ..., don't forget the `,` ;-) ]; // Return the menu $event->return = $menu1; } } // Handle Menu 2 (Link to marketplace portal) if($menu_number === 2) { // Get the current user $user = $event->wire()->user; // Hide admin menu except for vdp members if ($user->isSuperuser() || !$user->hasRole('theater')) { // Do not show the menu $event->return = false; } else { $menu2 = []; // Return the menu $event->return = $menu2; } } }); FYI: Code is part of a ready.php file which lives in /site (s. also https://processwire.com/docs/modules/hooks/) After that the PW top header looks like this: If you click on Mein Markplatz, you get the verbose list*. *) The member user for the demo has no existing entries, so you see none (only the link to add a new entry). 1.3 Keep it maintainable As an administrator i must be able to identify which entry is related to which member. So i prepend the user name to pages names programmatically. This is done by a little helper hook. All relevant templates has a hidden field named `creator`, which gets populated with the user name on page save. To avoid overriding the value when a adminstrator edits an entry, its packed in a condition. Very important, because otherwise the assignment (entry <> member) gets lost! All entries edited by a administrator would have a new owner ?. Definitely not what we want... Btw. the user role `theater` in this example represents the special role for members mentioned above. /** * Utility hook for `Build Marketplace Admin Menu` * * Field `creator` is a hidden page field, that is populated * on page save with the username of the created user. Only related * to members marketplace pages. * * Prevent superuser to change `created user` while edit/save * the page for administration purposes. * * We need this hook on page save, because we want to show * the username within the admin page sidebar list ($page * only provide the ID of the created user). */ if (!$user->isSuperuser() && $user->hasRole('theater')) { $wire->addHookBefore('Pages::saved', function($event){ $page = $event->arguments(0); if($page->hasField("creator")) { // Get the current user $user = $event->wire()->user; // Populate template field for use in the admin sidebar list $page->creator = $user->name; // Save back to $page $page->save('creator'); } }); } FYI: Code is part of a ready.php file which lives in /site (s. also https://processwire.com/docs/modules/hooks/) The complete ready.php vdp-marketplace-demo-ready.php So this is it, mainly. As there are two ways to go after a successful login (Backend view to edit/add content or Frontend view of the members marketplace overview page) the members must decide where they want to go first. Btw, after the user is logged in, the navigation changes within the member frontend scope. So the user can switch between frontend and backend view each with one single click. 2. Publish selected members content on the public website 2.1 Clients request After the relaunch was online, the customer had another request: They wanted to let members decide if their entries (of particular sections of the member marketplace) should also be integrated/viewable on the public website. Visually identical to the views within the member marketplace. Those (public) pages should be available in the navigation and also be indexable by search engines. While this seems not quite a too difficult task at first glance, it turns out to be a bit more tricky. The reason are the restrictions of page paths when dealing with the (secured)members and public scope. Note: All sections in the members marketplace are applied as blog pages, e.g. each has a parent page and associated children. 2.2 Starting, first approach First, i add a conditional checkbox to all related marketplace templates, which was needed in any case. But than it gets a bit annoying. Having kind of a (public) placeholder template (and page based on it) and then iterating over the member blog entries was a dead end. The `children->url` path of course leads to the member section (at that time i wrote a post about this because i hoped this could be solved somehow) As i have to have a real template/page(s) for this (s. 2.1 why), it isn't possible to hook paths here. I realized, i had to find a complete other approach... 2.3 Solution Finally i set up clones for all relevant members section templates (e.g. parent + child template), built public available pages from it and mirror allowed* member entries to the appropriate public pages on a regular base. To avoid disruption, those public pages are readonly for editors. *) Entries with a particular option set (e.g. Beitrag auch auf der öffentlichen VDP Website anzeigen?, s. picture above) The synchronisation between the members area and the public clones is done by cronjobs for each section. Example sync file for one section (VDP Blog): <?php namespace ProcessWire; /** * Synchronize members < > public blog pages * * This file is meant to get executed by a cronjob * * 1. Synchronize (add, update, delete) * 2. Synchronize (delete) * 3. Log, Mail */ // bootstrap processwire, adapt to your path include("../index.php"); // init $d = array(); $o = array(); $totalcountUpdate = ''; $totalcountNew = ''; $totalcountDeleted = ''; // Get member blog items $members_marketplace_blog_items = $pages->find('template=members-marketplace-blog-item'); // Iterate over member blog items, save `name` foreach($members_marketplace_blog_items as $item) { $d[] = $item->name; } reset($d); /** * 1. Synchronize (add, update, delete) * * Perfom synchronisation based on existing member blog items */ // Iterate over members blog items for ($i=0; $i < count($d); $i++ ) { // Get member blog item by given name from the `d` array. $members_blog_item = $pages->findOne("template=members-marketplace-blog-item, name=$d[$i]"); // Get the related public clone (if exists) $public_blog_item = $pages->findOne("template=blog-vdp-item, name=$members_blog_item->name"); /** * Conditional actions * * 1. if * Update present page * * Verbose: Is yet present in public section && is * allowed to be displayed * * 2. elseif * Add new page * * Verbose: Is not present in public section && is * allowed to be displayed * * 3. elseif * Delete page * * Verbose: Is yet present in public section && is * not allowed to be displayed */ if ($public_blog_item->name == $members_blog_item->name && $members_blog_item->options_members_marketplace_entry_publish_to_public == 1) { $public_blog_item->title = $members_blog_item->title; $public_blog_item->name = $members_blog_item->name; $public_blog_item->headline = $members_blog_item->headline; $public_blog_item->blog_date = $members_blog_item->blog_date; $public_blog_item->page_blog_tags_vdp_blog = $members_blog_item->page_blog_tags_vdp_blog; $public_blog_item->body = $members_blog_item->body; // Save page to get an ID for adding images, s.below $public_blog_item->save(); // Make sure we process an array $public_blog_item->of(false); // Delete images first to avoid duplication $public_blog_item->images_members_marketplace_entry->deleteAll(); // Add images foreach ($members_blog_item->images_members_marketplace_entry as $img) { $public_blog_item->images_members_marketplace_entry->add($img); } // Save page again (just for the sake of it) $public_blog_item->save(); // Save iteration for mail, s. below $totalcountUpdate = $i; } elseif ($public_blog_item->name != $members_blog_item->name && $members_blog_item->options_members_marketplace_entry_publish_to_public == 1) { // Add new page $public_blog_item_add = new Page(); $public_blog_item_add->template = 'blog-vdp-item'; $public_blog_item_add->parent = '/wissenswertes-ueber-puppentheater/vdp-blog/'; $public_blog_item_add->title = $members_blog_item->title; $public_blog_item_add->name = $members_blog_item->name; $public_blog_item_add->headline = $members_blog_item->headline; $public_blog_item_add->blog_date = $members_blog_item->blog_date; $public_blog_item_add->page_blog_tags_vdp_blog = $members_blog_item->page_blog_tags_vdp_blog; $public_blog_item_add->body = $members_blog_item->body; // Save page to get an ID for adding images, s.below $public_blog_item_add->save(); // Make sure we process an array $public_blog_item_add->of(false); // Add images foreach ($members_blog_item->images_members_marketplace_entry as $img) { $public_blog_item_add->images_members_marketplace_entry->add($img); } // Save page again (just for the sake of it) $public_blog_item_add->save(); // Save itereation for mail, s. below $totalcountNew = $i; } elseif ($public_blog_item->name == $members_blog_item->name && $members_blog_item->options_members_marketplace_entry_publish_to_public == 0) { // Delete page $public_blog_item->delete(); } } /** * 2. Synchronize (delete) * * Delete outdated public blog item pages, e.g. do not * exists in the member section any longer. */ // Get all member blog items $_members_marketplace_blog_items = $pages->find('template=members-marketplace-blog-item'); // Iterate over member blog items, save `name` foreach($_members_marketplace_blog_items as $_member_item) { $o[] = $_member_item->name; } reset($o); // Get all public blog items $_public_blog_items = $pages->find("template=blog-vdp-item"); // Delete public blog item if not found in members array. foreach ($_public_blog_items as $_public_blog_item) { if(!in_array($_public_blog_item->name, $o)) { $_public_blog_item->delete(); $totalcountDeleted++; } } /** * 2. Log, Mail (delete) * * Log results in PW and send status mail */ // $log->save("cron", "Update public blog posts - New: $totalcountNew, Updated: $totalcountUpdate, Deleted: $totalcountDeleted"); // $emailTo = '<your-email-address>'; // $emailFrom = '<your-email-address>'; // $emailSubject = "VDP Blog | Cron | balance public to member sections "; // $header = ''; // $header .= "From: ".$emailFrom. "\r\n"; // $header .= "X-Mailer: PHP/" . phpversion(); // $message = ''; // $message .= "Am: ".date('d.m.Y H:i')."\n"; // $message .= "Aktualisierte Blog Beiträge: ".$totalcountUpdate."\n"; // $message .= "Hinzugefügte Blog Beiträge: ".$totalcountNew."\n"; // $message .= "Gelöschte Blog Beiträge: ".$totalcountDeleted."\n"; // mail($emailTo, $emailSubject, $message, $header); die(); ?> FYI: This example codefile can live anywhere, just adapt the path where your PW instance is located Example cronjob sync file: vdp-cronjob-sync-blog.php.zip Have fun ?1 point
-
Thank you, that worked flawlessly! I was a bit scared of manually updating 4 production sites this way, but I managed to complete the task without any real issues.1 point