Jump to content

JayGee

Members
  • Posts

    278
  • Joined

  • Last visited

Posts posted by JayGee

  1. 10 minutes ago, nbcommunication said:

    Hi @JayGee,

    My main concern with this approach would be usability for users that are the opposite of bots - e.g. older, less tech savvy users ("I tried to but I couldn't see the form") - but I think a text prompt with the captcha would remedy this. There might also be issues with cumulative layout shift, if this is a concern then rendering a placeholder of the size of the rendered form with the captcha sitting on top of that might solve that.

    What I would say is that if I were developing this, I probably wouldn't piggy back on this module and instead use it as a reference for another module written from scratch. This module is just a turnstile version of the MarkupGoogleRecaptcha module, built to facilitate an easy switch from using reCAPTCHA to Turnstile. That said, if it does what you need it to do for your use case then that's great!

    I do like the idea of only rendering the form once the captcha has been passed though, I'm sure there must be some UX research / opinion about this but couldn't find any with a quick search. Do let us know how you get on!

    Cheers,

    Chris

    Hi Chris,

    Thanks for your input.

    We were also concerned about cumulative layout shift - but I think this can be fixed by setting heights on placeholders etc. We were focussed only on solving the immediate problem in hand... bots!! I've also thought we could have a dummy form with the same fields etc but no logic/action and switch them out following validation.

    FWIW it seems to be working so far too 🤞.

    In terms of UX - yes we were unsure if this was really the 'right thing' to do - but in my opinion it's not to dissimilar in approach to Cloudflare's standard bot mitigation approach where the whole page is prevented from rendering. I think for ease and speed of deployment to address specific issues, the trade-offs are worth it.

    We'll keep this forked as a separate module for the moment.

  2. 11 hours ago, bernhard said:

    Would be great if you could share how you use it. That's probably easier/faster than creating a module and could also be helpful/interesting 🙂 

    There’s not a huge amount to tell (currently), we’re using it in a very simple way.

    So if a client needs a lot of video on their site we’ll provision a library for their site in our Bunny account rather than using Yotube embeds (or similar). We then embed videos to the site using a ‘video block’ in repeater matrix with the video loaded by its Bunny ID.

    Specifically we use Bunny’s stream platform which provides encoding to multiple formats/resolutions/sizes for different devices, analytics, geolocation options, customisable player etc and then optimised delivery to the site visitor.

    At the moment video upload is manual via their dashboard, however they have a full upload API hence the plan to explore doing this via a module soon.

    They do provide things like edge caching, DNS and a standard CDN too (I believe Stream is built on top of their CDN) which I why I think it could be used with ProCache. I’m just not sure if you go down this route how you simultaneously achieve the benefits of the stream player etc - I still need to test this to determine if a separate module is needed or not.

    • Thanks 1
  3. We use Bunny CDN for an increasing number of projects - it’s cheap and reliable.

    Planning on making a module when I get a chance too to enable upload to their CDN from inside ProcessWire.

    Although I think this may already be possible via ProCache - not had a chance to check yet though.

    • Like 1
  4. On 11/6/2024 at 9:56 PM, JayGee said:

    Hi @adrian - just wondering with your module is there a way to configure the whole site to be protected, but to exclude one particular page from protection? I can't see a way to do this without having to configure every page 1 by 1, unless I'm missing a trick?

    Hi @adrian I just wanted to share that this problem came up again today and I found a working resolution without needing to modify your module.

    We installed your module and enabled protection from the home page settings and checked to cover all children (essentially enabled site wide). We then moved the webhook APIs to a module using the URL hooks (hooked via init()) which allows them to bypass the site protection without unprotecting the rest of the site. 🙌

    I thought I'd share in case this is of use for anyone else in the same situation.

     

    • Like 1
  5. Hi all, I've been doing some work to extend this great module created by @nbcommunication to meet a specific need we have. This is very much as-yet untested in production, but I wanted to share it here now anyway in case anyone wants to point out any flaws in the logic, try out the changes or suggest improvements before we push it to any live sites or make a PR to NB.

    The challenge:
    We manage a number of sites where we would like to get forms behind Turnstile. But in many cases these forms are connected to or hosted by third-party CRMs/Email marketing platforms etc which makes integrating Turnstile tricky and time consuming.

    The proposed solution:
    Rather than modifying a plethora of different third-party form integrations 1-by-1 and verifying submissions with Cloudflare on submit, we'll remove the forms from the DOM and only render them once Turnstile verifies the site visitor. As mentioned this is as-yet untested so I've no idea how robust this will be against bots and scrapers, but it seems worth trying IMO!

    In case people are wondering why we wouldn't use Cloudflare's other bot mitigation tools - we don't control all site's DNS and not all sites run behind Cloudflare. Turnstile works regardless of whether the site uses Cloudflare nameservers.

    The approach:
    I've modified the Turnstile module with a few new methods to do the following:

    • Utilises @ryan's awesome URL hooks to create some endpoints to handle Turnstile token verification and:
    • Dynamic loading of HTML render files into a page only once the token is verified.
    • Use of data-attributes in page elements to specify the target location and file for rendering.

    Forked branch available here: https://github.com/warp-design/MarkupCloudflareTurnstile/tree/feature-protect-content-turnstile

    All probably best illustrated visually:

    Example page structure using a mix of the existing module methods and the new ones:

    <body>
    
        <?php
        //Load module in page
        $captcha = $modules->get('MarkupCloudflareTurnstile');
        ?>
    
        <!--
        Existing module widget render call.
        Set inside #turnstile-container to auto hide turnstile after verification
        -->
        <div id="turnstile-container">
            <?= $captcha->render(); ?>
        </div>
    
        <!--
        Elements you wish to protect with Turnstile.
        Set data attribute with render file path, relative to templates folder.
    	There divs will populate with the specified render files when Turnstile verifies.
         -->
        <div class="turnstile_content" data-render-path="inc/exampleForm"></div>
        <div class="turnstile_content" data-render-path="inc/exampleContent"></div>
    
        <!-- New method to load the scripts if you want to protect dom elements behind Turnstile -->
        <?= $captcha->renderProtectedContent(); ?>
    
        <!--Existing module script call-->
        <?= $captcha->getScript(); ?>
    
    </body>

    And how this page looks live. Note: .turnstile_content elements only populate when Turnstile is verified:

    Test - 11 December 2024 - Watch Video

    885fc50c24db4218a44a3d6dd5e9b417-4f16a8f0956978b7-full-play.gif

     

     

    Let me know what you think - is this a workable approach, or am I overlooking pitfalls?

    Likely issues/TODOs you may encounter:

    • Things may need more sanitization and better error handling to come out during testing.
    • Not sure how this will behave when loading in external JS. I've tried to ensure it will initialise any scripts in the render files when they are loaded. In theory things shouldn't be too different to loading content with frameworks or something like HTMX.
    • Would be nice to eventually add support for passings $vars and $options params to the render files like any other PW template call.
    • Someone may have already implemented the above in another module and I hadn't noticed! 😅
  6. I'm building a custom module for project that will leverage LazyCron.

    I can't seem to find how you tell your module that LazyCron is required?

    I've tried adding the following to my getModuleInfo()

    'requires' => [
    	'LazyCron'
    ],

    and have also tried adding the following that ChatGPT suggested... but not sure if it has made up this syntax as I've not seen it before?!

    'requires' => [
    	'ProcessWire:LazyCron'
    ],

    Either way I get the error:
    ProcessModule: Error reported by web service: That module is not currently tracked by the modules directory

     

    In an ideal world I'd just enable the core module from my own module, is this possible?

  7. 15 hours ago, adrian said:

    @JayGee - not currently. I wonder if the best option might be to make protectedCheck() hookable and then you could add an exception for the required page via a hook in ready.php

     

    Thanks @adrian for confirming I wasn't overlooking something obvious at least!

    The use case was to protect a staging site but allow certain routes for webhooks/APIs etc. Have worked around it for the moment using basic auth at server level, but it would be a handy feature. Will add it to the backlog and have a look at forking it and making a mod when get some time 🙂 

  8. Hi @adrian - just wondering with your module is there a way to configure the whole site to be protected, but to exclude one particular page from protection? I can't see a way to do this without having to configure every page 1 by 1, unless I'm missing a trick?

  9. 12 hours ago, FireWire said:

    @JayGee The module expects Method C so your markup should look something like this:

    <?php
    $htmxForm = $htmxForms->render('your_form_field');
    
    echo $htmxForm->styles;
    echo $htmxForm->scripts;
    echo $htmxForm;

    The module only swaps what's inside the form markup and shouldn't have any conflicts with scripts or styles.

    Option C has been the best option for me because I can add the styles and scripts once on the page wherever I want them rather than directly where forms are rendered. I throw the CSS file up in the <head> element and the scripts at the bottom near the closing <body> tag with my others.

    Ah ok perfect thanks - that explains it - I still need to add the form styles. 😎

    Thanks for the module and keep up the good work!

  10. 8 hours ago, JayGee said:

    Amazing thanks - will give that a test shortly and confirm back.

    I've had a moment to check now and can confirm the upgrade solves the issue and conditional fields now work. Although I'm seeing a slightly different issue - some of my styling on the form changes when using your render()method.

    At a glance I can't quite put my finger on what changes in the output to cause this - I think it could be to do with where in the page the scripts etc are injected vs. manually putting them into the template rather than a bug.

    Which embed method does your module use for the form render?

    (Sorry for the vague feedback!... up against a deadline and happy to test more for you later if it would be useful. 🙂) Great module though - super useful addition!

    • Like 1
  11. I would like to second the votes for greater developer tooling. Things like:

    • Being able to re-use the same field in a template.
    • Being able to more easily and natively version control template/field definitions.
      • Perhaps definition of template fields from inside the template code itself or page class?
    • Perhaps better support of raw html in template views vs. php files - maybe through an enhanced JS api for field content, or using data-attributes directly in html. This would smooth development pathways from front-end design/dev to backend with less reliance on local/dev php servers and more 'headless' functionality. (Obviously not a major hangup, but just a slight modernisation).
    • Like 3
  12. SOLVED - but I'll leave this here for anyone else to reference as I struggled to find examples.

    Long story short, I think I was massively overthinking it - with a bit of help from Chat GPT (!! Chat GPT know ProcessWire now - who knew!) I've got this:

     

    .....
    } elseif($field->type == 'FieldtypeRepeaterMatrix') {
                //HANDLE REPEATERS HERE
                $repeaterItems = $page->$field;
                foreach ($repeaterItems as $item) {
                    // Iterate over each field in the Repeater Matrix item
                    foreach ($item->fields as $subField) {
                        $subFieldName = $subField->name;
                        $subFieldValue = $item->get($subFieldName);
    
                        // Perform your modification here if the subfield is a string type
                        if (is_string($subFieldValue)) {
                            $modifiedValue = $this->replace_merge_tags($subFieldValue, $tags, $defaultTags);
                            // Save the modified content back to the item
                            $item->set($subFieldName, $modifiedValue);
                        }
                    }
                }
            }

     

    • Like 2
  13. I've got some code that is carrying out a basic find-and-replace operation on some page output. I'm hooking into the page render:

    $this->addHookBefore('Page::render', $this, 'renderOutput');

    Looping through the fields and modifying page output accordingly which is all working fine.

    The problem is I cannot figure out what approach I should be using for doing the same on repeater or repeater matrix fields in the page output. As far as I can tell Page::render hook doesn't fire for the repeater pages so I presume I need to loop through the matrix item sub fields at output.

    Does anyone have any guidance/examples - I can only find examples for hooking repeaters on CMS side rather than frontend output.

  14. DW - Found it ?‍♂️

    Had to add some logic to detect if we're already on the 404 page as my array check was broken because the data isn't present on the 404 (created a loop).

        if (array_key_exists($this->input->urlSegment1,$allVariantData)) 
    

    I'm now doing 

    if($page->id != 27) { //Wrap in condition to ensure this logic doesn't affect 404 pages

    is this the best way to detect a 404 page? Does the 404 ID ever change, or is this solid enough to rely on?

  15. I have an autoload module with the follow (abridged) code. The problem is that I cannot seem to throw the 404 error below. There's no page output prior to this point, so I can't see why this isn't working. Hoping someone else can!

    Hook via init()

    <?php
    public function init()
    {
      $this->addHookBefore('Page::render', $this, 'renderOutput');
    }

    my function:

    <?php
    public function renderOutput($event)
    {
     
      $variant = 'defaults';
      if ($this->input->urlSegment1) {
        if (array_key_exists($this->input->urlSegment1,$allVariantData)) {
          $variant = $this->input->urlSegment1;
        } else {
          throw new Wire404Exception(); //throw 404 to prevent made up variants resolving dynamic default data for 'pages' that don't exist
        }
      }
    
    }

     

    I've taken out the code not relevant to the issue but can confirm all the other logic and that around the url segments is all running as expected. I just get an exception when I try to call the 404 exception! 

  16. It would be cool to try and get something up and running. I think there's a growing awareness of PW and we pick up a few but ever increasing number of organic enquiries from people who have PW sites built for them by other people so it only seems natural they would check the PW website to find devs.

  17. 49 minutes ago, JayGee said:

    Thanks both, this all makes sense - I knew there would be a way I was overlooking!

    I think in all likelihood I'll use a combination of the 2 suggested selectors as there's no reason for me to touch anything in the admin folder:

    $non_system_templates = $templates->find("flags=0,!hasParent=2");

    I need to make sure I also exclude repeater templates. The reason this issue came up is because I'm adding a repeater field, and it got added to the repeater templates which caused an infinite loop when adding a repeater item! ?‍♂️

    On second thoughts - hasparent is a page selector isn't it rather than a template selector?

     

    EDIT:

    Can confirm this works perfectly for my scenario - thanks for your help @wbmnfktr and @Robin S:

    $templates = $this->templates->find("flags=0");

    Now I know of the existence of the template flag system this is really handy.
    For reference for anyone readying this in the future, checking the database I can see the standard templates all have flag 0 as implemented above. The admin repeater templates are all flag 8.

    • Like 1
  18. Thanks both, this all makes sense - I knew there would be a way I was overlooking!

    I think in all likelihood I'll use a combination of the 2 suggested selectors as there's no reason for me to touch anything in the admin folder:

    $non_system_templates = $templates->find("flags=0,!hasParent=2");

    I need to make sure I also exclude repeater templates. The reason this issue came up is because I'm adding a repeater field, and it got added to the repeater templates which caused an infinite loop when adding a repeater item! ?‍♂️

    • Like 1
  19. This feels like it should be simple but can't see it in the API docs.

    I want to loop through all a site's templates and add some fields via a module, but I don't want to touch admin templates.

    What's the best way to filter them? Is there a selector for $templates->find() like admin=false or similar?

×
×
  • Create New...