Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


MoritzLost last won the day on October 14

MoritzLost had the most liked content!

Community Reputation

675 Excellent

About MoritzLost

  • Rank
    Sr. Member

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location
    Cologne, Germany

Recent Profile Visitors

1,124 profile views
  1. https://processwire.com/api/ref/wire-array/import/ That's correct, the sort order of a page's children is relative to that level of hierarchy, not global. So by using pages->find with the sorting order you get weird results. I don't think there is a way to get a hierarchically ordered result in one query. Do you want your page array to be ordered depth-first (first page -> children of first page -> second page -> children of second page -> ...) or depth-first (first page -> second page -> ... -> children of first page -> children of second page -> ...)? I assume you just need your $articles variable to be a flat array of all pages in their page tree order, correct? I don't think it can be done in one query, but you can use WireArray::add and WireArray::import to create your flat array of pages. For depth-first order: $articles = new \ProcessWire\PageArray(); foreach ($page->children('template=event, hide_in_programm=0') as $article) { $articles->add($article); $children = $article->children('template=event, hide_in_programm=0'); if ($children->count()) { $articles->import($children); } } For breadth-first order: $articles = new \ProcessWire\PageArray(); $parents = $page->children('template=event, hide_in_programm=0'); $articles->import($parents); foreach ($parents as $article) { $children = $article->children('template=event, hide_in_programm=0'); if ($children->count()) { $articles->import($children); } }
  2. Just to go against the grain a bit: Those modules are way, way overkill for 99% of sites. Just looking at the screenshot in the Seo Maestro thread, all those options would confuse most of my clients. Who really wants or needs to manually edit the change frequency of a single page? Some of those options should also be generated automatically (Locale, based on the current language) or set globally (Site Name, for example). I get that you can control which fields to show and that it's kind of a framework which you can use for all kinds of sites. But in my experience, showing five screens of SEO settings on every page is the best way to get clients/editors to be scared of them and never use them. Three fields - title, description, preview image - are all you need most of the time. KISS. I would use external tools for this. There are many tools that are much better at this stuff than Yoast, and they look at the page as a whole, not just the body content. For example, at work we have at some points used the following tools among others, in no particular order: Ryte, Seobility, Semrush, Sistrix. And many more ...
  3. What do you mean by form output? Generelly, forms are used for input πŸ™‚ The first step is to determine which interactions you want to track. For example, you could track an event: ... whenever a form is successfully submitted. ... whenever a form is partially filled but then abandoned. ... each time somebody fills out an individual field (will result in many events). ... whenever somebody finishes an individual step of a multi-step form. Beyond that, you first need to determine what your client wants to know, in terms of specific metrics, interactions etc. Most of those you can do with simple event handlers reacting to form changes, inputs and button clicks. // find all formbuilder forms on the page const FormBuilderForms = Array.from(document.querySelectorAll('form.FormBuilder')); // track the submit button FormBuilderForms.forEach(form => form.addEventListener('submit', e => { // this assumes you're using gtag.js with transport mechanism 'beacon' gtag('event', 'form_submitted', {/** add additional information based on the form data */}); }); A bit more tricky is tracking submissions only after they've been validated server-side, since you can't catch that with JavaScript. However, after submitting a form you will usually show a success message or redirect to a dedicated thank you page, so you can just track those: // FormBuilder uses this ID for the submission message const FormBuilderSuccess = document.getElementById('FormBuilderSubmitted'); if (null !== FormBuilderSuccess) { gtag('event', 'form_submission_result', {/** track the name + result of this submission */}); } Does that answer your question? It's just a matter of determining what you want to track, and then adding appropriate event handlers with JavaScript.
  4. @ngrmm Yes, you can set regular cookies as mentioned in my first paragraph, though they won't be accessible through ProcessWire's $session API. But why would you load 87kB of library bloat for something that you can do in one line? πŸ™‚
  5. You can't save data to the session in the browser, because session data is stored server-side. The only thing the browser stores regarding the session is the cookie that identifies the current session for the server. If you need to access the stored value both client- and server-side, you can just use a regular cookie. By omitting the expires field it will only be valid for the current browser session, the same as ProcessWire's sessions. However, if you don't need to access the value server-side (which I assume you don't for a modal), you can use sessionStorage or localStorage instead, which do the same thing as cookies but with a cleaner API. Use localStorage if you want the stored value to persist across sessions (for a dismissable modal this is probably what you want) or sessionStorage to store a value only for the current browser session. const dismissalKey = 'modal-dismissed'; // user clicks on modal button $('.modal_button').click(function(){ // 1. store dismissal in the sessionStorage OR the localStorage localStorage.setItem(dismissalKey, '1'); // 2. toggle class $('.modal').toggleClass('off'); }); // somewhere else, check if the modal has been dismissed const modalIsDismissed = Boolean(localStorage.getItem(dismissalKey));
  6. Where are you getting the error, and where are you declaring the variable? If you're trying to access a variable in the template file corresponding to the page template that has been declared in the _main.php, this won't work because the _main.php is executed last. The template files are included in the following order (assuming your config above): _init.php -> [current-template].php -> _main.php So if you want to declare a variable to use in all templates, you need to do that in the _init.php All the template files should have the ProcessWire namespace. Not sure about the undefined function errors, those functions should be available in the ProcessWire namespace. Would need to see the file to diagnose.
  7. Yeah nice resource, I've been using them for a while, I guess they rebranded a while from unsplash.it πŸ™‚ By the way, the pictures are from unsplash.com, so they are completely free and can even be used in final commercial products. Though they don't have many upload guards in place to prevent people uploading copyrighted material, so it's worth it to do a reverse image search just to make sure. There's also undraw.co for illustrations, which is nice because the illustrations are SVG files and you can customize the main color right on the website.
  8. That sounds ... bad πŸ˜… Are you sure there isn't a more convenient way to do this in Snipcart? Anyway, as far as I can tell your solution is producing the correct result, so the only problem is the memory consumption. You could try to build the JSON on the fly instead of pushing everything on one big array. That is, open a file handle, encode individual lines in your recursive function and write them directly to the file. Might be a bit slower, but wouldn't require holding all combinations in memory. Though you gotta take care to have valid JSON in the end, i.e. no trailing comma for the last line and stuff like that.
  9. The _x function is part of ProcessWire's translation system – using it is good practice, because it allows you to change hard-coded strings (such as the language code) through the backend without touching the code, and translate them to multiple languages for multi-language sites. You're probably just missing a translation. Go to Setup -> Languages -> Portugese (might also be default depending on your language setup), then under "Site Translation Files" check if the main.php is already listed, otherwise select it through "Find files to translate". Add the correct language code there and it should appear in your HTML!
  10. What exactly is your use case here? I haven't completely cracked your code yet, you want only unique combinations, right? So only one of (A + B) and (B + A)? In this case, you're looking at n^2 possible combinations (I guess that's called a Power Set, but math theory is not my strong suit). You mention 14 elements as the limit at which you run out of memory. In this case, you're looking to generate 2^14 = 16384 combinations (at least it's a step up from ALL possible combinations, which would be 14! = 87178291200 πŸ™ƒ). Why do you need that many? Given your variable names, I assume this is for some kind of product configurator on a store page? In this case, you're not going to present 16 thousand possible combinations anyway. Couldn't you just calculate the price for a given combination on the fly? Sorry if I'm rambling, maybe you really need this. In this case, I'd say your solution needs to be a lot more imperative and less functional. Recursive functions are kinda RAM-heavy, as far as I'm aware PHP doesn't even have tail call optimizations, so all those intermediate results are staying in RAM. Also, you're passing the $addOns and $base arrays by value, so those are duplicated for every function call. So using simple for- and while-loops instead of a recursive function might already be enough to reduce memory usage a lot.
  11. If you really need some serious speed increase you can of course go directly to the database instead of using $pages. Though that is a lot more work, because you'll have to manually add status flags to your query, manage multilanguage support etc. I've done this for my module Automatically link page titles, the list of linkable titles and corresponding page IDs is retrieved directly from the field_title table. See the source code for reference. If you can't optimize the query, caching might be a solution, this way only the initial access will run slowly, but subsequent requests and queries will be fast. Your query varies by $item, $eventDate and $limit, so you could create a cache key based on that and store the results through the $cache API. Something like this: $limit = $item->qty; $cacheKey = implode('-', ['bookings', $item, $eventDate, $limit]); $cache = $this->wire('cache'); $selector = "template=booking, booking_items.booking_item.id=$item, booking_date=$eventDate, booking_status!=pending|cancelled, limit=$limit"; $pp = $this->wire()->pages; $otherBookings = $cache->get( $cacheKey, WireCache::expireSave, function () use ($pp, $selector) { return $pp->find($selector); } ) Quick and untested, might need some adjustments. You can use WireCache::expireSave to invalidate the cached results whenever any page is saved, though that's not very efficient if the bookings are edited very frequently. Or use a max age of a day or so, at the risk of sometimes showing outdated results.
  12. Important update: I've just updated to module to version 2.0.0 which fixes the issues with the API requests and makes the module work correctly again. However, the module now requires ProcessWire 3.0.167 or above! Read on below for an explanation. Since publishing this module, I ran into several problems with API requests not working correctly. I found that the reason was both an issue with the way the module formats it's API requests, as well as some issues with ProcessWire's cURL implementation, which means that some requests wouldn't work correctly (namely PUT and DELETE requests). I then submitted a pull request to the ProcessWire core which fixes those issues, which were thankfully accepted by ryan. The fixes are now live and available in ProcessWire 3.0.167, and I've updated the TrelloWire module to fix some internal issues as well, so the module should now work correctly once again. Unfortunately, this means that ProcessWire versions below 3.0.167 won't work correctly. New options: Switch the network implementation used by the module There's a new configuration option available that you can use to force the module to use cURL, fopen or socket connections respectively. Check out the documentation for usage information! If you can't update to 3.0.167 ... You can still install and use the module on older ProcessWire versions (though the installation will ask for confirmation if you are below 3.0.167). The module will try to use fopen to connect to the API on any ProcessWire installation below 3.0.167, but I can't promise it will work correctly. You can also try socket connections using the configuration option above, but I couldn't get it to work in my test environment. Let me know if you need support or something isn't working for you! @maddmac Just tagging you to let you know you don't need to use the dev branch from Github anymore πŸ™‚
  13. @adrian Hi Adrian, the latest version is throwing a warning if there are no external panels: I think this will only occur if there are no external panels, if the glob pattern is empty static::$externalPanels will be undefined (see TracyDebugger.module.php#L320-327). Should be fixed by initializing $externalPanels to an empty array (see L143). Thanks!
  14. Awesome, thanks @ryan! πŸŽ‰ Now I can update my TrelloWire module so it works properly again πŸ™‚
  15. It doesn't have to be, but it's certainly best practice. You can point your form directly to a PHP script, but you will have to bootstrap ProcessWire manually if you want to use the API. The PHP script also can't be in the template directory, as direct access to that is blocked by ProcessWire for security reasons – see my answer here. How best to add custom logic to your forms depends on how your form is built: FormBuilder? Use a hook to adjust how it processes the form, Custom form? You can put your logic in the same page template where you build your form. As zoeck mentioned, use the $input API to check if the form has been submitted and handle the inputs there.
  • Create New...