Leaderboard
Popular Content
Showing content with the highest reputation on 04/03/2023 in all areas
-
2 points
-
Two great news!! 1) The module directory now reads module version numbers from package.json files!! Now when using automated workflows like shown above your module's version in the modules directory will automatically be in sync with your module ? 2) Microsoft has just released the github actions extension for VSCode that helps developing and debugging github actions directly from within your IDE!! https://marketplace.visualstudio.com/items?itemName=GitHub.vscode-github-actions2 points
-
I think this is more of a "Pete doesn't understand Alpine yet" issue but wondering if someone can help. I've got a Buy Now button on a product grid that renders a modal via HTMX. I'm using Padloper demo data code (modded slightly) to display the price/options markup. For a product without variations I can get that to work. But for a product with variations, because the modal content being loaded via HTMX contains alpine x-init that is being added to the DOM after the original page has loaded, the Alpine code won't work so the popup looks like this (it should say "Select an option") then if you click on an option it says this: Then funnily enough if you close the modal and open it again (or click a "Buy Now" button for another product with variations) it seems to work: Also simply closing the modal and clicking Buy Now on the same product, the modal now works too. The code returned via the HTMX request that loads the modal looks like this, so I suspect it's that initVariants() code that just needs to be changed to not be x-init? Or something else needs re-triggering somewhere along the line - I'm not sure. <div id='padloper_add_single_product' hx-trigger="padloperfetchupdatedcart delay:500ms" hx-post="/?action=update-cart" hx-target="#padloper_side_cart" hx-vals='{"is_single_product_add": 1, {padloper_cart_update_product_quantity: 2, act: "update-cart"}'> <div <?php echo ($isProductWithVariants) ? " x-init='initVariants()'" : '' ?>> <?php if ($isProductWithVariants) { echo renderProductVariants($product); } echo renderPriceAndAddToCart($product); $cart = $padloper->cart; $numberOfTitles = $cart->getNumberOfTitles(); $totalAmount = $cart->getTotalAmount(); $totalQuantity = $cart->getQuantity(); ?> <div id='cart-summary' class='hidden'> <span>Products: <span id='numberOfTitles'><?php echo $numberOfTitles ?></span></span> <span>Quantity: <span id='totalQty'><?php echo $totalQuantity ?></span></span> <span>Price: <span id='totalAmount'><?php echo $totalAmount ?></span></span> </div> <div id='cartnotice'></div> </div> </div> initVariants is part of the Padloper Demo Data so lives inside this code: Alpine.data("Padloper2DemoData", () => ({ ... I'm having a lot of fun learning Alpine and HTMX but really having trouble wrapping my head around this and don't want to rebuild it all in jQuery at this stage so any help would be greatly appreciated!1 point
-
Hey guys, I'm indeed starting further development on this module in the next days! It needs a lot of work to be done. The main part will be the transition to Snipcart 3.0 engine + a robust EU VAT tax integration. As usual I'll report the progress to this thread. Please stay tuned! Greetings, Martin1 point
-
Hear, hear! For htmx, BugBytes has some neat htmx stuff. Although backend is Django, theory is the same. Most (at least it used to be that way) htmx stuff out there is related to Python stuff. BugBytes also has some Alpine.js tuts. Perhaps my favourite tutor of them all, Brad at Traversy Media has this Alpine.js crash course too.1 point
-
This is my problem - I've just been happily using jQuery since v1 really even though there are much more lightweight tools available now for some of the easier bits and I've never learned Vue etc. I do like HTMX because it makes it easier to see what's happening when you're dealing with simple AJAX requests - what it's firing off, where and so on all written up within the element that it relates to, whereas on a large CRM I've built over the last 6 years it's hard keeping track of everything - scrolling up and down big JS files to find what I've done years ago sometimes. It's not hard finding $(document).on('click', '#elementid'... references really, but seems neater being able to just see it inline in the source code in terms of what's being triggered. Yes even a generic demo would be good, and I hear you on the list of things you intend to do - I've got about 10 years' worth I've not got round to at this point ? although after a long while if theyre still not done then maybe they're no that important?1 point
-
I suppose I find them quite easy to grasp because I found htmx and Alpine after I'd been using Vue, Nuxt, etc. Have you seen the htmx demos? I have been thinking about a series of tuts on htmx + alpine + tailwind for ProcessWire. But then again, I have been thinking about a lot of things for years ?. I forgot to mention that sometimes some alpine stuff don't work because they are out of scope. Inner/nested x-data takes precedence over outer ones, for instance. I'll try put something simple together. Even something generic (not Padloper related) I suppose would do. This would cover events; bounce; waiting; doing things after other events; toggling state, oob, etc.1 point
-
Hi @Pete, Hard to tell without seeing all the relevant bits. Here's a few thoughts. As an aside, I am wondering why you need to use HTMX to render the modal. From what I can see, you already have the product title and price in the product card in the products grid with the buy now buttons. Unless prices change constantly (like stocks), which I don't think they do in your case, the only thing that htmx should be doing in the modal is to listen to the 'add to basket' and optionally, to the increase/decrease in basket. After that, it renders the response (success or fail to add to basket, i.e. the greenish text). Otherwise, I'd have Alpine JS open and close the modal and optionally render the modal markup. If Alpine JS is not rendering the markup, it would mean modal markup for each product is already done but hidden and their visibility controlled by Alpine, e.g. :class. Either way, I don't see why htmx should be rendering the modal. It also leads to extra hits on the server that you probably don't need. I don't think it has to do with x-init. Think of x-init like ProcessWire _init or Process modules init(). It allows you to hook into the lifecycle and do stuff before the DOM is updated. I could be wrong about this with respect to your use case though. This and... this...suggest it could be a race condition. Again, without seeing the modded code, it is hard to tell. There are various options including: use $nextTick (but not sure it applies to this case). Have alpine listen to a custom event, i.e. @mycustomevent='handleCustomEvent()'. You can send a custom event after htmx swap, settle, etc. Use htmx on load event to talk to Alpine. 'on load' is called every time an element is loaded to the DOM Great! Not at any stage please! ?. Just because of this, I can try put together a simple demo for you. But first, clarify why you need htmx to render (instead of just update) the modal ?.1 point
-
Thank you very much! I actually cobbled something together that works ? Thank you very much for your help!1 point
-
Ok, Claus! You are close to the solution.? You will get every value by its name attribute. To add all of them to the body, I recommend you concatenate all the values in one string. $email = $form->getValue('email'); $message = $form->getValue('message'); If you have all of your $_POST values than you create your body string (fe with a little HTML markup). $body = '<ul><li>Email: '.$email.'</li><li>Message: '.$message.'</li></ul>; As the last step, add it to the mail body: $m->body($body); // or if you want to use HTML markup $m->bodyHTML($body); You will find a working example at https://github.com/juergenweb/FrontendForms/blob/main/Examples/contactform.php Best regards PS: If you will need help, please post the code of your form here.1 point
-
1 point
-
I’m getting this when I try to go to the Duplicator module: Fatal Error: Uncaught Error: Call to undefined function shell_exec() in site/modules/Duplicator/Duplicator.module:1439 #0 [internal function]: Duplicator::getModuleConfigInputfields(Array) #1 wire/core/Modules.php (4130): call_user_func(Array, Array) #2 wire/core/Wire.php (419): Modules->___getModuleConfigInputfields('Duplicator', Object(InputfieldForm)) #3 wire/core/WireHooks.php (952): Wire->_callMethod('___getModuleCon...', Array) #4 wire/core/Wire.php (484): WireHooks->runHooks(Object(Modules), 'getModuleConfig...', Array) #5 wire/modules/Process/ProcessModule/ProcessModule.module (1680): Wire->__call('getModuleConfig...', Array) #6 wire/modules/Process/ProcessModule/ProcessModule.module (1415): ProcessModule->renderEdit('Duplicator', Array) #7 wire/core/Wire.php (413): ProcessModule->___executeEdit() #8 wire/core/WireHooks.php (952): Wire->_callMethod('___executeEdit', Array) #9 wire/core/Wire.php (484): WireHooks->runHooks(Object(ProcessModule), 'executeEdit', Array) #10 wire/core/ProcessController.php (350): Wire->__call('executeEdit', Array) #11 wire/core/Wire.php (413): ProcessController->___execute() #12 wire/core/WireHooks.php (952): Wire->_callMethod('___execute', Array) #13 wire/core/Wire.php (484): WireHooks->runHooks(Object(ProcessController), 'execute', Array) #14 wire/core/admin.php (160): Wire->__call('execute', Array) #15 wire/modules/AdminTheme/AdminThemeDefault/controller.php (13): require('/customers/a/0/...') #16 site/templates/admin.php (15): require('/customers/a/0/...') #17 wire/core/TemplateFile.php (328): require('/customers/a/0/...') #18 wire/core/Wire.php (413): TemplateFile->___render() #19 wire/core/WireHooks.php (952): Wire->_callMethod('___render', Array) #20 wire/core/Wire.php (484): WireHooks->runHooks(Object(TemplateFile), 'render', Array) #21 wire/modules/PageRender.module (575): Wire->__call('render', Array) #22 wire/core/Wire.php (416): PageRender->___renderPage(Object(HookEvent)) #23 wire/core/WireHooks.php (952): Wire->_callMethod('___renderPage', Array) #24 wire/core/Wire.php (484): WireHooks->runHooks(Object(PageRender), 'renderPage', Array) #25 wire/core/WireHooks.php (1060): Wire->__call('renderPage', Array) #26 wire/core/Wire.php (484): WireHooks->runHooks(Object(Page), 'render', Array) #27 wire/modules/Process/ProcessPageView.module (184): Wire->__call('render', Array) #28 wire/modules/Process/ProcessPageView.module (114): ProcessPageView->renderPage(Object(Page), Object(PagesRequest)) #29 wire/core/Wire.php (416): ProcessPageView->___execute(true) #30 wire/core/WireHooks.php (952): Wire->_callMethod('___execute', Array) #31 wire/core/Wire.php (484): WireHooks->runHooks(Object(ProcessPageView), 'execute', Array) #32 index.php (55): Wire->__call('execute', Array) #33 {main} thrown (line 1439 of site/modules/Duplicator/Duplicator.module) This error message was shown because: you are logged in as a Superuser. Error has been logged.1 point
-
It turns out that this was the missing piece: curl_setopt($cURL, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.2; WOW64; rv:17.0) Gecko/20100101 Firefox/17.0');1 point
-
Hello Claus, thank you for reporting the bug - it is fixed now. There was a missing typehint declaration at the label file. I have updated the module now to 2.1.26 - alternatively please replace the folllowing file: https://github.com/juergenweb/FrontendForms/blob/main/Formelements/Textelements/Label.php On line 20 I have changed the following: protected int $enableAsterisk = 1; // to protected int|string $enableAsterisk = 1; Best regards Jürgen1 point
-
There are a number of ways you could conditionally add CSS to the PW admin, but one simple way is to add this to /site/templates/admin.php (before the line that requires controller.php) if($user->hasRole('editor')) $config->styles->add($config->urls->templates . 'styles/admin-custom.css');1 point
-
There are several updates on the dev branch this week (commit log), including issue fixes, feature additions and minor class improvements. One of the updates I'd planned to add this week was moving InputfieldTinyMCE into the core. However, I noticed that TinyMCE was up to version 6.4.1 now and we were still running 6.2.0, so I decided instead to upgrade ours to the latest and test it out for another week in its own repository. If all continues to work well, I'll likely commit it to the core in 3.0.215. If you have a chance to test the latest version of InputfieldTinyMCE, please do, and open an issue report if you run into any trouble. Last week the Wire Request Blocker module was released in the ProDevTools board and this week we have version 2, which includes several new additions: Added support for blocking groups. Added configurable settings for immediate block (rather than just a strike) for URLs and user agents. Added support for using RequestBlocker in other applications (like we use it here in IP.Board). Added a feature were you can manually test URLs or user agent strings to see how they match your rules. Added a configuration setting so you can choose whether or not to use a log file. Added a section to the docs on how to block URLs from your .htaccess file. As I wrote this post, the processwire.com site is getting hounded with dozens of IPs trying to locate backup or database zip/rar/tar/gz files, using every possible combination of filenames and extensions you can think of, including those that include the term "processwire". Remember to never leave backup files or DB dump files accessible by URL lying around on your server, because they will get eventually found. Adding these rules (below) to WireRequestBlocker's URL matching rules seems to mostly stopped those DB/backup hunting bots: /ba=/backups/|/backup/|/bak/|/back/ .txt=credentials.txt|backup.txt|password.txt|passwords.txt .sql=.sql.gz|.sql.tar|backup.sql|dump.sql|db.sql|database.sql|mysql.sql|.com.sql .tar=.tar.gz|.tar.sql|dump.tar|backup.tar|bak.tar|website.tar|backup.tar|www.tar .zip=backup.zip|bak.zip|.com.zip|well-known.zip|index.zip|public_html.zip|website.zip|dump.zip|wallet.zip|application.zip .rar=bak.rar|website.rar|backup.rar|www.rar .gz=website.gz|bak.gz|backup.gz|.com.gz /old/ WireRequestBlocker only knows its rules and doesn't know who's real and who's a bot, so be careful not to hit URLs containing those strings on this site or it might hit you with nothing but 403's for a few hours. ? Next week is Spring Break here, so I'll likely be on a reduced schedule with kids home from school. Thanks for reading, have a great weekend! +75 more blocks (not shown)1 point
-
I'm also reusing generic fields in my templates with renamed labels. Keeps the DB cleaner. I use custom page classes, a great feature that was introduced in 3.0.152 to map those generic field names to more meaningful properties. This way I get intellisense in my editor and don't have to look up the mappings of generic field names to meaningful ones. Here's an example page class: <?php namespace ProcessWire; use RockMigrations\MagicPage; /** * Custom page class that provides properties/methods for pages with template glossary-item * * */ class GlossaryItemPage extends DefaultPage { use MagicPage; /** * holds the glossary term * * @var string $term */ public $term; public $hide; public $exclude; public $tooltip; public $meaning; public $description; // set custom properties in loaded public function loaded() { $this->set('term', $this->title); $this->set('hide', $this->checkbox); $this->set('exclude', $this->checkbox2); $this->set('tooltip', $this->text); $this->set('meaning', $this->text2); $this->set('description', $this->rte); } /** * Magic Page hook for clearing cache for terms from module Glossary * */ public function onSaved() { $this->wire->cache->delete(Glossary::CACHE_NAME); } } The property->fieldname mapping happens in the loaded() method. you can comment the property definitions so you get some meaningful info with code intellisense. In the template where I want to use pages with template glossary-item, I define the type for those pages to get intellisense: /** @var GlossaryItemPage $p */ <?= $p->term ?> Some notes on the page class code: The GlossaryItemPage extends DefaultPage. My DefaultPage class is a base class for all other page classes which holds generic methods that I want to have available in all page classes I'm using @bernhard's fabulous RockMigrations module which, apart from migrations, provides MagicPages. This makes it super easy to add commonly used hooks to your page classes. I have a Glossary module installed which handles migrations and logic for the glossary. In the migrations for that module I define the custom field labels in the template context: 'glossary-item' => [ 'fields' => [ 'title' => [ 'label' => 'Name of the Term', ], 'checkbox' => [ 'label' => 'Hide', ], 'checkbox2' => [ 'label' => 'Exclude this term from parsing', ], 'text' => [ 'label' => 'Text Shown in the CSS Tooltip', ], 'text2' => [ 'label' => 'Meaning', ], 'rte' => [ 'label' => 'Description of the Term', ] All in all this is a very structured approach. It surely takes some extra time to setup. But this pays back, especially for larger, more complex projects. It took me quite some time as PW developer to come to this kind of setup. I started out with very simple procedural code. I wish I had all these tools available when I started out developing with PW that we have now (page classes, migrations etc.) thanks to this great community. Everyone here has their own approach and workflow. So you will surely get some inspiration.1 point