Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 10/08/2020 in all areas

  1. 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.
    4 points
  2. It was Kongondo doing maintenance release to old one. But I know Kongondo is working hard to get v2 released.
    2 points
  3. This is so common - I do things like this all the time, not just for menus. Does anyone else think this should be part of the core? For now, I wrote a simple flat function: /** * Recursive traverse and visit every child in a sub-tree of Pages. * * @param Page $parent root Page from which to traverse * @param callable $enter function to call upon visiting a child Page * @param callable|null $exit function to call after visiting a child Page (and all of it's children) */ function visit(Page $parent, $enter, $exit=null) { foreach ($parent->children() as $child) { call_user_func($enter, $child); if ($child->numChildren > 0) { visit($child, $enter, $exit); } if ($exit) { call_user_func($exit, $child); } } } With PHP 5.3 you can generate a menu (or whatever else) recursively as simple as this: visit( $pages->get('/menus/main') , function(Page $page) { echo '<li><a href="' . $page->url . '">' . $page->title . '</a>'; if ($page->numChildren > 0) { echo '<ul>'; } } , function(Page $page) { echo '</li>'; if ($page->numChildren > 0) { echo '</ul>'; } } ); Dead simple. I've seen the options for modules etc. that generate menus - they seem to grow out of control with a million options, and my own helpers seem to evolve the same way, and it doesn't jive with the beautiful, self-contained, simple templates you normally get away with in PW. Would it make sense to have a standard visit() method in Page in the core?
    2 points
  4. Here's how I managed to do this by hook or crook ?. Summary Hooks alone are not enough We still need to be able to switch templates and view/enable languages if those templates support languages We need to be able to do this both during page creation and post-creation We need CSS, JavaScript and Hooks We use hooks to: (a) deactivate non-default languages (b) to pass an array of template IDs that we designate as mono-lingual We use CSS to hide unrequired language tabs, inputs and labels We use JavaScript to add/remove 'hide' classes as needed We need to load the CSS and JavaScript in the admin. There are various ways to do this. I've simply added them via templates/admin.php You'll notice some brief FOUC, but they are not major and can probably be sorted out using CSS and JavaScript. I've left in some example code in the CSS (see below) Code CSS JavaScript PHP /site/templates/admin.php /site/ready.php Other approaches, anyone? Demo
    1 point
  5. Might RockFinder speed things up sufficiently? Latest version at https://github.com/baumrock/rockfinder3. I'd expect it to reduce your query times greatly - probably well under a second. And you can keep using PW selectors.
    1 point
  6. PHP Notices are not something to fix immediately but one should deal with them as soon as time permits. It is because they signal some unintended behavior and naturally, we are not aiming for such a thing. Specifically, "Trying to get property 'XYZ' of non-object" is a common issue, which means that – for example – in the $page->id->int expression the ID property is an integer and as such has no properties because it is not an object (aka "non-object"). Therefore trying to access ->int results in this notice. This also means that if ($article->int == $page->id->int) will not work as intended. This is the way engineering works ? However, sometimes just take a break and learn form professionally crafted tutorials, such as this one: https://www.youtube.com/watch?v=D8ZcKqevECY&list=PLLQuc_7jk__WTMT4U1qhDkhqd2bOAdxSo&index=1 The hard part is to find good tutorials, of course.
    1 point
  7. Hi @Robin S - I can see the reason and have a fix, although I am not sure how robust it is. The background is that in July 2016, @tpr was having some issues with some email clients needing the From name to be mime header encoded. He gave me this code to fix things: https://github.com/adrianbj/TracyDebugger/blob/81dbda3fccbe961680f9b7a6bb76f055bf41a06f/panels/MailInterceptorPanel.php#L27-L29 // from @tpr - for dealing with encoded fromName which is necessary for some email clients if(function_exists('mb_decode_mimeheader')) { $item['fromName'] = mb_decode_mimeheader($item['fromName']); } But it looks like the issue is when there are special characters that aren't encoded, this is breaking things. My attempted fix is replacing that with: if(function_exists('mb_decode_mimeheader') && mb_detect_encoding($item['fromName']) != 'UTF-8') { $item['fromName'] = mb_decode_mimeheader($item['fromName']); } but again, I am not sure how robust that is - encoding is not my speciality ? Can you test that change for me. Also, does anyone else have any thoughts on a better way to do this? @teppo - you must deal with these sorts of characters in email headers - any tips?
    1 point
  8. Thank you all for your good advises, @dragan , @szabesz , I'm learning a lot thanks to you.
    1 point
  9. So what i am looking for is when you order a product you can type in how many quanitys you want to add to your basket so far i have it like this if ($page->variations->count) { $content .= "<form method='post' class='padloper-cart-add-product' action='" . $config->urls->root . "padloper/add/'>"; foreach ($page->variations as $p) { $content .= "<input type='radio' name='product_id' value='{$p->id}'>" . $p->color->title . " " . $p->size->title . "</input><br />"; } $content .= "<input type='submit' name='pad_submit' value='" . __("Add to cart") . "' /></form>"; } else { $content .= $modules->get("PadRender")->addToCart(); } echo $content; but i am not sure how do i tell padloper's API to usee that inputed number to add correlating quanities simply adding <input type='number' name='quantity' min='1'> didnt worked EDIT: nevermind i just had to edit name="quantity" as name='qty'
    1 point
  10. @desbest I think a new version of Padloper 1 was released the other week fixing some things. Not sure if @kongondo has anything to do with that release or if its still @apeisa. Either way I am glad there was an update in the Padloper world. Never bought a license but I think I will now.
    1 point
  11. I just did that and while I didn't exactly loose data it just didn't work as expected because Repeater Matrix misses the matrix field's actual type data. I'd rather go the way of using a migration script that you can run through CLI or using RockMigrations (this is probably the fastest way, since the API is very good) module and copy/transform data from the repeater field, to the new repeater matrix field.
    1 point
  12. Variables like $page are reserved by PW, so you shouldn't try to redefine them. PW tries to find a field 'autores', which is not available in the current $page, but in the page array you're looping through. Try: foreach($pages as $p) { if(count($p->autores)) { If you install Tracy Debugger (which every PW developer should, imho), you can include debug output for variables, which is a big help when developing.
    1 point
  13. Ok, you are right @Robin S. I think, now i understand you. ?‍♂️ Your idea to use a field for the parent-child relationship works great: I add a empty repeaterfield to template. In ready.php i add to a edit button (each children page) include pagination. It looks like it´s a repeater field items (old page situation). All happy. $this->addHookAfter('Inputfield::render', function (HookEvent $event) { $field = $event->object; $form = wire('modules')->get("InputfieldForm"); //get edit page $page_id = $this->input->get('id'); $page = $this->pages->get($page_id); //add child pages to empty repeater - items not moveable, deletable or to clone if ($field->name === 'products') { $childPages = $page->children('limit=15'); $pagination = $childPages->renderPager(['getVars' => array("id" => $page_id)]); foreach ($childPages as $childPage) { //build the fake-repeater header $wrap = $this->wire('modules')->get('InputfieldFieldset'); $wrap->addClass('InputfieldRepeaterItem InputfieldStateCollapsed InputfieldRepeaterMinItem InputfieldNoFocus'); $wrap->name = "repeater_item_{$childPage->id}"; $wrap->label = $childPage->index + 1 . ': ' . $childPage->product_title . ' Art.: ' . $childPage->title; //if all fields are filled out mark the header $isFilledOut = ($childPage->product_keyword && $childPage->product_type); ($isFilledOut ? $wrap->addClass("text-black", "headerClass") : ""); //add the edit button for the child page (class pw-modal for modal edit) $submit = wire('modules')->get("InputfieldButton"); $submit->attr("value", "Produkt Details bearbeiten"); $submit->attr('data-href', wire('config')->urls->admin . "page/edit/?id=" . $childPage->id); $submit->addClass('pw-modal uk-margin-bottom uk-margin-left'); $wrap->add($submit); $form->add($wrap); } $field_style = '<style>.text-black{color:black !important;}.InputfieldRepeaterItemControls{display:none !important;}</style>'; $event->return = $form->render(); $event->return .= $field_style; $event->return .= $pagination; } });
    1 point
  14. @gornycreative - If you are using Cloudflare - you may want to set some rules as seen here:
    1 point
  15. This week I’ve been working on updates for ProcessWire 3.0.168 as well as a new Stripe payments module for FormBuilder. In the core, the ProcessPageView module that handles all requests got a pretty significant refactoring. While it was largely focused on optimization, I also just like to go in every few years and rewrite stuff in high traffic modules like this to keep the module fresh, as well as keep my mind fresh on how it all works. I find there’s often room to do something better. The ProcessLogin module also got some upgrades this week that are primarily focused on maintaining the contents of a request URL in the admin between guest and admin user states. Now it can retain most query strings in a request URL after login. There’s still more to do in 3.0.168 so the version bump isn’t being made this week but may be ready next week. So far there are also a couple of GitHub issue resolutions and $sanitizer method improvements as well. On the FormBuilder side, we have the Stripe payments Inputfield, but since that module has been built, Stripe has released new APIs to handle SCA payments (soon required for EU transactions). With these types of payments, as I understand it, a multi-factor type process takes place where the user confirms the transaction with their credit provider. So it changes the payment flow quite a bit… enough that I’ve found the current Stripe payments module can’t really be adapted for it, at least not in a reliable way. That’s because the new API requires that the payment take place interactively before the form is submitted, since the user has to manually confirm it outside the form. So this will inevitably lead to cases where a payment has been charged but the final form isn’t submitted for one reason or another. Maybe it would work most of the time, but it just doesn’t seem like a reliable transaction flow to me. For this reason, I’m building a separate module for FormBuilder that provides a better alternative for the SCA transactions. With this module, the user submits the form, but FormBuilder saves it as a partial/pending form submission. Following form submission, the user goes through the SCA payment process with Stripe. When that completes, Stripe sends a webhook to FormBuilder that converts the form submission from pending to completed, at which point emails are sent, FormBuilder actions executed, etc. So it's Stripe that submits the final form, rather than the user. I’ve got a lot of work still to do here, but since a few people have contacted me looking for SCA support with Stripe payments, I just wanted to keep you up to date and let you know it’s in progress. The existing InputfieldFormBuilderStripe module will of course continue to be developed as well, as most regions outside the EU do not require SCA. Thanks for reading and have a great weekend!
    1 point
  16. Hello to all mighty people and Happy New decade start. Wish you all the greatest goodness, joy and happiness. Well, and a lot of great code as well ? I've implemented WEBP images to optimize my soon to be released profile and by a lucky coincidence I discovered on my Mac that no images are showing when using the Safari. I thought that Apple would have embraced the idea by now when several other browsers have already done that but it seemed like I was wrong. I tested the .htaccess approach, however I could not make it working under Safari, so I decided to add a little function to my _functions.php: //WEBP Image Support function webp_support($imgURL) { // Check if the browser headers contain image/webp support if(strpos($_SERVER['HTTP_ACCEPT'], 'image/webp')) { // If yes, use the webp image url return $imgURL->webp; } else { //Else, show the original image url return $imgURL; } } After that, in every image call I do the following: <?php $img = $page->images->first // Call for the image location $image = webp_support($img->size(100,100)) // Used to size an image and convert it to WEBP //Image call in the markup echo "<img src='{$image->url}' alt='{$image->description}' >"; That seems to be working fine and show the WEBP format on Chrome, Opera and Firefox under MacOS/Windows/Linux but show the original image version under Safari. I did not test with the Windows version of Safari since it is a long time not updated version and it won't make much sense to support the newer format anyway. My question for you is if there is a simpler approach than my current to show WEBP images to the supported browsers and fallback to original If not?
    1 point
  17. There is an option for changing the "created" date via the API using quiet mode: $page->created = $timestamp $page->save(array('quiet' => true)); This only works for created though, not modified. This is what I use for modified - make sure you do this after the last $page->save() or it will be overwritten. $sql = "UPDATE `pages` SET `modified` = '".date('Y-m-d H:i:s', $timestamp)."' WHERE `id` = '".$page->id."';"; $update = wire('db')->query($sql);
    1 point
  18. This inputfield uses the ProcessPageSearch AJAX API, which is accessible to logged-in users only that have administrative access. Meaning, it can't be used on the front-end of a site, unless for an administrative user. However, this Inputfield is mainly just a front-end to the jQuery UI autocomplete, with some tweaks to make it consistent with PW's admin style and offer some configurable options. So one could very easily implement the same sort of functionality on the front-end of a site by creating a page with it's own template to handle the ajax calls, translate them to a $pages->find() operation, and return the matches. It doesn't need to do any more than this: /site/templates/search.php <?php $resultsArray = array(); if($input->get->q) { $q = $sanitizer->selectorValue($input->get->q); $results = $pages->find("title*=$q, limit=50"); foreach($results as $p) $resultsArray[$p->id] = $p->title; } echo json_encode($resultsArray); From there, the rest is just jQuery UI autocomplete: http://jqueryui.com/demos/autocomplete/#multiple-remote
    1 point
×
×
  • Create New...