- 
                Posts4,046
- 
                Joined
- 
                Last visited
- 
                Days Won67
Everything posted by Pete
- 
	Very nice! Only other thing I would add is maybe use hidpi variants on the PNGs too as my monitor is 1.5x normal DPI and they look a little fuzzy and possibly fuzzier still on fancier 4k screens. I enjoyed the honest pricing - it's been a bit of a journey these past few years to realise ecommerce often should start at that price point due to time involved. It's never particularly quick to set up and in my (limited) experience there will always be enough requests for stuff that's not "out of the box" to more than justify it. (Disclaimer: of course, pricing is different around the world but those figures didn't strike me as anything other than sensible).
- 
	It's actually sort of on the list for the projects we work on together Ryan, just I think the client is talking to me about it rather than give you another chunk of work to think about. Might be worth us discussing it next week.
- 
	So I had to do this one recently - develop a new theme on a busy site so the staff could test it out with their live data and the solution was to add this into site/init.php: if ($user->isLoggedIn() && $user->new_site_toggle == 1) { $config->urls->templates = "/site/tailwind/"; $config->paths->fieldTemplates = dirname(__DIR__) . "/site/tailwind/fields/"; $config->paths->templates = dirname(__DIR__) . $config->urls->tailwind; $modules->AdminThemeUikit->logoURL = 'site/tailwind/images/logo-white.svg'; $config->AdminThemeUikit = [ 'style' => '', 'recompile' => false, 'compress' => true, 'customCssFile' => '/site/assets/admin.css', 'customLessFiles' => ['/site/tailwind/styles/admin.less'], ]; } You might not need all that code but basically there was a checkbox field for certain users called "new_site_toggle" where they could login and toggle the new templates on and off and the template files just lived in /site/tailwind/ . "fieldTemplates" is for RepeaterMatrix template files in case anyone is wondering about that one. The Admin Theme config stuff at the end of my code above was just because I like to customise the colours etc in the admin theme, plus in this case it helped reinforce which version they were currently about to view on the frontend. I think I also added a toggle button and some jQuery to the frontend to make toggling whilst viewing the site a one-click process. Honestly the only problem with this approach was the new theme having different fields for some templates so old stuff had to live alongside new stuff, but as content was being updated all the time and I didn't really have time to do it any other way. In hindsight using some of Bernhard's modules would have helped as I ended up doing far too much dev on the live site instead of syncing changes ?
- 
	It doesn't come up all the time for me (depends on the site) but often enough that I agree with others that re-using images on other pages is important. I rarely insert them into the editor - that's my problem. How could we have an image from a different page's single/multi-image field be used in another page's single/multi image field because that's how I would need to use that feature? Maybe next to the upload button have another button to select existing from another page (or media manager - I like that idea) and it's inserted into that field as a reference and can have it's own description, tags etc. Likely others have already talked about this a lot over the years whereas I've just ignored it and duplicated my images quite a few times ? I think though that this is where storing images in folders by page ID would maybe need to be replaced with something else to uncouple them from page IDs on disk, like maybe files/field id/ instead though granted that would be complicated for an existing site with thousands of images already on it. They'd also need to be grouped under the field ID as on a travel website /files/photos (as an example) could have 10k files or a lot more with variations under it easily. Not sure that's actually a problem though - feels like it might have been 10 years ago but maybe it's not now. If you wanted though you could have a subfolder per image ID for that field to store it and all variations neatly which somewhat alleviates the issue.
- 
	I'll have a chat with some of the mods about what we do with it as I don't have time to manage it any more and it needs updating - has done for years.
- 
	Registrations on the forums have been temporarily disabled whilst we deal with a bot problem. Hopefully we'll be able to re-enable registrations later today.
- 
	- 8
- 
					
						
					
							  
- 
					
						
					
							  
 
 
- 
	So I tried this method but it still puts in the parameter if it's empty: I think the solution is to use the notes to convey what the default value will be if empty, but also have a way not to add it into the markup if it's empty - perhaps some sort of __omit_empty override, so default_term__omit_empty parameter since we don't want to make assumptions for everyone else using this already? That way for these specific cases I can also add a note warning them that if it's left empty it will defer to the defaults that can change over time so the content editor has had fair warning. EDIT again - my brain is not in gear today because I can simply do this myself and check for an empty value ? So this is a non-issue now - I can work with this easily by doing: if(strlen($default_term) === 0) { // use the default value in the PHP code } And using strlen because the value might actually be a zero of course. Edit #237: Here's my solution: Attributes: default_amount default_amount__notes=Leave blank to default to 150000 - default may be changed in future default_term default_term__notes=Leave blank to default to 25 years - default may be changed in future default_type default_type__type=select default_type__options=Repayment|Interest Only default_type__notes=Leave blank to default to Repayment default_rate default_rate__notes=Leave blank to default to 4% - default may be changed in future And defaults are now set in the PHP code, overridden with the HannaCode selections if any values are set <?php namespace ProcessWire; $types = ['Repayment' => 'repayment', 'Interest Only' => 'interest']; $default_amount = strlen($default_amount) > 0 ? $default_amount : 150000; $default_term = strlen($default_term) > 0 ? $default_term : 25; $default_type = strlen($default_type) > 0 ? $types[$default_type] : 'repayment'; $default_rate = strlen($default_rate) > 0 ? $default_rate : 4; echo $files->render('partials/calculators/mortgage', ['default_amount' => $default_amount, 'default_term' => $default_term, 'default_type' => $default_type, 'default_rate' => $default_rate]);
- 
	Neat, I missed that! @Robin S a very good point and I'm not sure what the solution is to be honest. EDIT: skip to next post. A few options: For some tags the easiest option is not to use the Hanna Code Dialog - maybe we could simply have an option to skip your module being used on a per-tag basis somehow? I've no idea how hard that would be but would solve the problem for this one but still allow it to work for other tags on the same site In the Hanna Code Dialog have the defaults set as placeholders instead of default values - that way if they aren't populated then they aren't used? I can simply set the defaults in the PHP code then. I think perhaps option 2 makes the most sense above - if a dialog option has no value entered simply don't add it into the tag markup. EDIT: @Robin S actually the obvious answer is to use parametername__notes and mention the default there and add the default values into the PHP code I think - I'll try that now.
- 
	@Robin S something I had noticed when making all variables editable is even if you don't change them from the defaults, it inserts them into the code. For example, I have a site where I want use this for a mortgage calculator and want to set things like term (years), type (repayment/interest-only), rate (percentage) and so on, but if I only want to change the "type" from repayment (default) to interest only on one page, the hannacode also ends up setting the rate in the code in the editor even though I leave it as the default. This wouldn't normally be a problem but the site has articles for different terms, repayment types and potentially interest rates, but when interest rates change I change the default rate in the Hannacode, but using the dialog it makes it fixed for that page. I think if you use the dialog and the value saved == the default value, it just shouldn't appear in the hanna code block. In my example, this would be the default with no overrides: [[mortgage_calculator]] And some pages I'll want it to default the mortgage amount: [[mortgage_calculator default_amount="70000"]] But changing one variable sets them all using HannacodeDialog even though the other values are the default ones: [[mortgage_calculator default_amount="70000" default_rate="4" default_type="repayment" default_term="25"]] On another note I'm also keen to see a TinyMCE version ??. I know it's a lot harder than this next suggestion, but I did get ChatGPT to write most of a plugin for both TinyMCE and CKEditor in the past year- I knew nothing about plugins for either editor prior to that but with ChatGPT's help I was able to get there in about 90 minutes versus some confusing (to me!) documentation. It was funny because it was ChatGPT creating a plugin to write an article outline USING ChatGPT for one of them ?
- 
	@Jason Spooner I'm submitting a PR on Github now for Horst to look at - thanks for finding the issue.
- 
	@horst the regex mentioned above does appear to be faulty as it only allows domain endings up to 6 characters whereas this discussion suggests an upper limit of 63 (though nobody has created one that long yet to my knowledge). I would just go for 2,24 for now to keep it relatively sensible as the longest currently is 24, or you could just make it 2,63 to future-proof it a bit? Source: https://stackoverflow.com/a/22038535
- 
	  New post: Using date range fields in ProcessWirePete replied to ryan's topic in News & Announcements @MarkE I was going to say "+1 for the times feature" but for accommodation it doesn't make as much sense to have it there as you are mainly after the number of days/nights right? Arrival/departure times could simply be set against each holiday cottage/apartment or fall back to a "company standard" arrival/departure time like you get with some of the bigger companies? All I'm thinking is otherwise you need to enter the arrival and departure time *every time* rather than have it set at one of the "parent levels" like cottage/apartment or globally. @ryan I definitely see the point for an optional time input for some types of event - like a single day course that runs 11am-3pm it would be good to still use this field otherwise you're back to needing 2 fields again. Same for multi-day events where there's a very definite start and end time. These are the sorts of things where on the frontend you would have a calendar with all the events on and there would be a real mix of single/multi-day but you definitely want a way of showing the times. Also allows for frontend stuff like the Resource Timeline and Resource Time Grid on libraries like https://fullcalendar.io/demos
- 
	Thanks Ryan, I've really wanted something like this for a long time so good to hear you're making progress. ProDrafts is useful, but if this allows for a more complete version history like you might get in other CMS' and you can also then add in approval workflows down the line (separate module I reckon) that would be amazing too as I have a few sites where there are several people working on stuff at once and I know at least one of our mutual clients might find it useful too ?
- 
	Hi folks, I have a system with multiple separate installations that should be identical really apart from uploads and database and, for a long time, for no particular reason, the only folder I've symlinked to a "master" folder is the wire directory. Since nothing should differ on these installations apart from the site/assets folder, should I just be able to symlink all other directories too? In theory all I need to be unique is the assets folder and the site config files. There are obviously quite a few benefits - only having to update modules in one place, updating all installations to the same version at once from the master version etc. Currently I've been doing it with Github but I've realised I'm just duplicating a lot of files unnecessarily whilst I'm not using something like Docker (it will use something like that eventually but not needed for a year or two). I would be interested to know how others have approached this if you've had a similar business need.
- 
	Can confirm this is caching properly now (tested using Wirecache option).
- 
	Just tested and sending via CURL using Postmark's API from a command line it went through fine so I guess it must be the module trimming the .solutions part of the domain unless the server config can also have an effect on emails sent this way?
- 
	Hi Horst, is there anything in the module that would trim a recipient's TLD? I'm finding a recipient with a .solutions domain is getting their addresses trimmed to user@domain.soluti when sending via Postmark but I didn't have this issue on an earlier version of the module... not that I can remember anyway ?
- 
	Ooh nice to see autocomplete getting some updates there ?
- 
	Thanks again - I've got the demo working. The HTMX demo works with 2 dummy variations under a product, but the Alpine demo doesn't show the options. I don't think it matters too much though as I've still got a lot to look at adapting this to my project first - I'll let you know how I get on.
- 
	Wow thanks - I'll take a look and let you know how I get on!
- 
	Thank you - I will check it out! My biggest problem is I never make enough time to watch videos and read tutorials - it only happens "in the heat of battle" (where battle is with a deadline ?) whereas I need to get my workload to a level where I can set aside an hour or two each week to learn things properly and have a play around outside of a project. I could probably build up a little library of reusable code based on common scenarios that way instead of having to remember which project I did something on that I need again in a hurry a year down the line (I think we've all been there, right?).
- 
	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?
- 
	Actually yesterday at one point that markup was before the closing body tag in my footer - one of the reasons I gave up on using HTMX to replace parts of it is I couldn't work out how to open the modal itself (change modalopen to true) AFTER the htmx response was finished. I was, of course, trying not to open the modal on the button click and then have a delay whilst the variables were filled in but I suspect there's some simple HTMX/Alpine combo that does the job. So if you're up for teaching me something ridiculously simple like that I would very much appreciate it too ?
- 
	Thanks! Yeah I did initially start rewriting a big PHP function I've used on other projects called buildModal() to use HTMX to just update the necessary bits but then after a while I realised I was reinventing something I'd already built so probably not the best use of my time when I'm trying to finish something in a hurry (plus it was the weekend and I was getting annoyed with myself for working the weekend so gave up too easily ? ). I think my other thought was that the empty markup is only about 4kb so "why not load the whole thing?" especially since you have to replace the content with some sort of markup anyway - but that does add up over time and on this shop repeat customers would genuinely open up that 3-5x per order and there are a lot of orders daily so the 4kb does add up I guess! I did read about nextTick and custom events but couldn't wrap my head around it yet. I probably need to watch some videos too - I find the docs for both HTMX and Alpine confusing and a little inaccessible for me at least - I have real trouble learning without lots of real-world examples and the docs probably aren't the best place to find those. If there's a good source of HTMX and Alpine (combined) video tuts out there that folks could recommend I'd love to check them out. If you're up for doing a simple demo that would be great - as much as possible I'd like to just re-use your functions from Demo 1. I'm happy to change my modal code to just update the modal - I have been playing with it a bit more today. The template for it at the moment is simply: <?php namespace ProcessWire; /** @var $title */ /** @var $formID */ /** @var $url */ /** @var $content */ /** @var $action */ /** @var $buttons */ /** @var $scripts */ ?> <div id="modal-wrapper" x-data="{modalopen: true}" x-cloak> <!-- Modal Backdrop --> <div id="modal-backdrop" x-show="modalopen" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="transform opacity-0" x-transition:enter-end="transform opacity-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="transform opacity-100" x-transition:leave-end="transform opacity-0" tabindex="-1" role="dialog" x-bind:aria-hidden="!modalopen" class=" z-90 fixed inset-0 overflow-y-auto overflow-x-hidden bg-gray-900 bg-opacity-75 md:p-4 lg:p-8" > <!-- Modal Dialog --> <div class="flex flex-col shadow-sm bg-white overflow-hidden w-full max-w-3xl mx-auto" x-transition:enter="transition ease-out duration-200" x-transition:enter-start="transform opacity-0 scale-125" x-transition:enter-end="transform opacity-100 scale-100" x-transition:leave="transition ease-in duration-100" x-transition:leave-start="transform opacity-100 scale-100" x-transition:leave-end="transform opacity-0 scale-125" role="document" > <div id="modal-title" class="py-4 px-5 lg:px-6 w-full bg-gray-50 flex justify-between items-start"> <?php if ($title) { ?> <h4 class="font-medium"> <?php echo $title ?> </h4> <?php } ?> <div class="-my-4"> <button type="button" class="close inline-flex justify-center items-center space-x-2 border font-semibold focus:outline-none px-2 py-1 pt-4 leading-5 text-sm rounded border-transparent text-gray-600 hover:text-gray-400 active:text-gray-600 ml-4" x-on:click="modalopen = false" > <svg class="hi-solid hi-x inline-block w-6 h-6 -mx-1" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"> <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/> </svg> </button> </div> </div> <form id="<?php echo $formID ?>" class="InputfieldForm ajaxForm my-0" method="POST" action="<?php echo $url ?>" enctype='multipart/form-data' autocomplete="off"> <div class="p-5 lg:p-6 grow w-full"> <div class="block-content pb-3 text-gray-600"> <div id="messageBox"></div> <?php echo $content ?> </div> </div> <div class="py-4 px-5 lg:px-6 w-full bg-gray-50 text-right space-x-1" id="modal-buttons"> <?php echo $buttons ?> </div> </form> </div> <!-- END Modal Dialog --> </div> </div> <!-- END Modal Backdrop --> <div id="modal-scripts"><?php echo $scripts ?? '' ?></div>
- 
	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!
 
            
         
                 
					
						 
					
						 
                     
                     
					
						 
                     
                     
                    