Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 11/21/2024 in all areas

  1. Hey @herr rilke thx for your interest. Unfortunately nobody else showed interest so it looks like a video would not be interesting to a lot. I did that as well, but what I don't like with that approach is that if you move a block you have to adjust all classes of all blocks which is tedious. My approach works similar but different 😛 I use a dedicated block type solely for the color. This block sets a custom runtime flag (like $site->bgColor) and all blocks then add a custom class based on that bgColor flag's value. So once I have a color block with setting "muted" all following blocks might get the class "bg-muted", for example. Then when the next color block comes up it might set the bgColor flag to "primary" which would tell all following blocks to add the class "bg-primary". Now the challenge is to make that work with spacings and with frontend editing. On frontend editing the problem to solve is with sorting blocks, because classes come from php and sorting is done on the client with JS. So you need to add a little js to adjust classes once sorting happens. In my project this is done like this: // section color updates on sort document.addEventListener("rocksortable-added", (event) => { let sortable = event.detail; sortable.option("onMove", (e) => { setTimeout(() => { let el = e.dragged; let container = el.closest("[sortable]"); let children = container.children; let colorClass = null; // loop all items and update color classes for (let i = 0; i < children.length; i++) { let child = children[i]; // don't change class of dragged item if (child.classList.contains("sortable-drag")) continue; // update colorClass on every rpb-color block if (child.classList.contains("rpb-color")) { colorClass = child.getAttribute("data-col"); continue; } // update colorclass of element if (!colorClass) colorClass = "white"; child.classList.remove("has-bg-white"); child.classList.remove("has-bg-muted"); child.classList.remove("has-bg-primary"); child.classList.remove("has-bg-secondary"); child.classList.add(`has-bg-${colorClass}`); } }, 0); }); }); For block spacings I've switched my approach from PHP based calculations to CSS based calculations. The trick is to only use margin-top for blocks, because then you can define different margins for blocks based on the previous block like this: .bg-white + .bg-muted { margin-top: 20px; } This way you can achieve a lot of flexibility in your design with very little complexity in code. Hope that helps!
    1 point
  2. Cacheable Placeholders This module allows you to have pieces of dynamic content inside cached output. This aims to solve the common problem of having a mostly cacheable site, but with pieces of dynamic output here and there. Consider this simple example, where you want to output a custom greeting to the current user: <h1>Good morning, <?= ucfirst($user->name) ?></h1> This snippet means you can't use the template cache (at least for logged-in users), because each user has a different name. Even if 99% of your output is static, you can only cache the pieces that you know won't include this personal greeting. A more common example would be CSRF tokens for HTML forms - those need to be unique by definition, so you can't cache the form wholesale. This module solves this problem by introducing cacheable placeholders - small placeholder tokens that get replaced during every request. The replacement is done inside a Page::render hook so it runs during every request, even if the response is served from the template cache. So you can use something like this: <h1>Good morning, {{{greeting}}}</h1> Replacement tokens are defined with a callback function that produces the appropriate output and added to the module through a simple hook: // site/ready.php wire()->addHookAfter('CachePlaceholders::getTokens', function (HookEvent $e) { $tokens = $e->return; $tokens['greeting'] = [ 'callback' => function (array $tokenData) { return ucfirst(wire('user')->name); } ]; $e->return = $tokens; }); Tokens can also include parameters that are parsed and passed to the callback function. There are more fully annotated examples and step-by-step instructions in the README on Github! Features A simple and fast token parser that calls the appropriate callback and runs automatically. Tokens may include multiple named or positional parameters, as well as multi-value parameters. A manual mode that allows you to replace tokens in custom pieces of cached content (useful if you're using the $cache API). Some built-in tokens for common use-cases: CSRF-Tokens, replacing values from superglobals and producing random hexadecimal strings. The token format is completely customizable, all delimiters can be changed to avoid collisions with existing tag parsers or template languages. Links Github Repository & documentation Module directory If you are interested in learning more, the README is very extensive, with more usage examples, code samples and usage instructions!
    1 point
  3. I've used DigitalOcean for years and the experience has been great, but little less over time. Ever since they went public with their IPO they've raised their prices noticeably and it feels like there are a bunch of upcharges for things that should be included. As a word of warning to anyone stumbling across this post, don't even bother with their managed databases. Terrible performance with high latency that really slows down applications. Not surprised that @ErikMH tests of DO vs others showed lag. I'm going to take a look at Vultr for my next move, the pricing looks good, like DO used to be. @modifiedcontent The flavor of Linux you choose will have less of an impact than the hardware. I tend to go with Ubuntu on servers because everything is easily available through apt repositories and it has wide support. You could say the same for Debian, but I go with Ubuntu since they offer Expanded Security Maintenance and Livepatch services. Knowing that there's automatic updates to the server is nice. Combine that with configuring unattended-upgrades and it's a good way to keep things up to date. When you read the information on their site about these services, the language targets the enterprise, however when you create an account you can get these services for free for a limited number of machines. I've run ProcessWire on both Ubuntu and Alpine and didn't notice a difference other than Alpine was a little more bare bones. As long as the server can handle PHP and a database, ProcessWire won't know the difference. You're better off focusing on optimizing PHP-FPM workers and taking advantage of the strong PHP features like OPcache, adding the ModPageSpeed module, and JIT compiling (if it suits your use case). If you choose to explore using ModPageSpeed that will be an easy add and configuration on Ubuntu, Alpine will require a Docker container and extra work. As for a recommendation on hardware, NVMe drives will likely have the most impact on performance, followed by the processor. Depending on how much you expect your server to handle, they're worth the few extra bucks if it's in your budget. I've switched between the basic VPS and a VPS with an upgraded drive and CPU and the difference was noticeable in how fast the PW admin runs. ProCache content is also delivered faster via NVMe. I saw some benchmarks that were performed on a DO droplet and AMD beat out Intel easily on performance. Not sure if that translates to other cloud providers, but given what we've seen with Intel and their chip shenanigans in the past year, I'm all AMD these days. Not sure of how you prefer or plan to manage the server itself, but if you want a recommendation for a control panel, I've recently had a great experience with Virtualmin. It has a lot of UI control for some granular items that you would expect to manage from the CLI. I've managed VPSs via both, and have long preferred managing everything via bare SSH and bash but Virtualmin offers pretty much everything you need in a gui, and is great on performance. It also makes managing resources much easier than CLI, like how much RAM is dedicated to the database process (if you choose to run your DB on the same server), which makes it great for running lean on lower spec servers. I did just migrate to Virtualmin + bare Ubuntu from OpenLiteSpeed + CyberPanel within the last month. OLS has some attractive features out of the box, like native support for HTTP3 which provides excellent speed on TTFB, but it comes with tradeoffs and locks a lot of things behind an upgrade package that is hard to justify in cost. OLS locks you to one worker process unless you purchase a very expensive enterprise upgrade. I use ProCache to deliver content where possible but there are times when you can't, and the PW admin can run noticeably slow. The HTTP3 and extra layer of built-in caching are eclipsed by less than stellar performance everywhere else. I added some extras here that nobody asked for, but if anyone else has some experiences they can share I'm interested in hearing more from the community as well.
    1 point
  4. Hey all! This is a module to enhance forms built using the Pro FormBuilder module by providing the ability to submit them in place using AJAX and HTMX. FormBuilderHtmx works in harmony with FormBuilder by handling front-end rendering and AJAX and lets FormBuilder manage form configuration and processing. FormBuilderHtmx provides a drop-in replacement for the $forms->render() method and provides all native features and behavior (and adds a few extra superpowers to boot). Noteworthy features: Zero configuration, install and render AJAX powered FormBuilder forms immediately Render multiple forms on the same page. Supports both multiple instances of the same form or different forms. Each form is processed independently. Non-intrusive, can be used alongside FormBuilder's native rendering methods and does not modify core module behavior Perfect for forms embedded in popups and modals Does not conflict with styling and other JavaScript already in-place, only handles the form submission/response loop Automatically disables the `Submit` button on submission to prevent duplicate requests Provides the ability to add a custom 'spinner' shown when a form is being processed Gives you the ability to add additional HTML attributes to your FormBuilder <form> element. Add additional custom functionality using HTMX attributes, hook into form actions with your JavaScript, or even add AlpineJS directly to your forms. Compatible with FieldtypeFormSelect, let users choose which forms to embed, your code determines how they are rendered Uses HTMX, a stable, powerful, and tiny (14kb gzipped) library, installation documentation available here This module is BYOH (Bring Your Own HTMX) in that the HTMX library is not included or available within this module. This ensures long-term stability by not locking FormBuilderHtmx to external asset versioning. FormBuilderHtmx uses stable core HTMX features so use the library version that works for you and confidently add this module to both new, existing, and future ProcessWire applications. In some instances CSRF protection may need to be disabled to submit forms with this module. Just test your forms and you're good to go. Using this module is truly easy. <!-- Replace the native $forms->render() method with $htmxForms->render() --> <?php $htmxForm = $htmxForms->render('your_form_name') ?> <!-- Use native ProcessWire properties and methods as usual --> <?php echo $htmxForm->styles; echo $htmxForm->scripts; echo $htmxForm; ?> Presto. You can optionally include a helpful 'spinner' or activity animation that will be showed to users while their form request is being processed. Check out these ready-to-go examples you can use in your projects. <style> /* Add these styles to your CSS, the `.htmx-request` must be present as shown here. Be sure to include any CSS your 'spinner' may need, and style everything as desired */ .activity-indicator { display: none; } .htmx-request .activity-indicator, .htmx-request.activity-indicator { display: block; } </style> <!-- Optional second argument matches that of the $forms->render() method for pre-populated values The third argument is the CSS selector matching your 'spinner' element --> <?= $htmxForms->render('your_form_name', [], '#indicator-for-the-form') ?> <div id="indicator-for-the-form" class="activity-indicator"> <span class="spinner"></span> </div> Presto (again) Check out the documentation for detailed usage and other available features. Pull requests and issues filed on Github are welcome, or drop by here to get some help! Install as a ProcessWire module Install using Composer Download from the FormBuilderHtmx Github repository . Cheers!
    1 point
  5. New version pushed. This resolves several issues and also adds expected features. The $htmxForms->render() method is now a true drop-in replacement. All methods/properties available on $forms->render() are available. The $htmxForms render method returns the original object expected from $forms->render(), so FormBuilder scripts and styles can be used The same form can be used multiple times on the same page when all are rendered using FormBuilderHtmx, each separately tracks state/errors/submissions Has more thorough checking for form submissions to detect HTMX form submissions vs. traditional form submissions Resolves issue where the full page markup was appearing in place of the form in some instances when submitting A note on multiple instances of the same form on one page- if one is rendered using FormBuilder and a submission has errors, all instances of that form will show those errors regardless if rendered using FormBuilder or FormBuilderHtmx. This is a core behavior of FormBuilder AFAIK and is not something introduced by FormBuilderHtmx. A benefit to rendering multiple instances of the same form using FormBuilderHtmx is that each form is individually processed. Have done a lot of testing with great results, but as always, community testing and feedback is appreciated! Available for download via the Github repo. @gornycreative & @Sanyaissues let me know if this fixes the issues you're seeing.
    1 point
  6. Just working on a new module for a customer who is concerned about the wire frontend cookie set w/o prior consent by the user. The customer uses frontend forms which require session cookies (wire) e.g. for CSRF checks, input validation, failed attempt restrictions etc. So he wanted to show a cookie dialogue asking for consent for technical required cookies, even if this is not 100% required by the DSGVO. First used a modified PrivacyCookie module to achieve this, before I went to create a minimalistic module myself. My module hooks before page::render and adds a cookie consent dialogue which asks for consent for technical required cookies and shows an Accept/Decline button and links to imprint and privacy policy sites. My module also hooks into $config->sessionAllow and sets it to true if user gave consent, requested a backend page or a wire session already exists. This way wire cookie is only created in frontend if user gave consent. On the form page of my customers site the display and processing of the frontend form is wrapped in a $session->hasCookie() block to execute only after user gave consent. Without consent a message is shown that using the form requires cookies. By default the consent cookie is stored for 7 days if accepted, so the cookie dialogue won‘t show up on next visit unless user cleared cache. If user declined, the consent cookie expires after the browser session so the cookie banner pops up again on next browser session. So who may be using this module? Clients only using technical required cookies by default (no google fonts, youtube etc.) maybe with an optional frontend form, which are still afraid or simply want to have a cookie consent dialogue before the PW wire frontend cookie gets created. Will do some more tests and polishing, before uploading the module to my Github repository.
    1 point
  7. I know very little about multi-language development in PW, but just to confirm: are you using the FieldtypeURLLanguage module? It's created by Ryan but is different from the core FieldtypeURL module.
    1 point
×
×
  • Create New...