Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/19/2023 in all areas

  1. Art bot, Databass selector and.WireArray selector diffnt things and not do same thing .this is the way one.is airplane / other is tractor WireArray selector for any.things in memory : fields : templates : fieldgroupos : smogashsnags : ur own tipos : and if necessario - pages in memory { b.coz PageArray extendo WireArray } but u shlud use airplane for.pages not tractor WireArray selectors = genral purpoose for any things u can hold in WireArray in mem. ,, tractor Databass selector == more power ful and optimizely justed for.pages ,, airplane !!! if u using WireArray selector for |find|filter| pages then you are loaded pages u should not / not necessario / not fficent / donut push pages round in.tractor fly, $willyc
    3 points
  2. Purge the StackPath CDN cache when ProCache clears. https://github.com/nbcommunication/ProCacheStackPath If you use StackPath's CDN to deliver your website, you need a way to clear its cache when ProCache clears. This module connects with your StackPath stack via the StackPath API and when ProCache clears it requests StackPath clear the cache, attempting to respect the specific rules (Parents, Family, Children etc) set up in ProCache. This module is being using in production but only for a couple of sites that just clear the whole cache when a page is saved. The implementation of the Parents / Family / Children rules haven't been fully tested, and it isn't clear from StackPath's documentation whether their 'recursive' option only works from the root URL or from internal pages too. Hopefully it does and I'll hopefully get it tested soon. Cheers, Chris
    2 points
  3. Synchronises ProCache clearing across a multi-instance environment. https://github.com/nbcommunication/ProCacheSync The main purpose of this module is to allow ProCache to be used in an auto-scaling multi-instance environment. How it works When a page is saved and cache clearing is triggered, the page id(s) associated with that clear are saved to the database. ProCacheSync runs a check every minute via LazyCron to look for records in the database since ProCache was last cleared. If it finds any it processes them as ProCache would. Any records it finds will have been generated by a clear on another server instance, thus enabling multiple instances of ProCache to stay approximately synchronous. This module is not yet being used in production. Cheers, Chris
    2 points
  4. I'm not yet sure what ProcessWire could do here since it's the template file that controls all the logic of what gets output. But I may not yet fully understand the request, so I'll use an example or what I do understand below. Markup Regions don't have control over what your template file spends time rendering, just what gets output at the end. So there wouldn't be much benefit to having output of partials when it still has to spend the time to render everything, whether used in the output or not. Instead, you would need some logic in your template file in order to selectively render partials, and gain a performance benefit from it: <?php namespace ProcessWire; // render just $part if requested, otherwise render all parts $part = $input->get('part'); // i.e. header, content, footer ?> if($part == 'header' || !$part): ?> <div id='header'> ...header markup... </div> <?php endif; ?> if($part == 'content' || !$part): ?> <div id='content'> ...content markup... </div> <?php endif; ?> if($part == 'footer' || !$part): ?> <div id='footer'> ...footer markup... </div> <?php endif; ?> <?php if($part) return $this->halt(); ?> In the above example, if the page is requested without a "?part=" query string in the URL, then it renders everything (header, content and footer). But if rendered with a "?part=content" query string in the request URL (for example), then it would render and output just the <div id='content'>...</div>.
    2 points
  5. Wow... is all I can say right now for the moment. What amount of traffic or hits/second are you awaiting for that kind of setup? I built and ran pretty cheap and simple setups that handled up to about 30-50k hits*/day without noticable issues - ok, those sites were ProCached and running behind Cloudflare CDN (free tier), yet... it worked out. They probably could have handled even more. Nothing of my projects here are scaling horizontally, vertically or in any other direction 🙊 compared to your setup. It's not within your league of setups by any measure - but here is how I built something that scaled back in my days very well: JS files came from sub[1-3].domain.tld super necessary parts were inlined file_get_contents of custom JS came from external sources CSS files came from sub[1-3].domain.tld almost all (critical) CSS was inlined file_get_contents of custom CSS came from external sources IMGs came from assets[1-3].domain.tld Cloudflare took care of GZIP and compressing and caching the output (not sure about brotli) ProCache took care of the heavy load prior to everything else as 95% of the whole site/s were cached (pre-cached by using a Sitescraper after each release) with a very long lifetime Asset and file handling were kind of static and strict without much options for custom solutions (wasn't really necessary for those sites) as the overall page setups were kind of minimal and simple (blog style - minimal differences) files like JS, CSS, IMGs came from other services and not my host, actually everything from a subdomain came from other services as the hosting was too cheap to handle lots of requests - I used Github, Zeitgeist (which is Vercel now - I guess), and some other services I can't remember, for that It was a bl**dy hell to make that work back then (BUT I had to save money I didn't have then) - but those were also one of my very first real projects with ProcessWire then (one of my first public 10 projects ever, and most of them were my own projects) - nowadays that setup would probably be still annoying in some parts, yet more feasible and easier to handle with way better results. My issues back then were limited database and webserver connections (those were over limit pretty fast) at my hosting companies (HostN*n, Dream***, Host***, Blue***, A2***, and such - super cheap) so I split all assets to other services and made them work via subdomains. In the very early days I only paid something between 0,99 USD/month for those sites. Later on 2,99 USD and even later 8,99 USD. It only became faster and faster. About a year before selling/shutting down those projects I paid about 60 USD/month/project. STEEP! Still the almost same setups could easily handle more than double/triple the hits*/day nowadays but with far better pagespeed results than ever before. Till today I'm happy with these kind of setups for my projects. The moment I reach at least 50k+ hits*/day with a project I return to that but with methods and services from today. What I use nowadays (for whatever reason - you will find out 😉😞 webgo IONOS Hetzner Plusline Server Netlify Vercel Cloudflare Pages Cloudflare CDN Cloudinary Planetscale Runway Superbase * real hits/users/sessions - no fake requests ** paid plans for super high traffic sites, otherwise free tiers
    2 points
  6. The core show-if can only work when the test relates to values that are contained in inputfields in the Page Edit form, (e.g. "some_field=foo"). Technically there is a field in Page Edit that relates to the parent - the "Parent" (parent_id) field on the Settings tab. But that inputfield is set to AJAX-load so the value isn't available to the inputfield dependencies JS. But you can use the Custom Inputfield Dependencies module to create show-if conditions that are evaluated by PHP rather than JS: https://processwire.com/modules/custom-inputfield-dependencies/ You would create a show-if condition like this:
    2 points
  7. Extends Pagefile to use Cloudflare Images, Stream and R2 storage to serve files. https://github.com/nbcommunication/CloudflareAssets The main purpose of this module is to allow ProcessWire to be used in an auto-scaling multi-instance environment. By serving file assets from Cloudflare, it is not necessary to have all file assets copied to all instances and we also get the benefits of serving assets from a CDN. How it works When a Pagefile is added in the admin or via the API, it is uploaded to Cloudflare's R2 storage service. Additionally, if the file is an image, it is uploaded to Cloudflare Images, and if the file is a video it is uploaded to Cloudflare Stream. When a URL for the Pagefile is requested e.g. $pagefile->url(), the appropriate Cloudflare URL is returned. As ProcessWire's admin still requires the file to be available locally, in a multi-instance setup if a file is not available it is downloaded from the 'master' copy in R2. This module is not yet being used in production. There may be changes to how Images work in the coming months as features are still being rolled out to this Cloudflare service. Cheers, Chris
    1 point
  8. @kongondo When using $padloper->getValueFormattedAsCurrencyForShop() there is a space after the £ symbol which I notice on the demo site too. Where might one remove this space so it displays as £10.00 rather than £ 10.00?
    1 point
  9. @kongondo sorry about all the questions... Continuing on with this discount solution I've made, I'm trying to show the discount code on the padloper-order page opposed to the order item. I've edited your PadloperProcessOrder::orderSaved hook to suit and when I edit the order page from the page tree I see that the discount code is saved to the text field however it doesn't display if I view the order page via the shop dashboard. I assume it's due to this rendering a customised page edit view, so wondering if there is an easy solution to get this custom field outputting on the shop's order page?
    1 point
  10. @kongondo Yes, I was playing around with some other idea and I've left this in with my haste! There is no requirement for that conditional whatsoever 😂
    1 point
  11. If it's to use of anyone this thread covers how I've implemented a (currently hardcoded) discount code with the help of @kongondo. I can share more information if required, but this should defo get you in the right direction. The next job, when I get a mo, will be to look at making an add on to pull and update the discount code from for admins of the shop. I know that it's on the roadmap for development, so it depends whether I get round to that before this feature is released as part of the core package.
    1 point
  12. @WillyC yes, the use case was an import - a big migration from another CMS; I wanted to maintain a known list of tags in memory for efficiency, rather than sending an airplane to fetch all tags again and again - you know, for the climate's sake 😸 But anyway, it's fine. I suppose I could have maintained my own vanilla array index instead of a PageArray but I thought I was being cool using the new tools, until I found out it's a tractor. Anyway, tis done now. @flydev thanks, but that requires me to know that there aren't two distinct items: "system change" and "change system". At first I posted because I thought there might be something I was missing (like WireArray::setCaseInsensitiveMatching() or such). But then as I dug into it I found that the limitations are hard coded. None of the help/docs pages I read have any warning of this; there's many examples of chaining from a db query ($pages->find()) into some other filter without warning. I think there should be warnings in the docs about the different implementations, when suggesting filtering on a WireArray, as opposed to a $pages query. I think there should be an equals operator that is explicitly case insensitive. (though perhaps we've exhausted every combination of symbol already...!) I think the codebase should be updated to be UTF-8 compatible so that É matches é, for example on the case-insensitive matchers. But I'm too much of a noob to do PRs yet (and I have to train my editor to use tabs not spaces 🤣) Anyhoo, thanks for the suggestions, all.
    1 point
  13. Just adding that if you use a fallback operator in your selectors like `~|=` the last three tests in your code should get a result.
    1 point
  14. It also has issues like fields not having edit rights make conditions not being evaluated properly. Also, Presentation settings like "Open + Locked (not editable)" and others make it fail to work. The way it is implemented in the core is half baked, has not been taken care of for years and based on the probably wrong design decision that it can be done with JavaScript only. @Robin SYour module is a lifesaver indeed. Thanks a million!
    1 point
  15. I just recently started using DDEV and it's great. However I do have one issue with it out of the box, it seems like ProcessWire's normal error reporting doesn't work for me when debug mode is on. Instead I get the standard 500 error message that would normally be shown to a logged-out user. Anyone else run into that? This is when not using Tracy Debugger. When using Tracy, it does show errors, but only if I manually set it to DEVELOPMENT mode, it's not able to DETECT that.
    1 point
  16. @kongondo Legend! Ta. I did it like so if ($input->post->padloper_cart_products || $input->post->padloper_cart_remove_product || $input->post->discount_code) { $products = $input->post->padloper_cart_products; $rem_products = $input->post->padloper_cart_remove_product; $padloper->updateCart($products, $rem_products, $isRedirect = false); $discountCode = $sanitizer->text($input->post->discount_code); if (!empty($discountCode)) { if ($discountCode == "T/O-FF") { $session->set('orderDiscountCode', $discountCode); } else { $session->set('orderDiscountCode', $discountCode); } } $session->redirect($page->url); } Works a charm coupled with your example price update hook. I'll post link to this chat in the other topic where someone was asking for a solution 😊
    1 point
  17. Hello, We've recently been researching how to use ProcessWire in a horizontal scaling environment (multiple server instances using a load balanced, read replica databases), and ran an experiment using AWS Elastic Beanstalk. Getting read replica databases up and running was easy - it's built in to the core: https://processwire.com/blog/posts/pw-3.0.175/#how-to-use-it-in-processwire Using multiple server instances throws up one big problem: how to keep the filesystem on multiple instances in sync given that ProcessWire doesn't currently support using an external service (like s3 or EFS) as the filesystem. The solution that we came up with is to use various Cloudflare services (R2, Stream, Images) to serve file assets, and we've built a module to facilitate this: We're not using this in production yet, but our tests on EB were successful, and we're confident this will solve the main part of this problem. However the Cloudflare Images service is still quite new and there's still features to be rolled out (e.g. webP for flexible variants) so it can't be considered a complete solution yet. Additionally, we use ProCache and this presents an additional multi-instance problem - if the cache is cleared on one, how can we clear it on all? Our solution is to log clears in the database and use this to sync up clearing. We built another module: Again this worked well in our test, but isn't yet being used in production. The main purpose of this thread, aside from sharing these potential solutions, is to ask for and discuss other experiences of hosting ProcessWire in a horizontal scaling environment. What solutions did you come up with (if you want to share them) and are there other potential issues we maybe haven't thought about? Cheers, Chris
    1 point
  18. Hi @alexm, Thanks for clarifying. I get you now. Although the those hooks would normally work, since the form in cart-edit is being submitted to a 'virtual' URL handled by URL Hooks and because a redirect occurs, execution halts, hence, the 'hooks' get released/discarded and you are left with nada. If anyone knows if my statement is untrue or partially incorrect, please let me know. Now, back to your issue, easiest solution is to handle updating the cart yourself using $padloper API instead of sending the form (action) to the virtual padloper URL. This will allow you to process your custom form inputs yourself. Updating the cart is as simple as this: <?php namespace ProcessWire; // *** UPDATE CART FOR AN EXISTING CART ITEM *** // @note: $id: this is the id of this product as a cart item in the database // it is not the page ID of the product! // @note: these inputs should match the fields in your custom 'cart-edit' form $id = (int) $input->post->padloper_cart_update_product_id; $quantity = (int) $input->post->padloper_cart_update_product_quantity; // update the cart ($key=>$value pair of cartItemID => cartItemQuantity) $updatedCartProduct = [$id => $quantity]; // update the cart $padloper->updateCart($updatedCartProduct, $rem_products = null, $isRedirect = false); // handle your custom form input $discountCode = $sanitizer->text($input->post->discount_code); // ETC... Your and PadloperCart::getProductPrice', null, 'discountCodePrice' Hook doesn't need changing. Hope this helps. Please let me know if you need further help with this.
    1 point
  19. Just released v1.1.0 with support for automatically switching to the tab that contains the first error. This way editors won’t be confused if the error is on a different tab from the one they’re currently on.
    1 point
  20. Looks like the ajax upload is leading to the 403 page being returned - html where json was expected. Question is why. Do you have any custom (non standard PW) directives in your .htaccess file? What version of PW are you running there? Other things - is this running on a platform with a WAF/Modsecurity or other front-end?
    1 point
  21. Hi, and welcome to the forums! I recommend that you use different templates for the home page and child pages. This should make doing what you need in the back end (editing) pages straightforward Then for the template files, there are various approaches you could use. Probably the easiest would be the one described under "Direct Output with Includes" at https://processwire.com/docs/tutorials/how-to-structure-your-template-files/. For example, the includes for both template files might be head, body and footer sections, but a menu section could be different in each. Let us know if you need further help!
    1 point
  22. Hi @alexm, I have tested and it works for me with hook, hookBefore and hookAfter, i.e. all the below work (in ready.php): <?php namespace ProcessWire; // $this->addHookBefore('Padloper::updateCart', null, 'updateCartHook'); $this->addHookAfter('Padloper::updateCart', null, 'updateCartHook'); // $this->addHook('Padloper::updateCart', null, 'updateCartHook'); However, it is not clear to me how hooking into Padloper::updateCart helps with what you are trying to achieve. 676 in the example above is the cart_row_id of some product and 6 is the quantity of the product in the cart. What information about the cart are you after in relation to your discount?
    1 point
  23. @ngrmm The snippet above hooks into ProcessPageEdit::buildForm – this would add hCaptcha to the page edit forms in the backend, not to Form Builder forms. The example code would add the hCaptcha code to all page edit forms, but you could limit it to pages with specific templates. Through $event->object you have access to the ProcessPageEdit instance object, and $event->object->getPage() will get you the page being edited. If you want to insert the hCaptcha field to all Form Builder forms programmatically, something like this should work, though I haven't tested it: $forms->addHookBefore('FormBuilderProcessor::renderReady', function (HookEvent $event){ $processor = $event->object; $form = $event->arguments('form'); if ($processor->formName !== 'contact_form') { return; } // insert hCaptcha }); This should insert hCaptcha into a form named contact_form. Keep in mind that the selected embed method still needs to support this, so the caveat regarding embed method D still applies.
    1 point
  24. 1 point
  25. This will take care of changing the published date: $query = $database->prepare("UPDATE pages SET published=:pub_date WHERE id=:page_id"); $query->execute([ ':pub_date' => $pubDate, ':page_id' => $pageId ]);
    1 point
  26. That's actually cool! Even more if you would give me a like!
    1 point
  27. That's a good example sinnut, but a minor change to make it work: public function afterSave($event) { $page = $event->argumentsByName('page'); // get argument by name, more readable if($page->is(Page::statusUnpublished) || $page->publish_date) return; $page->publish_date = time(); $page->save('publish_date'); } isset() wouldn't work in the previous example as the field exists but is not populated it will always return true. Also $page->of(false) isn't really required as in a module the page has no outputformatting on anyway. To populate the datetime field you'd just give it a timestamp. As the field holds input-outputformatting date formatting it will take that. Not wrong but no need to. If you also need to restrict to certain pages you could add a check for the template before status check. if("article" == $page->template) return;
    1 point
×
×
  • Create New...