Leaderboard
Popular Content
Showing content with the highest reputation on 03/17/2022 in all areas
-
I think a better way is to skip the Add Page step and then make sure the title is always automatically derived from your two fields when they are populated. There are a few steps involved, illustrated here with case that is different to yours but you can see the similarity. In this example the template of the parent page that new pages are added under is named "creatures", and the child template (where the title is being set automatically) is named "creature". 1. For the "creatures" template, make sure that it allows a single template for children: the "creature" template. 2. For the "creatures" template, in the "Name format for children" setting enter "Y/m/d H:i:s". This will allow the "Add Page" step to be skipped and will automatically set the page name to the current date and time. We will later change the name in a hook. 3. Optional but recommended: for the "creature" template, choose the "creatures" template as "Allowed template(s) for parent". This lets you quickly add child pages via Pages > Add New and also ensures that new pages can't be added in the wrong place. 4. For the "creature" template, edit the Title field in the template context and set the visibility to "Open when populated + Closed when blank + Locked (not editable)". The title is going to be set automatically so editors should not be able to change it manually. 5. Add hooks like the ones below to /site/ready.php. // Pages::added $pages->addHookAfter('added', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); // Creature if($page->template == 'creature') { // This is a newly added page so the fields that make up the title won't be populated yet $page->setAndSave('title', 'New creature'); } }); // Pages::saveReady $pages->addHookAfter('saveReady', function(HookEvent $event) { /** @var Page $page */ $page = $event->arguments(0); /** @var Pages $pages */ $pages = $event->object; // Creature if($page->template == 'creature') { // Return early if the page is in the trash (thanks @taotoo) if($page->isTrash) return; // If the fields that make up the title are populated if($page->colour->id && $page->animal->id) { // Set the title $page->title = "{$page->colour->title} {$page->animal->title}"; // Sanitize the title as a page name $name = $event->wire()->sanitizer->pageName($page->title, true); // Set the page name while making sure it auto-increments if there is a sibling page with the same title $page->name = $pages->names()->uniquePageName($name, $page); } } }); Result:4 points
-
I do not think that a naming convention that fits all needs exits. Still, I mostly find useful using these "rules": "Thinking in reverse", something like French, where adjectives/describing words are usually placed after the noun: text_head, text_subhead, text_body When using date/time: it is yyyy_MM_dd-HH_mm_ss or similar what I use. The important thing here is the order, so when alphabetically listed we also get chronological order. I try to avoid sequential numbering (text_1, text_2, etc) as they are meaningless. Adjectives/describing words should be semantic, whereby a name of something indicates its intention, purpose or relation to other objects and not its properties which might change: text_h1 instead of text_bigred, for example When dealing with composit "objects/things" I often stick to the basic idea of BEM but I am not following it strictly. If lots of multiple of the same fields are needed for a template, I simply pick the most appropriate looking Pro field(s). I know this does not help those who do not have them, but if a project is big enough to warrant for such needs then the Pro fields are probably worth it, especially a DEV license is not that expensive at all, I think.3 points
-
Well please try the module and see if that works first. Then try a custom approach and see if it breaks. The reason why I created the modules is exactly to avoid hickups when copy/pasting things from this thread or placing things in the wrong spot... So that everybody has a quick test of SSE with a single click (install module) and can proceed from there.2 points
-
2 points
-
This might work (am not sure) but did you want to be more specific by using an ID? You probably know this already but wanted to point out that you can pass all those attrs in one go like this: <?php namespace ProcessWire; $field->attr([ 'hx-post' => $ajaxURL, 'hx-swap' => 'beforebegin', // etc... ]);2 points
-
This will never work. It should be a URL not a path ?. Either way, ProcessWire will block access to test.php. You have various options for this in the backend, e.g. point it to ProcessModule or a virtual URL that you handle using url hooks or to an Inputfield as shown below: <?php namespace ProcessWire; $adminEditURL = $this->wire('config')->urls->admin . "page/edit/"; $adminEdit = "{$adminEditURL}?id={$this->page->id}&field={$name}"; $out = "<a href='#' hx-get='{$adminEdit}'>"; Which will produce something like this: hx-get="/processwire/page/edit/?id=1234&field=name_of_inputfield"2 points
-
It's explained in this post: Try separating functions from declared variables. See how it is done in the core site-default profile: https://github.com/processwire/processwire/blob/d78276e2c265f6b70384a13eb4febd4811a1db77/site-default/templates/_init.php Put all your functions in a file that is pulled in with include_once. Declare your variables in _init.php.2 points
-
I think the best approach would be to use css ::first-line pseudo selector for that.2 points
-
Padloper 2 has received a number of updates, pushing it closer to a production release. Stripe Finished the Stripe payment gateway. It is based on the latest Stripe Payment Intents + Stripe Elements. The Stripe Elements widget is fully configurable (UI). I will be updating the docs about this. You can test this now in the demo site. Make sure to read 'about' first here. If upgrading, there are a number of simple steps (actually just one simple step). Just create a page titled Stripe in the admin under the payment gateways parent page. Currently, it is not possible to create a payment gateway using the GUI. Shipping Rate Selection If more than 1 shipping rates are matched, the checkout form will now present the customer with a form to select their preferred rate (e.g. express - €5, standard - €2, etc.). [I have just noticed a bug if using the inbuilt form with this; I'll fix asap]. You can test this by adding this product to the basket and selecting Kenya as the shipping country. Variants The demo site and the starter site have been updated to show how to handle products with variants - adding to basket, checkout, etc. You can test by adding this product or this Padloper [fake] product to the basket. Pay using Stripe and you'll even get to download Padloper! OK, file's fake, obviously. Reports View and functionality is now ready. Powered by htmx. Hoping to create a demo video of this and other backend views soon. Downloads This was not ready in the last release. it is now. Test with 'Padloper' product linked to above. If upgrading, you will need to install the related Fieldtype + add it to the download template. I'll write up about this separately. Bug Fixes Fixed a number of bugs. Docs I've updated the docs in some places. New Requirement I have added a new requirement for PHP BC Math Extension. Currently, Padloper will not work without this. Otherwise we have never-ending pennies/cents rounding errors. Whole libraries have been created just on this one issue; just Google it. BC Math solves it for us. Pending Manual Order Creation: this has been a difficult but getting close to finishing it up. Documentation: Especially the most pertinent. Some minor bug fixes. Some PayPal indempotency + rounding issues! If anyone knows how to pass amounts as pennies/cents to PayPal instead of whole currencies, please let me know. It used to work with the old API. I haven't been able to find how to do this in the latest API and checkout SDK. Production Release My plan is to release a stable version in March 2022. Beta testing has finished. Thank you all who've participated. Edit: making the demo site pretty and perform better on smaller screens is still on my todo. It's not urgent though. Thanks.1 point
-
This module for ProcessWire enables the debug mode to bypass the restriction to install modules. This is useful if you are tired to manually set the debug mode in the configuration. Note Please note that this module doesn't replace the real debug mode in the configuration file /site/config.php. With this module you will not receive any errors/notices/warnings like in the real debug mode. It serves only to bypass the restriction to install modules. Installation To install this module you have to enable the real debug mode. After installation you should deactivate debug mode again. To enable the real debug mode, download /site/config.php via FTP and open it in a text editor. Look for a line where you can find $config->debug = false; change it to $config->debug = true; save the file and upload it again. After module installation change it back to $config->debug = false;. For all future module installations, you just have to enable the debug mode in the module settings like described below. After module installation, you should deactivate it in the same way. Settings The settings for this module are located in the menu Modules=>Configure=>DebugModeSwitch. Enable or deactivate debug mode Set the checkmark (1) and click the submit button (2) will enable the debug mode (3). The debug mode can be also restricted for superusers only (4). Links ProcessWire module directory: https://processwire.com/modules/debug-mode-switch/ Github: https://github.com/techcnet/DebugModeSwitch1 point
-
I guess nobody wants to hear that, because it seems to be too nerdy to create fields via code, but this is just another example why I love my setup so much. Thank's for reminding me of those days where I was struggling myself with those topics ? For those interested in an advanced approach of organising PW projects and keeping your setup clean I'll try to explain what I do for all my projects now. And that's another benefit: I always do the same. On every project. For every field. So every project works the same and I instantly know what's going on even if I haven't worked on the project for a longer time. For me these two things were crucial: Custom Page Classes (optional) RockMigrations (optional) RockMatrix or RepeaterMatrix If you haven't used custom page classes be sure to check them out: https://processwire.com/blog/posts/pw-3.0.152/#new-ability-to-specify-custom-page-classes That would actually take too long to explain... But I've shown some of the above mentioned techniques that might also be of interest for readers of this topic in the linked issue (https://github.com/processwire/processwire-requests/issues/154) The sort version which might be an idea for you guys having troubles with field names: You could create a custom class that is loaded in _init.php where you define your fieldnames as class constants: <?php // site/_init.php class MyProject { const field_body = 'body'; const field_teaser = 'body1'; const field_summary = 'body1'; const field_cover = 'blog_cover_image'; } Now you can access your fields in your templates like this: <?php // template newsitem echo "<h1>{$page->title}</h1>"; echo "<div>".$page->get(MyProject::field_teaser)."</div>"; <?php // template basic-page echo "<h1>{$page->title}</h1>"; echo "<div>".$page->get(MyProject::field_summary)."</div>"; Note that we are reusing the field "body1" and referring to it as "field_teaser" in newsitem and as "field_summary" in basic-page. Personally I don't do any reusing of fields any more but that's a different topic and relates to RockMatrix + RockMigrations. Hope the ideas where useful for someone nonetheless.1 point
-
I don't think that will work because the page will also be saved immediately after it is created and so the hook would just delete it before it can be edited. I suggest you just clean up abandoned pages on a regular shedule using LazyCron. First install the module at Modules > Install > LazyCron. Then add a hook like this to /site/ready.php: // Once per day $wire->addHook('LazyCron::everyDay', function(HookEvent $event) { // Find pages that appear to be abandoned because they still have the default title 24 hours after creation $time = strtotime('-24 hours'); $abandoned_pages = $event->wire()->pages->find("template=your_template, title='New Owner', created>$time, include=all"); // Trash the abandoned pages foreach($abandoned_pages as $abandoned_page) { $abandoned_page->trash(); } }); You could delete the pages if you like but maybe safer to trash them and then just empty the trash once in a while.1 point
-
Thanks for making me aware of something that I've done wrong for about 20 years ?1 point
-
I'm surprised you have so many template variables to declare. You might like to take a look at Markup Regions because that should greatly reduce the number of variables you need to hold markup. Does the below work? (P.S. parentheses are redundant for include, include_once, etc because they are expressions rather than functions) include_once './_func.php'; include './_header.php'; include './_sidebar.php'; include './_footer.php'; include './_buttons.php';1 point
-
Ok now we are talking about a totally different topic... But first things first. This is exactly what I'm using SSE for. The user clicks a button, ProcessWire starts doing a long running task (for example trashing lots of pages) and while it does so, the progress is sent to the client so that the client knows what's going on. I'd call that real world ? The reason why I chose SSE over sockets and over not implementing any client feedback is obvious: Having a long running task without a progress bar is just not an option. What if the user trashed several hundreds of pages and didn't know if that takes 5, 10 maybe 120 seconds? Other techniques are much more complicated to setup (for example web sockets). SSE is built in and does just what I needed: Inform the user of the progress of the task without polling. Of course while this task is running the system is blocked for all other requests. As far as I understand that's the nature of how PHP works. We have the same limitation everywhere in PW and everything in PHP... For example if you empty the trash with lots of pages and you try to visit the PW backend in another browser tab you'll also be blocked until the first tab has finished it's job - or am I wrong here? PHP is single threaded so if you wanted to come around this you'd have to do additional things. I've no experience in this territory, but this seems to look like it could be worth a try: https://stackoverflow.com/a/4350418 There's also https://www.php.net/Thread but that is based on a PECL. And so is https://openswoole.com/ which looks like it comes closer to what you are trying to achieve than what is possible with SSE as far as I understand. 1. Of course we are! Why shouldn't we?? The module is just here to have a common foundation to test things out and eliminate confusion about who copied which code snippet to whatever place etc.; You could now test the linked popen() technique and just add that to the module as a PR and everybody could understand and learn. 2+3. We'd need to have a real non-blocking background process for that. But as I said that not a matter of SSE that's a matter of multi threading in PHP. https://www.youtube.com/watch?v=spDpR2qr-Fs&ab_channel=Dr.RobertDimpsey So for my use case SSE seem to be a good option. For updating a website's content based on "real time data" polling might still be the better option as it will not block the user.1 point
-
I use generic words and numbers for field names, e.g. text_1, textarea_1. I really wish I didn't have to do this and could use descriptive names for fields, but the problem is that I almost always want to reuse fields for different purposes on different templates. So while a name like "city" is more meaningful than "text_1", I think it's much more confusing to call $page->city in some template when that field is actually holding a person's job title or something totally unrelated to "city". What I'd like is for PW to support field aliases, so that in the context of the "store" template I can give text_1 the alias of "city" and in the "employee" template I can give text_1 the alias of "job_title". Field aliases would need to be unique and in practice you could refer to a field by any of its aliases in any place in your code. I have an open request for this: https://github.com/processwire/processwire-requests/issues/154 Ryan seemed supportive at the time but it hasn't progressed anywhere since 2018. If anyone else would like this feature please "vote" for it with a thumbs-up at GitHub. I've also created a module that would allow aliases to be used but it can't be released due to issues with FileCompiler: https://github.com/processwire/processwire-issues/issues/8821 point
-
Not foolproof https://stackoverflow.com/questions/56301138/how-to-check-whether-server-supports-http-2-in-javascript-on-browser1 point
-
Here's the demo video showing the system lock. Let me know if you cannot watch it. Note, the system will lock even if the count is 10.1 point
-
For larger sites I mostly use generic, numbered fieldnames like text_ml_01 (ml for multilanguage) which I might generate via API. Then in the templates I change the labels to something more meaningful and via AutoTemplateStubs I copy the complete field info with labels into the php templates, looks sth. like: /** * Template: basic-page (Basic) * * @property string $title Titel * @property string $text_ml_01 Headline * @property string $textarea_ml_01 Intro * @property string $body_01 Content * @property string $text_ml_02 CTA Button Label * @property mixed $url_ml_01 CTA Button URL * @property Pagefiles $files_ml_01 Linked Files */ For smaller sites I prefer more custom fieldnames.1 point
-
1 point
-
Just a get param and an onchange triggered reload - it's only to filter to a specific organization so no need for anything fancier for now.1 point
-
I'd love to hear how you accomplished the filtering part — I'm assuming you've built a panel emitting custom events that trigger panel reloads. Or is it plain old get params?1 point
-
I wrote something about that a while back. Not much has changed since then. Yet I still sometimes find myself in this question loop about naming fields, templates and such.1 point
-
Perfect - thank you. Just in case anyone is interested, the panel above the tabs is a dropdown select for filtering the results of the data shown in all the other tabs / panels, so this works really nicely now.1 point
-
Hi @d'Hinnisdaël - I am really loving the new tab option, but I am looking for a way to add a panel above the tabs so that it is available no matter which tab the user is on. If I add the panel directly to $panels, it always appears at the bottom of the page below the tabs. Any ideas how I can make this work? Thanks so much!1 point
-
https://github.com/baumrock/RockSSE-demo Would be great if many of you could test this on your setups and let me know if it works as expected! In production I have a long running task like trashing lots of pages. The script will finish when all pages have been trashed.1 point
-
Padloper 2 documentation can be found here. This is WIP but has the very least to get your started. It is a bit rough around the edges. We'll improve it as we go along. At the very least, I suggest you read these sections: Getting Started API, especially the finder, cart & checkout and session order chapters. Frontend. With respect to the API, the most important thing to know about is the $padloper global variable. It is your gateway to nearly everything (finding things, carts, checkouts, orders, etc.) in Padloper (2). Please do let me know if you find any errors. I am also working on the starter (demo) site repo. This and the docs should hopefully help move you along. If I get a minute, I might throw in a quick demo video. No promises though ?. Happy reading ?.1 point
-
Hi all, Hope that there is a quick tip that someone already know... Is it possible to search in multilanguage fields only in the current language values without to search in the default language as fallback? See the quote below. In other words.. I would like to search only in the current language (Dutch), no matter if some of the Dutch language values are empty. Is it possible? Thanks1 point
-
Hi @Torsten Baldes, you could try the following: wire('user')->setTrackChanges(Wire::trackChangesOn | Wire::trackChangesValues); wire()->addHookAfter('Pages::save', function($event) { // >>> ON PAGE SAVE $page = $event->arguments(0); if($page->template->name === 'user') { // >>> APPLY ONLY TO USER TEMPLATE $changes = user()->getChanges(true); // output changes as log entry wire('log')->save('testchangelog', print_r($changes, true) ); $m = new WireMail(); $m->from('Your email From'); $m->to('Your email To'); $m->subject('Your email subject'); $m->body('Your email text'); $m->send(); } }); Note: made a couple of corrections and changed to WireMail as per @horst suggestion. Still testing if changes are recorded...1 point
-
@thetuningspoon I think you are on target here. There's a lot to be said for the InnoDB engine, and the row level locking vs table level should reduce contention and decrease latency with it. Redis, despite being single threaded, is writing to an in-memory key value store - so it's blindingly fast. I would be interested in seeing your updated code for the Redis session handler - if that's what you mean, as I need to update that module.1 point
-
I don't think it would resolve the issue. SHDB just saves to DB instead of the file-system. But PHP will still do one session request after another and probably uses db table locks instead of file locks (at least that's my guess). Are you using PW session functions or native PHP? Towards the bottom of this article there is PHP 7 option: session_start([ 'read_and_close' => true, ]); https://ma.ttias.be/php-session-locking-prevent-sessions-blocking-in-requests/ The author also mentions Redis (there's also a redis session handler db module for PW), but if you're not using it it won't be of much use...1 point