Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


MoritzLost last won the day on November 24 2020

MoritzLost had the most liked content!

Community Reputation

785 Excellent

About MoritzLost

  • Rank
    Sr. Member

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location
    Cologne, Germany

Recent Profile Visitors

1,302 profile views
  1. Hi @psy, thanks for the tutorial. I've implemented workbox in the Architekturführer Köln project, though I used the Workbox webpack plugin to generate the service worker (which is easier for JavaScript-applications that use Webpack anyway, not for ProcessWire sites). A couple of things that stood out to me in your guide: What's the purpose of not including the service worker on the /offline.html page? Service workers have a seperate lifecycle from individual page visits. Once registered, they will stay active until replaced or manually removed. It shouldn't matter if the registration code is repeated on the offline fallback page. One way to improve the user experience would be to precache important pages, so they will be available offline even before the user has visited them! See https://developers.google.com/web/tools/workbox/modules/workbox-precaching The list of pages to precache could even be generated dynamically, maybe have a checkbox on all pages to allow them to be precached, expose that list to the service worker and take it from there ... Seems like you're jumping through many hoops just to avoid having a simple build step for your JavaScript code. I often see people shy away from JavaScript compilation and actually make their job much harder because of this, but your code could be much simplified with a simple JS build step that would take only a couple of lines of configuration to set up. This will make it much easier to use libraries like Workbox, since you can just follow the installation and setup guides without having to, for instance, find workarounds for imports. I've written a guide on how to setup a basic JavaScript build step with ParcelJS on processwire.dev, take a look if you're interested. (Admittedly, Parcel seems kinda dead, nowadays I would recommend using Webpack 5. Or Snowpack, which seems to be all the rage right now 🙂 ) Finally, and I know this may be personal preference, I feel like the whole "offline.html" thing is kinda ... superfluous? For an app / SPA, yes, I would expect a custom offline notification screen. But for a classic website with individual page loads, telling me I'm offline on a custom page with your logo on top doesn't really help me in any way, since it doesn't offer anything that the "you're offline" page of the browser can't …
  2. Great, thanks! I'll test it out on Monday 🙂
  3. @adrian Hi Adrian, tiny bug report, I get some PHP notices in the errors panel when I define a constant with an array value in my config.php: 2x PHP Notice: Array to string conversion in .../includes/GetTemplateResources.php:6 This is the corresponding line: \TracyDebugger::$templateConsts = array_diff_assoc(get_defined_constants(), \TracyDebugger::$initialConsts); I found this question on SO, apparently array_diff_assoc always throws this warning when given a multidimensional array, and get_defined_constants will be multidimensional if one of the constants is an array. Not sure how to properly fix this, maybe run through the defined constants and handle all constants with array values separately? It's not that big a deal, but the red error notice on the bottom is bugging me ^^ Here's an example of constants in my config.php that causes this error (slightly obfuscated): const MEMBER_TYPE_X = 123; const MEMBER_TYPE_Y = 456; const MEMBER_TYPE_Z = 789; const MEMBER_ACCESS_FIELDS = [ MEMBER_TYPE_X => 'access_x', MEMBER_TYPE_Y => 'access_y', MEMBER_TYPE_Z => 'access_z', ]; Can you take a look? Thanks!
  4. If the textarea contains exactly the same as your test string, preg_match will not work differently. There's probably some additional content in there, maybe some whitespace or even a hidden character from pasting or something like this. I'd try dumping both your test string and the value from the database next to each other and check them for differences. Besides that, the most likely cause are the issues with your regex explained above. I'd also recommend using urlencode or rawurlencode instead of str_replace to encode the URL part. What kind of output are you getting with the value from the database? No match at all, or does it match something it shouldn't?
  5. Have you checked if $link->textarea_short actually contains the HTML you assume? If the structure is slightly different, the regular expression will not match anymore. Besides that, there are some issues with your expression: https* – If you want to match either http or https, use a question mark. The asterisk will also match httpssssssss... (.*) – This will match any number of any characters, including the paragraph end tag (</p>). Depending on your content, this will yield unexpected results: If your textarea includes multiple paragraphs, the regular expression will match everything between the start of the link to the last closing paragraphs tag. You can rectify that problem using the U flag (PCRE_UNGREEDY) – preg_match is greedy by default, this will turn it ungreedy. But it may still cause Catastrophic Backtracking. A better solution would be to use [^<]*, which will match any characters except the lesser than sign (<), so it can't "skip" the closing tag. It will still capture any additional content between the link and the closing tag though. What are you trying to do in the first place? Looks like some sort of URL encoding, but why match the <p> tags as well? It would probably be easier to use preg_match_callback with urlencode to find any links and encode them ...
  6. My module TrelloWire module uses $page->meta as an easy, site-independent way to associate module data with a page. The module creates Trello cards for new pages, and can update them through Trello's API whenever the page is changed. To do this, the module needs to store the ID of the card associated with that page somewhere. Using $page->meta was the easiest option, much simpler than creating a custom database table or programmatically creating a field when the module is installed. The caveat is that the value can't be updated or deleted through the user interface. However, that could be achieved through hooks. You can see how I store and use the page meta data in TrelloWire::createCardForPage and TrelloWire::buildCardData 🙂
  7. This is tricky because for the database "1,5m" is neither a word nor a number, so the comma is treated as a word boundary. This is why can't use selectors that make use of fulltext indexes (*=, ~=). The only option in this case is a slower LIKE comparison (%=), but that isn't aware of word boundaries, resulting in your problem with matching "11,5m" as well as "1,5m". A quick and dirty solution would be to include the space in your selector, but I'm not even sure if ProcessWire won't filter out any leading/trailing spaces in selector values: 'title%=" 1,5 m" The best solution is to turn the height of the tree into its own field which can be searched and compared properly. For the height, a simple integer field containing the height in centimeters would be appropriate. Then you can easily search for trees of a certain height, or even within a certain range of heights: // all trees that are exactly 1,5m high $trees = $pages->find('template=tree, height_cm=150'); // all trees that are between 1 and 2 meters high $trees => $pages->find('template=tree, height_cm>100, height_cm<200');
  8. Hi @Pip, thanks for reaching out, I think I know what the problem is. The module should work with any number of templates and on any number of fields. However, before creating a link for a given title, the module checks if the page the title belongs to is actually viewable. I made this the default because for a "normal" use case it doesn't make sense to create a link to a page the current user can't actually view. Based on your screenshots it looks like you display all hero abilities on the page for that hero, so I'm guessing the hero abilities don't have their own sub-pages in the frontend? If there's no hero-ability.php template, no hero-ability pages will be viewable, so the module will not create any links for those. In version 4.0.0 of the module I added a checkbox to disable the viewable checks for use cases like this one. Your screenshot looks like your site has an older version installed, so make sure to update to the latest version if you don't see the checkbox. After the update the option should appear in the new configuration fieldset Markup and output settings. By the way if my assumption is correct, you may want to use the hook TextformatterPageTitleLinks::buildTitleMarkup to modify the link for hero-ability pages to point to that ability on the hero page instead (using anchor links). See my answer here for details. If that doesn't solve the problem: I've written a bit about how to check what the module is doing in my answer here, use that to determine whether the module (a) is not finding the desired titles or (b) is finding the titles but not creating links for them. This can help you find out what's going wrong. Let me know if you need more help!
  9. @horst Hm that's interesting, though I'm not sure if that would be enough for me to call it a day ... I've found that in many cases the Datenschutzbeauftragte don't have a solid grasp on the technologies and what actually constitutes PII, so they basically judge compliance of a tracking mechanism based on whether it sets cookies or not. Even though fingerprinting is much more perversive and there's no real opt-out for that. I'm also fairly certain that using Matomo with cookies requires consent under GDPR – since it allows you to identify returning visitors, you can collect pseudonymous information, which requires consent. I'm surprised the Datenschutzbeauftragte of NRW would make such a blanket statement, and I don't think it would hold up in court (not sure if the written statement would help there, I'm not a lawyer 🙃). But even without cookies, it's a gray area at best. The reason people jump on the cookie debate while ignoring other mechanisms such as fingerprinting is probably because the legal precent (most notable the EUGH decisions) have mostly been about cookies. So right now there's a grey area regarding fingerprinting. But I think as soon as there's a test case / precedent fingerprinting will be shut down the same way consent-less tracking cookies were shut down. Anyway, regardless of the current legality I think it's a good approach to drop cookies and fingerprinting in favor of referrers to differentiate between visits and page views (as Cloudflare claims they do). Though we'll see how well it works and if it's as privacy-friendly as they claim 🙂
  10. Cloudflare announced the general availability of their new Web Analytics solution today (even for non-Cloudflare-powered sites): https://blog.cloudflare.com/privacy-first-web-analytics/ I'm quite excited about this, as I've been looking for a solution that's both privacy-friendly, free for personal sites and GDPR compliance. In particular, being able to collect visitor statistics without tracking any personal data is an attractive proposition, since it doesn't require consent even under the GDRP. I looked at various alternatives, but all have their caveats: Google Analytics is out for obvious reasons. Matomo is a solid choice since it can be configured to not set any cookies and anonymize IP addresses. However, it's use of fingerprinting is somewhat dubious, so it's a grey area whether you need consent to use it. A couple smaller alternatives like Netlify Analytics (for Netlify sites) or fathom look good enough, but their pricing isn't really feasible for small personal projects. I have added the Cloudflare tracking script to my tutorial site processwire.dev, for now I'll use it alongside Matomo. Will be interesting to see how their numbers compare to Matomo. What do you all think? Are there better alternatives out there?
  11. For a production site, I wouldn't use PHP 8 yet. It hasn't been enough time to find issues with ProcessWire, as well as for module authors to fix new issues. Is your site up-to-date? Current PW master version, all modules up-to-date and no abandoned modules in use? In this case, PHP 7.4 is very stable, works well with current ProcessWire versions and will be supported for another two years. We've been using it for a while now, so I can say that at least the core and our commonly used modules (ProFields, FormBuilder, ListerPro, LoginRegisterPro, ProCache, Tracy Debugger and all of my modules 🙃) work well with PHP 7.4. Through I would be vary if your site uses some abandoned or older modules, especially 7.2 and 7.4 introduced some backwards incompatible syntax changes that often cause issues with older code ... On a development site, go ahead and try PHP 8, and report any problems so they can be fixed. At work I'll install PHP 8 on our development server as soon as it's available in Plesk, and give our ProcessWire base installation a try 🙂 Looking forward to union types and match expressions in particular ...
  12. @mel47 Hi Mel, glad the module is working well for you! You can change the way links are created or prevent them entirely using the hook TextformatterPageTitleLinks::buildTitleMarkup (see the link for the documentation). This method is called for every title found in a text field and returns the HTML to replace the link. You can overwrite this to just return the title in certain conditions, which means no link will be created. Here's a hook that will keep track of which titles have already been linked and prevent more than one link per occurance of each page title: // limit automatic links to one per individual title, even if the title appears multiple times on the page wire()->addHookAfter('TextformatterPageTitleLinks::buildTitleMarkup', function (HookEvent $e) { $title = $e->arguments(0); $page = $e->arguments(1); $options = $e->arguments(2); // keep track of all the titles that have already been linked static $alreadyLinkedTitles = []; if (in_array($title, $alreadyLinkedTitles)) { // if the title has already been linked, overwrite the HTML markup with the plain title $e->return = $title; } else { // otherwise, just add the title to the array of linked titles $alreadyLinkedTitles[] = $title; } }); A couple of caveats: The static array will not distinguish between fields, so this will limit the automatic links to one link per title on the whole page, not one link per title within one field (though it sounds like this is what you want). If you access the same field multiple times in your template, it will only contain links the first time. Another solution, if the word you're repeating multiple times is very short, you can just use the minimum length setting to prevent it getting linked, or use the hook above to prevent automatic links for a few specific pages. I hope this works for you! If you need even more fine control, it might be simpler to create the links manually or use another module as suggested by @bernhard.
  13. Thanks for the detailed response @Robin S! That's exactly what I was looking for, I'll use that. Would be nice to be able to go without passing the current $page in, but I understand why it's required, I guess it doesn't matter 🙂
  14. I want to display all options (i.e. all selectable pages) of a page reference field in the frontend. Normally I would access the available options through the fieldgroup of the page's template like this: $options = $page->template->fieldgroup ->getField('my_page_ref_field') ->getInputfield($page) ->getSelectablePages($page); However, now I need to get the options of a field which is part of a repeater, so it doesn't exist in the current page's fieldgroup. I managed to get the selectable pages through the repeater field's template: $options = $templates->get('repeater_with_my_field') ->fieldgroup ->getField('my_page_ref_field') ->getInputfield($page) ->getSelectablePages($page); However, I don't like this solution. It depends on the field being part of the specified repeater field, which might change in the future. Also, I'm passing in $page which isn't really correct since the $page doesn't have that field. Not sure if this will cause problems, but it feels wrong. Is there a better way to get the selectable pages without the context of a page / template / fieldgroup?
  15. Preloads should go in the <head> of your HTML, before most of your other assets, so they can be discovered and preloaded very early. The root of your FOUT issue lies somewhere else, however. The problem is that you're only preloading the CSS file from Google Fonts, but not the fonts themselves. Check out the CSS file you're preloading - it's only 9 lines! So preloading this will have a negligable effect (DNS preconnect or prefetch would be more useful in this case). That's because the CSS file only includes the @font-face definition which includes the URL to the actual font file. In modern browsers, this will be a woff2 file - this is what you want to preload. One caveat of this is that older browsers which don't support woff2 will receive a different font file in a different format, so those users will have preloaded the woff2 gratuitously. On the other hand, if you add preloads for all available font formats, everyone will receive multiple files they don't need. Personally, I would only preload the woff2 file. I would also recommend hosting the fonts locally - if you're in the EU, this is kind of necessary for GDPR compliance. And since Browsers nowadays have segmented caches anyways, loading the fonts from Google isn't that much faster. It also helps to have a predictable URL to preload the font from - if you preload the font file from Google, the preload will break any time a new version of the font is released (see the version number in the URL above ...).
  • Create New...