Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 07/08/2022 in all areas

  1. Integrate plausible analytics or umami into your ProcessWire backend https://processwire.com/modules/rock-analytics/ https://github.com/baumrock/RockAnalytics Quickstart: Install the module Setup plausible analytics (either self hosted or paid cloud) Copy the tracking code into your site's markup Copy the share URL to your module's config Donations ??? About plausible analytics Plausible is a "simple and privacy-friendly Google Analytics alternative". It is open source and you can either self host it or buy one of their hosted services. A live demo of their dashboard and its features can be found here: https://plausible.io/plausible.io Tracking Snippet When you add a website to your plausible dashboard it will show you a tracking code that you can paste into your site that you want to track. This is what I use to make sure that we only track users on the live site (not on local development) and only logged in users: if(!$user->isLoggedin()) { $src = "https://plausible.verdino.com/js/plausible.js"; echo "<script defer data-domain='{$config->httpHost}' src='$src'></script>"; } Providing a dynamic domain is handy because during development you can add a second website to your dashboard and see if everything works without messing up data of your live site account. Example: We want to track the site "example.com", so we add this site to our plausible dashboard. Then we add the snippet with the dynamic domain attribute. On local development we have the host "example.com.ddev.site" so all visits will not show up in the plausible dashboard for example.com; Now we add another website to plausible with the domain "example.com.ddev.site" and voila - we will see our dev-websites' visitors in realtime. Backend Menu Item By default RockAnalytics will create a menu item at the top level of your backend menu, but you can move that page to any place you like. For example you could move the analytics page under the "setup" page at the top of the screenshot. You can also rename the page if you don't like the label "Analytics".
    8 points
  2. Just a quick update this week. The dev branch version is now at 3.0.202 as of today. Relative to 3.0.201 this includes 22 commits of various fixes, issue resolutions, improvements and additions. While there's nothing major that's new to report in this version, there is nonetheless quite a bit there, and if you are already running on the dev branch it's a worthwhile upgrade. For full details be sure to see the dev branch commit log. Thanks for reading and have a great weekend!
    5 points
  3. ProcessWire does not use a favicon in the admin backend. I usually insert a PNG-based one of the ProcessWire P logo to differentiate the frontend and backend of a site, however I upgraded my technique to use an SVG-based one, which has the added benefit of being able to quickly set the fill color. This is a nice trick, especially if you're working in multiple admin backends of different sites and want to be able to quickly identify which tab belongs to which site by the ProcessWire favicon color alone. Insert this in /site/templates/admin.php: wire('adminTheme')->addExtraMarkup('head', "<link type=\"image/svg+xml\" rel=\"shortcut icon\" href=\"data:image/svg+xml,%3Csvg width='256' height='256' viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='#EB1D61' fill-rule='nonzero' d='M234.02346,56.2065308 C226.258185,44.611679 213.340949,31.3634673 200.370381,22.7873303 C173.426584,4.33370224 142.216153,-2.21573572 114.611028,0.642976614 C85.8219124,3.7470262 61.1714319,14.5951995 40.9049183,32.6861551 C22.1317268,49.454423 9.73715371,69.9560838 4.27586162,89.5083961 C-1.24942998,109.060708 -0.513435538,127.162331 1.45988289,140.794549 C3.53986718,154.629436 10.4304818,172.037714 10.4304818,172.037714 C11.8384712,175.376434 13.7904564,176.731123 14.8037821,177.296465 C19.8384108,180.048509 28.105015,177.627137 34.4516337,170.50169 C34.7716313,170.06435 34.9422967,169.45634 34.7716313,168.944332 C33.000978,162.128223 32.3609828,156.997474 31.7316543,153.029411 C30.2916651,145.178619 29.65167,132.026409 30.6116627,119.866214 C31.0916591,113.284776 32.3716494,106.244663 34.6116325,98.8632122 C38.9422665,84.281646 48.0728642,69.0600695 62.3447564,56.4092007 C77.715307,42.7876498 97.4271581,34.3715154 116.16835,32.1954806 C122.738967,31.4061347 135.240206,30.6487893 150.290759,34.3608485 C153.501401,35.1608613 167.282631,38.7555854 182.023853,48.7397449 C192.754438,56.0358614 201.394373,65.0386719 207.346328,73.9454809 C213.404949,82.44695 219.986232,96.783179 221.916885,107.279347 C224.647531,119.226204 224.647531,131.88774 222.706212,144.218603 C220.30623,156.570801 215.975596,168.581659 209.24498,179.152495 C204.605015,187.344626 194.983755,198.171465 183.613174,206.299595 C173.362585,213.510377 161.66134,218.715793 149.650764,221.595839 C143.57081,223.035862 137.469522,223.95321 131.218903,224.15588 C125.661612,224.32655 118.291001,224.15588 113.117706,223.2812 C105.427098,222.054513 103.82711,220.091815 102.067123,217.425106 C102.067123,217.425106 100.840466,215.505075 100.499135,210.36366 C100.616467,163.376243 100.595134,175.920443 100.595134,151.525387 C100.595134,144.63461 100.371136,138.383844 100.435135,132.709086 C100.755133,123.396937 101.54446,116.996835 108.20041,110.063391 C113.01104,104.953976 119.741656,101.87126 127.154934,101.87126 C129.405583,101.87126 137.160191,101.977929 143.97614,107.642019 C151.282751,113.74345 152.509409,122.084916 152.797407,124.314285 C154.461394,137.359827 145.842792,147.077316 142.536151,149.541355 C138.440182,152.613404 134.760209,154.106761 132.274895,154.981442 C126.984268,156.752137 121.170979,157.264145 115.944352,156.922806 C115.144358,156.869472 114.41903,157.392147 114.259031,158.19216 L112.499044,167.322972 C110.781724,174.256417 114.632361,176.795124 116.872345,177.691138 C124.029624,179.899173 130.376243,180.816521 137.896186,180.251179 C149.426765,179.440499 160.797346,174.896427 170.450607,165.893616 C178.663878,158.085492 183.346509,148.453338 184.946497,137.679832 C186.546485,125.722308 184.466501,112.847436 179.015875,101.945928 C173.021254,89.9244028 162.674665,79.8869091 149.042768,74.393488 C135.272206,68.9747348 124.317622,68.7827317 110.195062,72.3881226 L110.035063,72.4414568 C100.861799,75.5988406 93.0111915,79.4922361 84.8405865,87.9297042 C79.2406288,93.7537973 74.6539968,100.804577 71.8593512,108.762037 C69.0860388,116.783498 68.3393778,122.767594 68.2113788,132.069076 C68.0407134,138.959853 68.3713775,145.359955 68.3713775,151.354717 L68.3713775,190.832681 C68.3713775,203.462216 67.9447141,205.648918 68.3713775,212.145022 C68.6060424,216.454424 69.2033713,221.329168 71.091357,226.566585 C73.0326757,232.337344 77.1073116,238.257439 79.9019571,240.988149 C83.8165942,245.158882 88.7978899,248.508269 93.693853,250.588302 C104.904435,255.569715 120.125653,256.359061 132.466893,255.879054 C140.637498,255.569715 148.85077,254.439031 156.904042,252.529667 C173.010587,248.700272 188.477137,241.734828 202.077034,232.070673 C216.658258,221.798509 229.330162,207.782285 236.327442,195.878095 C245.298041,181.733869 251.100664,165.861616 254.119308,149.552022 C256.839287,133.210428 256.711288,116.452827 253.063316,100.356569 C250.183338,85.4229975 242.492729,69.0387358 233.61813,55.8118579 L234.02346,56.2065308 Z'%3E%3C/path%3E%3C/svg%3E%0A\">"); Replace the fill color (#EB1D61 -- the PW pink color) with your own brand color if needed. Note: this is not tested on Safari (doesn't support svg favicons) so make sure to implement a proper fallback if that's important to you.
    3 points
  4. Personally I'm a big fan of Form Builder and there are very few cases where I wouldn't use it. The builder and built-in actions are super flexible, it's often a requirement (or at least preferable) for site admins (content editors) to be able to customize the form, and by adding some hooks one can achieve pretty much anything with it. As it happens, I've also built a few e-commerce checkout forms with it, and would definitely do it again ?‍♂️ Cases where I usually go with a custom form are one-off cases with heavy focus on accessibility, super specific layout requirements, mostly custom inputs (which are of course possible to handle with Form Builder, but not exactly straightforward), or loads of custom JavaScript logic. I'll admit that this is quite opinionated, but I've never found the API way of generating forms particularly useful: for me at least markup is both easier and faster to generate without it (particularly if there are specific requirements), validation is in most cases a relatively minor issue — unless it's a very complex setup, in which case there are brilliant third party tools available — and core features such as $session->CSRF->renderInput() and $session->CSRF->hasValidToken() work just fine without it. Long story short: it's either Form Builder or custom form implementation for me ?
    3 points
  5. I looked at my HTML output today and all this chaotic whitespace triggered my OCD. This module simply hooks into Page::render and removes whitespaces from frontend HTML with a simple regex replace. I mostly put this together for cosmetics. I like my View source neat and tidy. This is not well tested yet, please open an issue if you run into problems. GitHub: https://github.com/timohausmann/MinifyPageRender
    2 points
  6. I heard back from Ryan via email:
    2 points
  7. Hello friends! I have another module for you, which will make your daily work as a Processwire developer easier. Introducing: AppApi This module helps you to create api-endpoints, to which an app or an external service can connect to. Features Simple routing definition Authentication - Three different authentication-mechanisms are ready to use. Access-management via UI Multiple different applications with unique access-rights and authentication-mechanisms can be defined The documentation has become quite extensive, so have a look at the Github repository for details: Installation Defining Applications Api-Keys PHP-Session (Recommended for on-site usage) Single JWT (Recommended for external server-calls) Double JWT (Recommended for apps) Creating Endpoints Output Formatting Error Handling Example: Listing Users Example: Universal Twack Api Routes Page Handlers File Handlers A special thanks goes to Thomas Aull , whose module RestApi was the starting point to this project. This module is not meant to replace this module because it does a great job. But if you want to connect and manage multiple apps or need other authentication methods, this module might help you. I am already very curious about your feedback and would be glad if the module helps you a little bit.
    1 point
  8. Modules directory: https://processwire.com/modules/page-render-find-replace/ GitHub: https://github.com/teppokoivula/PageRenderFindReplace This module applies replacement patterns defined via TextformatterFindReplace globally to page rendering. All the heavy lifting is done by TextformatterFindReplace (thanks, Ryan!) so this module is just a wrapper around said module plus a bunch of config settings — a few options for selecting matching pages, an option to log replacements as they happen, etc. Long story short, on recent projects I've been running into issues with temporary (development) domain creeping into URLs here and there. While not a major issue, this is annoying and takes some time to correct. Originally I was thinking of building a module that would handle text replacements and log them so that they can be manually fixed later, but TextformatterFindReplace already handles the replacement part quite nicely, so I figured I'd just make use of it, apply replacements to rendered page content instead of individual fields (works better for my use cases, where content is often rather dynamic), and add some logging. Hope someone will find this useful. Please note, though, that this module is not well tested yet so there may be bugs etc. ?
    1 point
  9. Hello, @Mats! There is a problem with usage of this field when it is being added inside Repeater. The map does not load when I click to Repeater item since Leaflet's JavaScript is not being initialized after AJAX request. Can you please fix it?
    1 point
  10. One option is to put them in a single directory. Some may see this as being less elegant, of course. Personally I don't mind, and have done that on multiple occasions ? That being said, I would assume the modules directory to be fine with it as long as there's a module file and/or separate info file for the main module in the root directory, with any "additional modules" in their own subdirectories. Though this is largely guesswork, as I'm not familiar with the way the GitHub parser in modules directory actually works. I've seen quite a few cases where the repository name doesn't match the module name (or has a prefix, such as processwire-[module name]) so I'd be surprised if that's the issue.
    1 point
  11. The author of Alpine.js and Alpine Components (Caleb Porzio) mentioned the following in an email announcement today: So, that will in fact be a fourth option. ? Works for me.
    1 point
  12. "Allowed memory size exhausted" is often a sign of a loop somewhere, but in this case it's more likely just an issue with your hosting environment or PHP configuration: 16777216 bytes = 16 megabytes, which is quite a small amount of memory. It's not surprising that it keeps running out. Is this an actual limit of your hosting package, or have you configured PHP to only use 16M? Either way I would recommend raising the limit to at least 64M, or preferably 128M.
    1 point
  13. That's an interesting topic and the reason why I built RockForms. I initially released it open source in 2018 (see forum post), but I've built a new version that is not public yet. The module tries to solve exactly the pain points that you mentioned @Jonathan Lahijani. It is a wrapper around Nette Forms which is a brilliant library for creating secure and powerful forms. It takes care of all the hard parts when dealing with user input (security, remembering filled fields etc) and it is the only library that I know that let's you write code ONCE and get both client-side and server-side validation rules. By including a small JS file you even get live validation / live feedback with custom error messages. In my opinion that is the best UX you can get. The drawback of such modules / approaches is always that it get's harder to control the markup of your forms. That's why I have put a lot of effort into making the forms as easily customisable as possible. This is an example that defines custom markup that places two fields into one single row using tailwindcss: $form->addSelect("salut", "Anrede", [ 'f' => 'Frau', 'm' => 'Herr', ]); $form->addText("degree", "Titel"); $form->addMarkup("<div class='md:grid grid-cols-2 md:space-x-6'>{salut}{degree}</div>"); Note that {salut} and {degree} get replaced by full field markup that holds all the necessary form magic (field error, live validation...). Also it works great with alpinejs and/or uikit because you can easily set custom attributes: $form->setHtmlAttribute("x-data", "{affiliate:false, azubi:false}"); ... $form->addCheckbox("affiliate", "Ich bin Anschlussmitglied") ->setHtmlAttribute("x-model", "affiliate"); You don't need JQuery on your frontend - you can use the tools you want. And you get forms that fit 100% to the rest of your site. ?
    1 point
  14. Probably the first step of "Add module"... ...should be updated to include any rules about how the repo needs to be organised. @ryan But most modules that I've seen abide by the following principles, so that's probably a good way to go: 1. Name the repo the same as the module, in your case "ProcessIndieAuth". 2. Put the module files and readme in the top level of the repo. Includes or assets could go in subfolders when needed.
    1 point
  15. Quick update! Thanks to your suggestion @Robin S, I could make it work without having to redirect to the child page. Here is the adjustments I came up with, I changed the action of the form to action='{$post->url}?submit_a_comment=1' Parent page template: <?php $form = $post->comments->getCommentForm([ 'className' => 'CommentFormCustom', ]); $formMarkup = " <form class='{form.class} discussions_message ' id='my-comment-form' action='{$post->url}?submit_a_comment=1' method='{form.method}' {form.attrs}> <div class='avatar'>"; // just added if(count($user->images)){ $imgUrl = $user->images->last()->url; } else{ $imgUrl = $user->url; } $formMarkup .= "<img src='{$imgUrl}' data-src='{$imgUrl}'>"; // end $formMarkup .= " </div> <p class='{cite.wrap.class}'> <label class='{label.class}'> <span class='{label.span.class}'>{cite.label}</span> <textarea name='{cite.input.name}' class='{cite.input.class}' required='required' value='{cite.input.value}' >{cite.input.value}</textarea> </label> </p> <p class='{email.wrap.class}'> <label class='{label.class}'> <span class='{label.span.class}'>{email.label}</span> <textarea name='{email.input.name}' class='{email.input.class}' required='required' value='{email.input.value}' >{email.input.value}</textarea> </label> </p> {if.website} <p class='{website.wrap.class}'> <label class='{label.class}'> <span class='{label.span.class}'>{website.label}</span> <input type='text' name='{website.input.name}' class='{website.input.class}' value='{website.input.value}' maxlength='255' /> </label> </p> {endif.website} {if.stars} <p class='{stars.wrap.class}' {stars.wrap.attrs}> <label class='{label.class}'> <span class='{label.span.class}'>{stars.label}</span> {stars.markup} </label> </p> {endif.stars} {if.honeypot} <p class='{honeypot.wrap.class}'> <label> <span>{honeypot.label}</span> <input type='text' name='{honeypot.input.name}' value='{honeypot.input.value}' size='3' /> </label> </p> {endif.honeypot} <p class='{text.wrap.class}'> <label class='{label.class}'> <textarea style='border: 1.5px solid !important;' name='text' class='{text.input.class} my-comment my-new-comment' required='required' rows='{text.input.rows}' cols='{text.input.cols}'>{text.input.value}</textarea> </label> </p> {if.notify} <p class='{notify.wrap.class}'> <label class='{notify.label.class}'> <span class='{notify.label.span.class}'>{notify.label}</span> </label> <label class='{notify.input.label.class}'> <input class='{notify.input.class}' type='radio' name='{notify.input.name}' checked='checked' value='{notify.input.off.value}' {notify.input.off.checked}/> {notify.input.off.label} </label> {if.notify.replies} <label class='{notify.input.label.class}'> <input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.replies.value}' {notify.input.replies.checked}/> {notify.input.replies.label} </label> {endif.notify.replies} {if.notify.all} <label class='{notify.input.label.class}'> <input class='{notify.input.class}' type='radio' name='{notify.input.name}' value='{notify.input.all.value}' {notify.input.all.checked}/> {notify.input.all.label} </label> {endif.notify.all} </p> {endif.notify} <p class='{submit.wrap.class}'> <button type='submit' class='{submit.input.class} button' name='{submit.input.name}' value='{submit.input.value}'>Reply</button> {form.hidden.inputs} </p> </form> "; $form->markup('form', $formMarkup); $form->labels('submit', 'Submit Feedback'); $form->labels('notify', 'Email Me'); // form notifications $form->markup('notification', "<div class='uk-alert {class}'>{message}</div>"); $form->classes('success', 'uk-alert-success'); $form->classes('pending', 'uk-alert-warning'); $form->classes('error', 'uk-alert-danger'); echo $form->render(); ?> Child page template: <?php // Show the comment form echo $page->comments->renderForm(); // If the submit_a_comment URL parameter is not present then redirect to parent page // This must go after the form render so that comment submissions will be processed before redirecting if(!$input->get('submit_a_comment')) $session->redirect($page->parent->url); ?> Comments are now adding to the right child without redirecting! Thank you so much for your time and help. This community is amazing!
    1 point
  16. I've just recoded a brief video where I've tried to explain how to install tailwind inside Processwire ( really badly spoken ? , so be kind...) Moreover I've updated the gist here to reflect the changes I've made since the last time I've written the guide above. There you have it:
    1 point
  17. Hi everybody, just found this one today by coincidence and it looks quite great: https://ui.toast.com/tui-chart/ Has anybody of you ever tried it? Even with nice export features! ? AND: Convert HTML Tables to charts: https://github.com/nhnent/tui.chart/blob/master/docs/wiki/import-chart-data-from-existing-table-element.md
    1 point
  18. There is a difference between selectors used with PageFinder... $pages->find($selector), $page->children($selector), etc ...and selectors used in memory... $some_pagearray->find($selector) Any string that strtotime() understands can be used with a PageFinder selector, but with an in-memory selector you can only use timestamps. This is because when FieldtypeDatetime prepares the database query it actually passes the value through strtotime() if it isn't recognised as being an integer (timestamp) or a DateTime object. See here and here. But FieldtypeDatetime isn't involved with in-memory selectors so in such cases if you are working with a time string you'll need to convert it to a timestamp yourself.
    1 point
×
×
  • Create New...