Jump to content

All Activity

This stream auto-updates

  1. Past hour
  2. Hi @biber I don't think the sort() function is available to pageimages because pageimages is not WireArray. The result of the below line returns nothing. $images = $page->images->sort("iname_".$order, SORT_NATURAL |SORT_FLAG_CASE); Then foreach($images as $image) Give error because the variable $images is empty. Gideon
  3. I'm using the pagefield to select pages inside multiple parent pages. I want to use the TEMPLATE as a mean of finding pages. Unfortunately, I selected a PARENT as well, and once this is done there is no coming back: I can't have no parent anymore, I would have to create a new field. Is it a bug (concept issue) or am I doing something wrong? Thanks!
  4. Today
  5. @Gadgetto I am struggling with webhooks :-) In the docs it says: * All hookable event handler methods will return an array containing payload Snipcart sent to your endpoint. * In addition, the following class properties will be set: * * $this->payload (The payload Snipcart sent to your endpoint) * $this->responseStatus (The response status your endpoint sent to Snipcart) * $this->responseBody (The response body your endpoint sent to Snipcart) * * (Use the appropriate getter methods to receive these values!) * * How to use the hookable event handler methods (sample): * ~~~~~ * $webhooks->addHookAfter('handleOrderCompleted', function($event) { * $payload = $event->return; * //... your code here ... * }); * ~~~~~ * * PLEASE NOTE: those hooks will currently only work when placed in init.php or init() or ready() module methods! * I have setup a hook for order.completed in the init method of a custom autoload module public function init() { ... // SnipWire Webhooks $this->wire->webhooks->addHookAfter('handleOrderCompleted', $this, 'handleOrderCompleted'); } Issueing post requests to the endpoint returns an empty response body While in the docs it says: when I var_dump($event->object->getResponseBody()) in my handler method, it gives an empty string which explains why the response body is empty. How can I set responseBody from within my hook handler method? There is no setter for that and Webhooks::responseBody is private, so I have no way to set it in my handler. To solve this, I introduced a setter method to the Webhooks class /** * Setter for responseBody. * * @param string $responseBody * @return void * */ public function setResponseBody(string $responseBody) { $this->responseBody = $responseBody; } Now in my handler method I can do $event->object->setResponseBody('{"test": "test"}'); Which results in While I was at it, I also added a setter for responseStatus. Not sure if you still maintain this module, so I will add this to my fork just in case anyone still needs it.
  6. @bernhard: Thanks to your forum thread, I finally did the switch from my previously used XAMPP development stack to WSL2/DDEV on my Windows 11 machine. Now I do all my Python, PHP and Node/Html projects within the Linux subsystem on Windows 11 using VS Code as my editor of choice. Only Windows Desktop C# projects (WinForms, WPF) are still done on the Windows side using Visual Studio 2022. Always wanted SSL certificates on my localhost. Installation was easy and my first project was set up within minutes by simply cloning and importing my MySQL dump into my ddev container. Thanks for the inspiration.
  7. To sort your gallery images with the newest ones first, just add a minus sign before ‘created’ in your sorting code. Use "?order=latest" in your link to apply this sorting. Doglikesbest
  8. Yesterday
  9. OK, here's my slightly revised `router.php` script: <?php if (PHP_SAPI !== 'cli-server') { die('Expected cli-server'); } if (file_exists($_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'])) { return false; } $_SERVER['SCRIPT_NAME'] = '/index.php'; $_SERVER['SCRIPT_FILENAME'] = $_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME']; require $_SERVER['SCRIPT_FILENAME']; The main change is that `$_SERVER['SCRIPT_FILENAME']` is now an absolute path. Not critical, but more correct.
  10. OK, got it. I'm using PHP's built-in web server for development. You can often use it directly, like this: php -S localhost:8080 But occasionally you run into situations that require a router script, like this: php -S localhost:8080 router.php I generally use something like this: <?php if (PHP_SAPI !== 'cli-server') { die('Expected cli-server'); } if (file_exists($_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'])) { return false; } $_SERVER['SCRIPT_NAME'] = '/index.php'; require __DIR__ . '/index.php'; ProcessWire required one additional line: <?php if (PHP_SAPI !== 'cli-server') { die('Expected cli-server'); } if (file_exists($_SERVER['DOCUMENT_ROOT'] . $_SERVER['SCRIPT_NAME'])) { return false; } $_SERVER['SCRIPT_FILENAME'] = 'index.php'; // <== Added! $_SERVER['SCRIPT_NAME'] = '/index.php'; require __DIR__ . '/index.php'; That's because of some assumptions in ProcessWire.php. With that added line url path hooks with extensions now work. (I'm going to hunt around a bit to see if I should make any other changes...)
  11. OK, thank you! It helps a lot to know that it *should* work. I'll keep trying to figure out what I'm doing wrong.
  12. I'm doing exactly that in RockFrontend: https://github.com/baumrock/RockFrontend/blob/e2b0beb70427c39ade99dc36547a370dd091f59f/RockFrontend.module.php#L2338
  13. Ryan has always done this (I really don't know why), but the tag on GH is added for the previous master version when the next master version is released and made available from the PW site's download page.
  14. This works: $wire->addHook('/hello', function($event) { return "Hello"; }); This doesn't: $wire->addHook('/hello.txt', function($event) { return "Hello"; }); (Note the `.txt` extension.) I see that in `WireHooks.php`, here, the extension will be removed, because "." will fail the `ctype_alnum` test. But the hook doesn't work even if I comment that block of code out, so that isn't the only issue. This is all rather curious because the original post that introduced url path hooks specifically called out `/sitemap.xml` as a possible use case. Am I doing something wrong? (Btw, curiously, when adding a `/hello.txt` hook, a `/hello.txt` URL doesn't work, but it doesn't produce a 404 either; it produces a blank page.)
  15. Hi, I have built a site with some galleries, which can be ordered by different criteria, like place, name or date_created. This works fine, iname_1,2 or 3 can be chosen by user. Now I want to have the option to sort the images "latest image first". Setting "rsort" instead of "sort" in line 31 comes up with this error: Where is my mistake? Any idea? Here is my template: 1 <?php include(\ProcessWire\wire('files')->compile(\ProcessWire\wire("config")->paths-> root . 'site/templates/_head.php',array('includes'=>true,'namespace'=>true,'modules'=> true,'skipIfNamespace'=>true))); // include header markup ?> 2 3 <div id='haupt'> 4 5 <?php 6 7 // output 'headline' if available, otherwise 'title' 8 echo '<h1>' . $page->get('headline|title') . '</h1>'; 9 10 //get all segments and clean segments! 11 $seg1 = $sanitizer->pageName($input->urlSegment1); 12 $seg2 = $sanitizer->pageName($input->urlSegment2); 13 $seg3 = $sanitizer->pageName($input->urlSegment3); 14 15 //check for the second urlsegment not needed 16 if ($seg2) { 17 // unknown URL segment, send a 404 18 throw new \ProcessWire\Wire404Exception(); 19 } 20 21 //check for the third urlsegment not needed 22 if ($seg3) { 23 // unknown URL segment, send a 404 24 throw new \ProcessWire\Wire404Exception(); 25 } 26 // Sortierung übernehmen: 27 $order = $input->get->order; 28 29 // sortiere nach name_: 30 if ($order >0) { 31 $images = $page->images->sort("iname_".$order, SORT_NATURAL | SORT_FLAG_CASE); 32 $session->set($order, $order); 33 } 34 35 // ohne Sortierung: 36 else { 37 $images = $page->images; 38 } 39 40 //normal content without first url segment! 41 if (!$seg1) { 42 43 echo $page->body; 44 if (!empty ($page->name_1|$page->name_2|$page->name_3)) echo '<p>Sortierung nach '; 45 if (!empty($page->name_1)) 46 echo '<a class="tab" href="'.$page->url.'?order=1">'. $page->get('name_1'). '</a>&nbsp;'; 47 if (!empty($page->name_2)) 48 echo '<a class="tab " href="'.$page->url.'?order=2">'. $page->get('name_2'). '</a>&nbsp;'; 49 if (!empty($page->name_3)) 50 echo '<a class="tab " href="'.$page->url.'?order=3">'. $page->get('name_3'). '</a></p>'; 51 52 // output images 53 foreach($images as $image) { 54 $iname_3 = $image->created; 55 $thumbnail = $image->height(100); 56 echo '<div class="rahmen"><a href="'.$page->url . $image.'?order='.$session-> get($order).'"><img class="shadow" src="'.$thumbnail->url.'" alt="'.$image-> kopf.'" title="'.$image->kopf.'" loading="lazy"></a></div>'; 57 } 58 59 } 60 61 //special view output with an url segment... 62 if ($seg1) { 63 // get the image in the correspondent position: 64 $index = $input->$seg1; 65 $image = $page->images->index($index); 66 67 // Link zum vorigen Bild: 68 echo '<a href="'.$images->getPrev($images->$seg1).'?order='.$session->get($order). '"><img src="'.$config->urls->site.'templates/styles/links.gif" alt="voriges Bild" title="voriges Bild"></a>&nbsp;'; 69 70 // Link zur Thumbnail-Seite: 71 echo '<a href="'.$page->url.'?order='.$session->get($order).'"><img src="'.$config ->urls->site.'templates/styles/index.gif" alt="zurück zur Übersicht" title="zurück zur Übersicht"></a>&nbsp;'; 72 73 // Link zum nächsten Bild: 74 echo '<a href="'.$images->getNext($images->$seg1).'?order='.$session->get($order). '"><img src="'.$config->urls->site.'templates/styles/rechts.gif" alt="nächstes Bild" title="nächstes Bild"></a><br />'; 75 76 // Bild zeigen: 77 echo '<img class="shadow" src="'.$images->url . $seg1.'" alt="'.$images->$seg1-> get('kopf|name_1').'" title="'.$images->$seg1->get('kopf|name_1').'">'; 78 79 //echo '<img class="shadow" src="'.$images->url. $seg1.'" alt="'.$images->$seg1->kopf.'" title="'.$images->$seg1->get('name_1|kopf').'">'; 80 81 82 // Textfelder zu den Bildern anzeigen: 83 echo '<h2>'.$images->$seg1->caption.'</h2>'; 84 echo '<h2>'.$images->$seg1->get('kopf|name_1').'</h2>'; 85 //var_dump($images->$seg1->filedata['_109']); 86 //var_dump($images->$seg1->caption); 87 echo '<p>'.$images->$seg1->bildtext.'</p>'; 88 echo '<p>| '.$images->$seg1->iname_1.'&nbsp; &nbsp;| '.$images->$seg1->iname_2. '&nbsp; &nbsp; | '.date("d.m.Y",($images->$seg1->created)).' |</p>'; 89 } 90 ?> 91 </div><!-- end content --> 92 <?php include(\ProcessWire\wire('files')->compile(\ProcessWire\wire("config")->paths-> root . 'site/templates/_foot.php',array('includes'=>true,'namespace'=>true,'modules'=> true,'skipIfNamespace'=>true))); // include footer markup ?>
  16. Me too! This is now default in all my installations for all the reasons you mention. But I feel this sort of update would be a PW4 thing?
  17. Hi @Christophe Unfortunately we don't have Code Intellisense or autocomplete in latte files at the moment 😞 See https://github.com/smuuf/vscode-latte-lang/issues/5 You are adding the method "listchildren()" to your ParentPagePage, nowhere else. That means you can all this method only on pages that have the template "parent-page". Why should it do that? You are calling a method of an object. If that does not exist it is expected to throw an error. You CAN do what you describe though. Sometimes it is useful and I'm doing that as well. You could add that method to your DefaultPage.php and there return an empty sting. That would make $page->listchildren() return "" by default, which means it does not throw an error. For some page types you can then implement a different logic: DefaultPage.php --> listchildren() { return ""; } FooPage.php extends DefaultPage --> listchildren() { return "foo!"; } BarPage.php extends DefaultPage --> listchildren() { return "BAR"; } // in any template echo $page->listchildren(); That it totally up to you. Same with regular ProcessWire templates. It's up to us devs how we organise things and everybody does it differently. I can only say what I came up with and what works great for all kings of projects (from very simple to very complex ones): layout.latte for main markup /site/templates/sections/... for all sections /site/templates/partials/... for all partials Details: layout.latte --> holds the html markup skeleton of the page, eg: <html> <head>...</head> <body> <header>...</header> <main>...</main> <footer>...</footer> </body> </html> Then all my template files are usually empty (like home.php, basic-page.php, foo.php, bar.php). Next, I divide my design into sections. A section is a portion of the page that goes from the very left to the very right and has an undefined height/content. You can then add those sections to your main markup file like this: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {include "sections/content.latte"} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> This is often all I need, because I build all the available sections in RockPageBuilder and then I can simply add them to the pages as I need them. But it works without RockPageBuilder as well. You then just need to code all your page layouts depending on the page template. If all those pages share the same breadcrumbs and content-footer it could look like this: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {if $page->template == 'foo'} {include "sections/content-foo.latte"} {elseif $page->template == 'bar'} {include "sections/content-bar.latte"} {else} {include "sections/content.latte"} {/if} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> You could also use a dynamic approach: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {include "content/" . $page->template . ".latte"} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> It's just regular PHP inside the latte tags, so you could also do is_file() checks etc: <html> <head>...</head> <body> <header> {include "sections/topbar.latte"} {include "sections/navbar.latte"} </header> <main> {include "sections/breadcrumbs.latte"} {var $file = "content/" . $page->template . ".latte"} {if is_file($file)}{include $file}{/if} {include "sections/content-footer.latte"} </main> <footer> {include "sections/footer.latte"} </footer> </body> </html> Obviously you'd need to create those files. Here I'm placing them into a new folder called "content", which would be /site/templates/content/foo.latte for example. Next, partials: If you have repeating markup inside your sections you can outsource them into the partials folder. For example let's say you want to show a blog overview page that shows all single blog items as cards. You'd have a section like "blog-overview.latte" like this: // blog-overview.latte <div uk-grid> <div n:foreach="$page->children() as $item"> <div class="uk-card"> <h3>{$item->title}</h3> <p>{$item->teaser()}</p> </div> </div> </div> This example is very simple and if you only use your cards here, then it's easier to leave them here. If you are using the exact same cards on two or three places then you can create partials for them: // blog-overview.latte <div uk-grid> {foreach $page->children() as $item} {include "partials/card.latte", item: $item} {/foreach} </div> // /site/templates/partials/card.latte <div> <div class="uk-card"> <h3>{$item->title}</h3> <p>{$item->teaser()}</p> </div> </div>
  18. Hey @bernhard, just updated a site to Rockfrontend 3.13.1 and noticed that auto-loading assets via $rockfrontend->styles()->add('foo.css'); $rockfrontend->scripts()->add('bar.js'); now has the order reversed in the generated markup. <script src='bar.js?m=1712642262'></script> <link href='foo.css?m=1713850912' rel='stylesheet'> Which in case of using UIKit is probably not ideal, since in my understanding the CSS should be loaded before the JS. Can you reproduce this or is something messed up on my part? Also, on a live site and with debug mode off, RF still renders a tag <script>var RockFrontend = {"isDDEV":false}</script> in the html head, wonder if that is necessary or what the purpose of that could be. Any pointers here? Not using RockFrontend.js if that's related in any way. Greetings to Austria and thanks in advance! 🙂
  19. If you truly want to make an admin theme from scratch like I'm doing, it's best to just take AdminThemeUikit, since that is the "official" and most supported theme and rip out UIkit and start replacing it with your own approach and just hack away at it. Keep in mind that ProcessWire makes heavy use of jQuery UI and a few other libraries so you'll have to play nicely with them unless you want to replace them too, but that takes it to another level. With Bootstrap, it's straight-forward enough given the similarities with UIkit, although this is turning out to be more work than I anticipated. But that was the point since I want it to force me into looking at how everything is interconnected. One idea for an admin theme is to do it with pure, modern CSS and as little JS as possible and as accessible as possible (good reason why here).
  20. Hello Bernhard, A bit of context before the questions below in the message. I want to display a list of children of the parent pages that are using the template "parent-page". So, I have created parent-page.php (empty for the moment) in /site/templates. And ParentPagePage.php in /site/classes in which I have this (where I tested different things): <?php namespace ProcessWire; class ParentPagePage extends Page { public function listchildren() { return "Clickable list of children"; } } I had more elaborate code(s) in the return statement, but things weren't working so I just put a string in it to keep it simple. (I've just noticed that vscode and intelephense are writing "Undefined type 'ProcessWire\Page'." in the PROBLEMS tab.) So I had : Method DefaultPage::listchildren does not exist or is not callable in this context on pages that do not use the parent-page template (and use the basic-page template). Method HomePage::listchildren does not exist or is not callable in this context on the homepage. For the error messages and blank page(s) to disappear it seems that it is mandatory to use this in main.latte: {if $page->template == 'parent-page'} {$page->listchildren()} {/if} and not just {$page->listchildren()}. At one point with custom page classes I think I was hoping it would also remove the need for that if condition. In /site/templates/sections/main.latte I currently have the code that follows - at the end of the message now (we apparently can't escape having to use the |noescape filter). I simplified the code to only define and check $image (the code borrowed from another website was also defining and checking $images, so not only the first image, I don't remember why/if it was needed). SO, my question(s) is how could this code be simplified, in part in order to have cleaner code in this main.latte file? Which parts of the code should be in main.latte, which ones in ParentPagePage.php and which ones perhaps in parent-page.php? How would you organize/separate them in the different files? Also, can $image and $thumb be defined elsewhere? Etc. Thanks again in advance! I tried yesterday with simpler children list codes (without images and uikit markup), but it seemed complicated and not clean. And now it's more complicated. I've tried with code directly inside the return statement, and also with a variable and then returning the variable. $thumb is currently defined if $image exists. If I used <img n:if="..." src="... it would be changed. But perhaps it wouldn't be important if it wasn't defined inside the {if}...{/if}. <main> <div class="uk-container"> <h1>{$page->title}</h1> {$page->body|noescape} {if $page->template == 'parent-page'} {$page->listchildren()} {/if} <div n:if="$page->template == 'parent-page'" class='uk-child-width-1-3@m uk-grid-match uk-margin-small-top uk-margin-medium-bottom uk-text-center' uk-grid> <div n:foreach="$page->children() as $child"> <div class='uk-card uk-card-small uk-card-default uk-card-body'> <a class="h2" href="{$child->url}"> {var $image = $child->images->first()} {if $image} {var $thumb = $image->size(200, 150)} <img src="{$thumb->url}" width="{$thumb->width}" height="{$thumb->height}" alt="{$image->description}" /> {/if} <h2>{$child->title|noescape}</h2> </a> </div> </div> </div> </div> </main>
  21. is there a way to make the options multilingual?
  22. I have managed to save the charge id to the order. For this to work I needed to make captureOrder hookable. This is probably not the right way tough.. $wire->addHookAfter('PadloperProcessOrder::captureOrder', function(HookEvent $event) { $paymentIntent = $event->return; $orderId = $paymentIntent->metadata->reference_id; if ($paymentIntent && $paymentIntent->status === 'succeeded') { $chargeId = $paymentIntent->latest_charge; // Load the order page using the order ID and save the charge ID $orderPage = wire()->pages->get("template=padloper-order, id={$orderId}"); if ($orderPage->id) { $orderPage->of(false); $orderPage->set('stripe_charge_id', $chargeId); $orderPage->save(); } } });
  23. To resolve the version discrepancy, it’s best to update to the latest master version, 229. This version includes about 8-10 fixes that are not in version 227. Updating will ensure you have the most recent improvements and bug fixes. Just go to the download page and get the latest version.
  24. @Jonathan Lahijani It's great you still working on this, can't wait to try it. I wish one day you make a tutorial on how to create an admin theme from scratch, as all forum's related content is outdated.
  25. Last week
  26. Thought this might be interesting for the UIkit/Tailwind users, maybe best of both worlds?? https://www.franken-ui.dev/docs/introduction
  27. @Mustafa-Online I made nice update today on this module after not having touched it in several weeks. It's now basically complete but before I release it I still need to clean up some old code that's left over, make it work more nicely with SelectizeAll and provide similar overriding capabilities that the UIkit theme has. This module includes Bootstrap Icons and it substitutes Font Awesome icons accordingly (I went through each one and found the equivalents!). It also uses the Bootstrap navbar and dropdowns. A side-effect of this is ajax-loaded dropdown content won't work in the first release. I may backtrack on using Bootstrap dropdowns depending on if that becomes difficult. Anyway, it's looking good overall. If anyone is wondering why use this as opposed to UIkit, it may be beneficial if you are doing a lot of custom admin stuff and want to use pre-made Bootstrap styled components since the Bootstrap ecosystem is much much larger than UIkit. Also, it feels a little more fresh, although my actual reason for creating this was to for a way for me to get a deeper understanding of how admin themes work.
  1. Load more activity
×
×
  • Create New...