Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 12/21/2022 in all areas

  1. You don't need a plugin for this, you can do it directly in the details tab in the field settings.
    3 points
  2. I'd start with what we all love PW for: The API. So I'd ask myself: What would I want it to work (without thinking about the consequences and the work that has to be done to make it work like that). And I'd probably come up with something like this: $newspages = $pages->find("template=newsitem, limit=12"); foreach($newspages as $p) ... echo $newspages->renderPager(); echo $infiniteScroll->renderTag(); To make that work you'd need an $infiniteScroll module with a renderTag() method. That method would render a JS <script> tag that finds the previous sibling (https://gomakethings.com/how-to-get-the-next-and-previous-siblings-of-an-element-with-vanilla-js/#an-example) and detects what page we are on and once the script tag comes into view which next page it should request via ajax and inject into the DOM. Then you'd only have to add the InfiniteScroll.js file to your <head> and maybe make the renderTag() configurable (like how many pages should be loaded before showing a "load more" button or to make the "load more" button markup configurable as well: echo $infiniteScroll->renderTag([ 'pages' => 3, // auto-load 3 pages, then show the load-more button 'button' => "<button class='uk-button uk-button-small'>load more</button>" ]); That would be how I'd like to have it work. But I have to admit that I've never built an infinite scroll so I might be missing something obvious or important ? Good luck and have fun ?
    2 points
  3. Update: I have, in a way, accomplished my goals! I have not been successful at adding any <optgroup>s, BUT I did figure out a way around my issue. Instead of adding the unsupported optgroups, I just inject extra, disabled <option>s. These options can get a label, so I can use them as sort of dividers between the rows of pages Currently I group them by template name, as the selector for the field has that as primary sorting anyway. Pretty simple.. as always with these things, once you figure it out <?php $wire->addHookAfter("InputfieldAsmSelect(name=linked)::render", function ($event) { $html = $event->return; // Get the input field in order to sanitize new values /** @var Inputfield $input */ $input = $event->object; // Create a DOMDocument object and load the html from the Inputfield $dom = new \DOMDocument; $dom->loadHTML($html); // Get the <select> and its childnodes $select = $dom->getElementsByTagName("select")->item(0); $options = $select->childNodes; // Keep track of the previous template name.. $prevTemplate = ''; //Loop through the childnodes for ($i = 0; $i < $options->length - 1; $i++) { $option = $options->item($i); if ($option && $option->attributes->getNamedItem('value')) { // Get the page onject $pageId = (int) $option->attributes->getNamedItem('value')->nodeValue; $page = $this->pages->get($pageId); // If a new template label is found.. if ($prevTemplate !== $page->template->label) { // Create a new <option> $newOption = $dom->createElement("option"); $newOption->setAttribute("disabled", true); $newOption->nodeValue = $input->entityEncode(mb_strtoupper($page->template->label)); // And simply insert it above the current <option> $select->insertBefore($newOption, $option); $prevTemplate = $page->template->label; } } } // Return the new HTML and add a paragraph to double prove this bit of code do its work $event->return = $dom->saveHTML(); }); I'd love to be able to add things like icons, and some more formatting.. but for now: pretty decent.
    2 points
  4. Interesting. I was sure I saw this particular plugin on a website with more than 5 reviews being displayed. Anyway, there seems to be no way nowadays to fetch the reviews over any API key without enabling the billing. I got the same message in my console while testing. I now decided to use this solution: - Fetch the latest 5 reviews via the google API - Save the recieved JSON object to a field in the ProcessWire backend - Render the reviews based on that field data I will create a cronjob that fetches new reviews maybe once a week so hat you don't need to do an API request every single time someone visits the page.
    2 points
  5. @eelkenet, cool that you were able to find a solution! Here's another way you could add disabled section items into the Page Reference AsmSelect using the PW API. It avoids getting each page individually in a loop so probably a bit more efficient. // Add dummy items to the selectable pages to act as section headings $wire->addHookAfter('InputfieldPage::getSelectablePages', function(HookEvent $event) { /** @var InputfieldPage $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; $selectable = $event->return; $t = null; $i = 1; if($field && $field->name === 'my_page_reference') { foreach($selectable as $p) { if($p->template->name !== $t) { $section = new NullPage(); $section->id = "section{$i}"; $section->title = mb_strtoupper($p->template->label) . ' ––––––––––––––––––––'; $selectable->insertBefore($section, $p); $t = $p->template->name; $i++; } } $event->return = $selectable; } }); // Set the dummy options to disabled $wire->addHookAfter('InputfieldAsmSelect::renderReadyHook', function(HookEvent $event) { /** @var InputfieldAsmSelect $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; if($field && $field->name === 'my_page_reference') { foreach($inputfield->options as $value => $label) { if(substr($value, 0, 7) === 'section') { $inputfield->addOptionAttributes($value, ['disabled' => 'disabled']); } } } });
    1 point
  6. Is there a... <form method="post" action="<?= $config->urls->root ?>padloper/empty/"> ...or similar call I can make?
    1 point
  7. You could apply the purify sanitizer when the field value is saved by hooking InputfieldTextarea::processInput(). But looking at it another way, it isn't really possible to guard against a malicious superuser - they could destroy the site in any number of ways. Therefore you have to accept that superuser is a role for trusted users only.
    1 point
  8. @zoeck wire()->addHookAfter('InputfieldRepeater::render', function (HookEvent $e) { /** * @var InputfieldRepeater $repeater * @var Page $page Repeater page */ $repeater = $e->object; $page = $repeater->hasPage; if ($repeater->getAttribute('name') == 'repeater_name') { $return = $e->return; $e->return = $return . 'Hello World !'; } });
    1 point
  9. Returning to this after 5 years, one of my annual Christmas/New Year web development projects. I think I got something working 5 years ago, but it was clunky and too confusing to implement throughout my sites. What is the recommended approach for 2023? Wish list: Infinite scroll - within reason, turning into a 'More' button after the first dozen items Lazy loading Not using plugins/modules ... Should I start with pagination? Or some other built-in feature to creates an array of items on page load, ready to be added to the page as you scroll down? The clunky first attempt called items by batch based on the latest added item, I think. I'll add my solutions here as I find them, using this thread to keep track of what I'm doing. Any tips/suggestions appreciated.
    1 point
  10. Hi there, I think what would help is a very minimal setup, a demo without ajax/htmx, templating etc. In the absence of that, here is a super basic question: 1. How do I add and remove a product to the cart purely via the API? This is for me to understand the basics. I'm imagining it would be something like $cart = $padloper->getCart(); if(!$cart->addProduct(product_id)) { echo 'problems adding'; } if(!$cart->removeProduct(product_id)) { echo 'problems removing'; } tx J
    1 point
  11. ?‍♂️ I would leave a beer from Franconia for the module ?
    1 point
  12. What about this: I (Stefanowitsch) will create a cronjob module that fetches new reviews maybe once a week so hat you don't need to do an API request every single time someone visits the page. ??
    1 point
  13. Which part was new? Date handling? That will forever be a mystery.
    1 point
  14. Hi @Stefanowitsch, Try: <?php $img = $image->render([ 'srcset' => [ 'rules' => '320x569, 640x1138, 768x1365, 1024, 1366, 1600, 1920', // first three rules here are for portrait images 'options' => [ 'upscaling' => true, 'hidpi' => true, ], ], 'sizes' => '(orientation: portrait) and (max-width: 640px) 50vw', ]); This is adapted from an example in the README which itself was adapted from an implementation in PageimageSrcset - I can't remember exactly how this works but I have used it in the past for portrait images on mobile. Cheers, Chris
    1 point
  15. The root of the site is one more level up from that location though..... Usually when I need to pass some php var to js I do this: $jsconfig = array( 'subscribe' => $urls->root . "myPhpFile.php" // the key "subscribe" can be whatever you want of course. // it points to the root of the site, close to "site" folder, one level up the "template" folder. ); echo "<script>var pwUrls = " . json_encode($jsconfig) . ";</script>"; ?> Then in js I reference that var like this: pwUrls.subscribe
    1 point
  16. yes it does, it looks like it's working. Thank you very much. Actualy learnt something new here. ? R
    1 point
  17. A new module that hasn't had a lot of testing yet. Please do your own testing before deploying on any production website. Custom Paths Allows any page to have a custom path/URL. Note: Custom Paths is incompatible with the core LanguageSupportPageNames module. I have no experience working with LanguageSupportPageNames or multi-language sites in general so I'm not in a position to work out if a fix is possible. If anyone with multi-language experience can contribute a fix it would be much appreciated! Screenshot Usage The module creates a field named custom_path on install. Add the custom_path field to the template of any page you want to set a custom path for. Whatever path is entered into this field determines the path and URL of the page ($page->path and $page->url). Page numbers and URL segments are supported if these are enabled for the template, and previous custom paths are managed by PagePathHistory if that module is installed. The custom_path field appears on the Settings tab in Page Edit by default but there is an option in the module configuration to disable this if you want to position the field among the other template fields. If the custom_path field is populated for a page it should be a path that is relative to the site root and that starts with a forward slash. The module prevents the same custom path being set for more than one page. The custom_path value takes precedence over any ProcessWire path. You can even override the Home page by setting a custom path of "/" for a page. It is highly recommended to set access controls on the custom_path field so that only privileged roles can edit it: superuser-only is recommended. It is up to the user to set and maintain suitable custom paths for any pages where the module is in use. Make sure your custom paths are compatible with ProcessWire's $config and .htaccess settings, and if you are basing the custom path on the names of parent pages you will probably want to have a strategy for updating custom paths if parent pages are renamed or moved. Example hooks to Pages::saveReady You might want to use a Pages::saveReady hook to automatically set the custom path for some pages. Below are a couple of examples. 1. In this example the start of the custom path is fixed but the end of the path will update dynamically according to the name of the page: $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'my_template') { $page->custom_path = "/some-custom/path-segments/$page->name/"; } }); 2. The Custom Paths module adds a new Page::realPath method/property that can be used to get the "real" ProcessWire path to a page that might have a custom path set. In this example the custom path for news items is derived from the real ProcessWire path but a parent named "news-items" is removed: $pages->addHookAfter('saveReady', function(HookEvent $event) { $page = $event->arguments(0); if($page->template == 'news_item') { $page->custom_path = str_replace('/news-items/', '/', $page->realPath); } }); Caveats The custom paths will be used automatically for links created in CKEditor fields, but if you have the "link abstraction" option enabled for CKEditor fields (Details > Markup/HTML (Content Type) > HTML Options) then you will see notices from MarkupQA warning you that it is unable to resolve the links. Installation Install the Custom Paths module. Uninstallation The custom_path field is not automatically deleted when the module is uninstalled. You can delete it manually if the field is no longer needed. https://github.com/Toutouwai/CustomPaths https://modules.processwire.com/modules/custom-paths/
    1 point
  18. Mh? Doesn’t fetch("/auction-longpolling.php" work? Starting with a slash is always relative to the “origin”. You could also put the full address: fetch("<?=config()->urls->httpRoot?>auction-longpolling.php" etc. (note httpRoot already comes with a trailing slash)
    1 point
  19. Either I'm missing an important detail or ... // define yesterday $theDayBeforeYesterday = strtotime("-2 day"); // get our pages $reallyOldEvents = $pages->find("template=template, date<=$theDayBeforeYesterday"); foreach($reallyOldEvents as $oldEvent){ // let's do something with it // maybe we put them into an archive // and delete all of them in 2 years // rather than now. } Does this find your events prior to yesterday?
    1 point
  20. It is no secret that Wordpress attracs a lot of no-coders and low-coders because of it's available template market. The no-coder buys a template on envato, themeforest, templatemonster, etc. and sells it as a website to the client. Most of the clients don't even know they bought an envato template website because they have no time and no website experience. By the time the client needs to have something changed, the wordpress template limitations won't allow for it and the no-coder is long gone selling a template somewhere else. Sooner a later the client is forced to call for a real coder for the needed level of support. Pagebuilders will attract even more no-coders and low coders. Having followed the Pagebuilder scene in Wordpress with Beaver, Bakery, Brizy, VisualComposer, Elementor, Genesis, Gutenberg, Themify, Divi, Oxygen, GeneratePress .... the list goes on and on. There is almost every month a new Wordpress Pagebuilder on the block. Why spend time in learning the Pagebuilder of the day if you could spend that same time in learning html, js, css and php and never need a Pagebuilder in the first place and give the Client a website that he really deserves: without Template limitations, unused theme functions and without all the Pagebuilder bloated code. Coming to my point: I hope that what is happening in the Wordpress Pagebuilder scene will never happen with future Processwire Pagebuilders.
    1 point
  21. I like repeaters for structuring data. For building a layout, not so much. I've seen the demo's on this forum of people using repeaters in creative ways to build a layout, but it never looks very intuitive to me. I've grown to dislike this approach so I've been looking at other content management systems for inspiration. Bolt CMS uses Article Editor, which is a nice (paid) javascript solution that's basically an advanced wysiwyg editor with support for grids and other nice features. I decided to integrate this into Processwire as an inputfield. Here's a demo: I created a few plugins for Article Editor that take care of uploaded images, inserting links and Hanna code support for adding dynamic bits to the editor. And the field also works in repeaters. You can pass your CSS to the editor so that the editor preview should look identical to the real page. I am using Bootstrap. A bonus of building a page this way is that the whole layout is stored in a single field so there should be fewer requests to the database compared to repeaters. Please note that since Article Editor is not free, you need a license to use it. I've been working on this module on and off for a while. There are refinements to be made, like perhaps loading the Hanna code previews dynamically (they are currently inserted into the editor after saving the page). Not sure if it would be good enough to release publicly but I thought I'd share it anyway because I'd like to hear if you think this is a nice approach :)
    1 point
  22. How would that concept work with multiple languages?
    1 point
  23. Hi @modifiedcontent have you considered just using Ryan's ProcessForgotPasswords module that is already part of PW and just loading it in your template file and having it take care of things for you? I've not tried it myself in my own template files but it is certainly possible. Something like this might work for you on your reset page template (totally untested, but you seem to be willing to experiment)... <?php if ($user->isLoggedin()) { $session->logout(); $session->redirect('/'); } else { $pfp = wire()->modules->get("ProcessForgotPassword"); $pfp->useInlineNotices = true; $pfp->emailFrom = 'your-from-address@your.domain'; echo $pfp->execute(); } There are several other settings like 'useInlineNotices' that are documented in the module from lines 17-28, linked here. You'll be better served using this core module if you can, rather than writing something yourself. If you do want to use this as a learning opportunity, and decide to go with your own code then I'd suggest research in the following areas: CSRF tokens, session variables, cryptographically secure random number generators, MD5 weaknesses and password hashing.
    1 point
  24. There are a few different ways to do this, including htaccess rewrites, but this code from willyc is a good option: http://processwire.com/talk/topic/1799-routes-and-rewriting-urls/ A few other posts worth reading: http://processwire.com/talk/topic/4847-redirect-in-htaccess/ http://processwire.com/talk/topic/3275-hide-parent-page-from-url/ http://processwire.com/talk/topic/4521-how-to-customize-urls/
    1 point
  25. I totally understand what you mean but just to clarify for those who may not ....Diogo is not saying things are not democratic here at PW..just that final decisions are made by the lead dev... . I don't need to remind us all that Ryan is very quick to listen and thoughtfully respond to requests, criticisms, etc. Sometimes I feel he bends over backwards to accommodate our many requests.... That has been my experience. Anyway, I digress, again, sorry
    1 point
  26. First off, I won't stop developing ProcessWire unless I'm dead. But lets say that one of you showed up at my door and shot me, and then I'm gone for good. This is free software and you don't get any guarantees there, no matter what CMS it is or how big the community or adoption of it is. But what you do get is the source code and permission to use it and do with it what you need to. There is far more security in that than any proprietary or commercial system. We should all feel very lucky that this project has attracted such a capable development community around it (more than any project I've ever seen), and there are several guys here that are fully capable of taking over the project if I go down in a hang-glider crash. I'm always reluctant to list off people because there are so many people that contribute to the core and I don't want to forget anyone. Suffice to say, I may hold the keys to the master GitHub account, but this is a project of many developers, at least 5 of which are fully capable of taking over the project if I kick the bucket. I'm certain that some of these guys could do better than me with it. Please don't take that as an invitation to show up at my door with a weapon. But I would suggest this may be better odds than with the bigger projects you'd mentioned. Lets also point out here that ProcessWire is not WordPress–it does not need daily updating in order to keep running. Most sites I build with ProcessWire are running the version they are launched with. With ProcessWire, you do not need to upgrade your site every time a new version comes out. You can generally upload it and forget it, and it'll keep running till the site as long as the server itself is running. What other CMS can you say that for? (I can't think of any) Personally, I think adoption of something like Drupal, Typo3, Joomla, etc. is more of a risk, because you are dealing with a legacy platform – you are adopting technology from 10 years ago. You are also adopting something that is a target for hackers and spammers. WordPress is perhaps the biggest target, and something I've very apprehensive to setup for clients. Ultimately when a company chooses to adopt a legacy platform because "it's what the clients know" or [more likely] what they themselves know, it's a lazy decision. It's not looking out for the clients' best interests, and it's pursuing mediocrity. When you pursue mediocrity, you pay for it in the long run. There is no better testament to that than the legacy platforms that agency seems attached to. 1-3 years after installing [Drupal/Joomla/Typo3/WordPress/etc.] for the client, they are going to be looking for "something different" in terms of the CMS (we all know this) and they won't be coming back to the same agency. The agency that thinks it's playing it safe is really just hurting themselves when they give their clients something tired and mediocre that anyone can give them. Instead, give them ProcessWire, and they'll know you are different and better (a secret their competition does not have), and they'll be a lifetime client.
    1 point
×
×
  • Create New...