Leaderboard
Popular Content
Showing content with the highest reputation on 07/20/2022 in all areas
-
I don't know when I last found a tool for my daily work that had such a huge impact as Latte. The last one was ProcessWire I guess (which had an even greater impact of course, but still). Latte uses PHP syntax so you don't have to learn a new language! It plays extremely well with the PW API and it makes my markup files so much cleaner and easier to read and maintain I can't tell you. From time to time I stumble over situations where I'm once more impressed by latte, so this thread is intended to collect small latte snippets to show how one can use it. If you want use Latte for your ProcessWire projects you can either install it via composer or you wait some more days until I release RockFrontend - a frontend module that can render latte files and comes with several other nice frontend helpers ? ----- Breadcrumbs the Latte+PW way: <ul> <li n:foreach="$page->parents()->add($page) as $item"> <a href="{$item->url}" n:tag-if="$item->id != $page->id"> {$item->title} </a> </li> </ul> The cool thing here is that the last item (the page we are currently viewing) is NOT linked. The <a> tag is only rendered for all other items. Still the label of the link is rendered, because we are using n:tag-if and not n:if ----- Output an image, but only if it exists: <img n:if="{$page->yourimage}" src="{$page->yourimage->maxSize(400,300)->url}" alt="..."> Note that the ->maxSize() call will NOT throw an error even if you didn't upload an image! This is one of my favourite features of latte: Write the markup once and then add simple instructions directly within that tag. No more if/else/foreach chaos ?3 points
-
I'll release RockFrontend very soon that does exactly that. It will support LATTE for templates (if you want), LESS for stylesheets (if you want) and comes with zero-setup autoloading (both on the frontend and backend). And you can inject scripts from your modules: $rf = $this->wire->modules->get('RockFrontend'); $rf->styles('head')->add(__DIR__.'/mystyle.css');3 points
-
True, that's why some of my new modules will work on the frontend by default if the site is using RockFrontend for the frontend. Otherwise users will have to include scripts and styles the boring old way... I've done it similar on many many sites. But it did not feel right. Too much "foreach" and "if/else" in my templates... Also things look easy at first thought (using FilenameArray), but then you notice it's not enough... What if you wanted to add a custom property to your tag like "defer"? That's another if/else in your template. What about a cache busting timestamp? Another few lines and checks you have to do, because ProcessWire does not have a nice way to convert between paths and urls, which you need, because you need the path for filemtime() but the url for the html tag... What if you wanted to add a script only on several pages or page types? Another if/else (how many do we have until now?)... What if you wanted to use LESS instead of CSS? Another module, some more lines of code... What if you wanted to add all stylesheets of a folder, so that you can split your CSS into logical pieces and move components from one project to another easily? You'd need to add all those files to your main markup file manually... All that is solved by RockFrontend: <?php namespace ProcessWire; /** @var RockFrontend $rockfrontend */ $body = $rockfrontend->renderLayout($page); ?><!DOCTYPE html> <html lang="de"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <?= $page->seo ?> <?php echo $rockfrontend->styles('head') ->add('theme/uikit.theme.less') ->addAll('sections') ->addAll('/site/assets/RockMatrix') ->addIf("theme/blogitem.css", $page instanceof Blogitem) ->addIf("theme/newsitem.css", "template=newsitem") ->add('https://use.typekit.net/xxx.css') // adobe fonts ->render(); echo $rockfrontend->scripts('head') ->add('theme/js/uikit.min.js') ->add('/site/modules/RockFrontend/lib/alpine.min.js', 'defer') ->add('/site/modules/RockFrontend/RockFrontend.js', 'defer') // when logged in rockfrontend will inject Alfred.js here! // don't remove this rendering block even if you don't add custom scripts ->render(); ?> </head> <body> <?= $body ?> </body> </html> And since I'm rendering the layout in line 3 (above the <head>) I can inject scripts and styles from any other file that is loaded for rendering.2 points
-
Have to agree with this one — it would be nice if we had a standard approach for this. Having built some plugins for WordPress recently, I must say that it's nice to have a "standard" way to inject scripts/styles. And of course that applies to site development as well ? $config->scripts and $config->styles are currently the closest equivalent to wp_enqueue_script/wp_enqueue_style we have, and some folks do indeed use them for their front-ends. But this is not particularly "well supported", there's nothing like the "deps" array from WordPress, etc. Additionally there's one pretty big issue: some modules don't check for e.g. admin context before pushing stuff to said config arrays, and that can easily lead to admin stuff "leaking" into the front-end. This is the biggest reason why I don't rely on these (on the front-end) myself ? If this was to be implemented in the core (not saying that it should, just thinking out loud), it might require a whole new concept — something like wireEnqueueScript($script, $deps). And, of course, we'd need to accept that it depends on the site whether this would work or not. To be fair, it's really the same for WordPress: unless theme calls wp_head() and wp_footer(), enqueue functions won't do much. So even there it's up to the theme to make sure that they work. Site-specific things can of course be cooked up already. Or approaches specific to individual output modules/frameworks, like the approach that Bernhard mentioned above. -- Just for reference, here's what I've done on some sites — probably not a big surprise that I'm using Wireframe here, and also running things through ProCacheBuster: // site/templates/wireframe.php echo $wireframe->render([ ... 'footer_scripts' => new FilenameArray(), ... ]); And then in layout file: // site/templates/layouts/default.php <?php if ($footer_scripts->count()): ?> <?php foreach ($footer_scripts as $footer_script): ?> <script src="<?= $buster->url($config->urls->resources . $footer_script) ?>"></script> <?php endforeach; ?> <?php endif; ?> </body> </html> This way I can push scripts to $view->footer_scripts from anywhere within the site (usually from Controller classes or individual views), and those get injected to the site's (global) footer.2 points
-
I have also been using Latte for a few weeks. Thanks to Bernhard ? It's just so awesome to use latte. But you also learn new tricks every day. I'm looking forward to the public version of RockFrontend (by the way a brilliant module ? thanks again Bernhard!)2 points
-
Just a little rant: Please don't turn our textarea/RTF-fields into something like Gutenberg or similar. As a module, ok. But please... not as the default option. I'm not that deep into all the details about those RTF-Editor tools/scripts but what's so bad about staying with CKEditor 4.x for a while as it's stable and mature enough. Never had any issues with it.2 points
-
I just wanted to mention that I hope that our new editor will still be a rich text editor and not a page builder (like the mentioned "article" editor) - imho we should not mix those two! I've done a lot of work and research in that regard over the last two years or so and I'm now very happy with my repeater based content builder. When I started I also looked at editor.js as the interface looked neat. But I couldn't even manage to build a single custom content element with it. It's an editor for JS artisans and not for PHP devs like me (us?). A repeater based content builder has the huge benefit that we can simply use all the existing fields that PW provides. If at some point someone created a new field that would most likely just work within a repeater. Having a new editor interface with a totally new storage concept would mean we'd need to build all those block's for the editor and we could not use them outside of it. What about Multi-Language? The example above shows a nice page builder, but I wonder how multi-language would work with such a field? In a repeater-based setup we can just install LanguageSupport and make those fields translatable. PS: Using a matrix based approach makes CKEditor fields usually super simple! Like this one where only bold text and links are allowed:2 points
-
Sorry, me again. ^^" I just realised that the chosen shipping method is not visible in the backoffice in the order page. How can I add it ? The owner of the shop need to know how he need to send the products ? I would like to add some info on the confirmations pages (success for example) for the customer bases on the choice in shipping method, like display the shop address if they had decided to come retrieve the order at the shop. in order-complete.php, if I bd $order, I can only see the shipping fee, and no info on the shipping method1 point
-
You know what they say about opinions ? Seriously though, I get your point, and I'm a big fan of keeping code (or rather unnecessarily complex logic) out of the view layer myself. That being said, I don't mind a few foreach and if/else blocks here and there, as long as it doesn't get out of hand. Looking at my example above, that first "if" seems to be pointless; for a simple use case like this, here's all we really need: <?php foreach ($footer_scripts as $script): ?> <script src="<?= $buster->url($config->urls->resources . $script) ?>"></script> <?php endforeach; ?> That's three lines. There's also no cache busting required here, since we're using $buster (and there are also non-commercial alternatives, like Pete's Minify module or AIOM) ? This is absolutely true. FilenameArray is a rather limited/limiting tool, best suited for relatively simple use cases. In the example above I used that because it was enough for that particular use case. And, to be honest, it's been enough for most use cases for me — but if something more nuanced is needed, then another data type (or another approach altogether) is likely going to be a better choice. From my point of view the first one here is not a big issue (I don't usually have that many scripts, so this can be handled with a couple of if-else blocks at tops, or a variation of the technique mentioned above, or Wireframe's placeholders) while other two I prefer to handle via build tools. This is not to say that these are not real concerns, mind you — just that they are (mostly) non-issues for me in my workflow ?♂️? Anywho, it'll be interesting to check out RockFrontend once it's available. It sounds like an interesting tool ?1 point
-
I guess you are adding the hook in init(). If you add it at ready() it will work. Init() is too early for the system to know anything about the user or the language... I think my explanation above is wrong - it works because of the way my language switcher for tracy works! I've updated the code which works for me: $wire->addHookAfter("/foo", function($event) { // first we get a fresh copy of the current user $user = $this->wire->pages->getFresh($this->wire->user->id); $lang = $user->language; // then we set the correct language to retrieve values $this->wire->user->language = $lang; // output to check results $title = $this->wire->pages->get(1)->title; return "user name = $user->name, language = $lang, homepate title = $title"; }); So you are right, the hook does not seem to have the correct language of the user by default. Which it should I guess. Maybe open an issue on github?1 point
-
Thank you, Andy. The steps were slightly different through my provider, but it seems ZIP was enabled anyway. I tried again to enable debugging in config.php, and for some reason it worked now. Could it be a caching problem somewhere, maybe, as I had just updated ProcessWire before posting my initial message here?1 point
-
Using RockFrontend your code would be like this: <div class="header_navigation block"> <div class="header_language block"><?= $rf->render("partials/header_language") ?></div> <div class="header_navbuttons block"><?= $rf->render("partials/header_navbuttons") ?></div> </div> Which is the short version of this: <div class="header_navigation block"> <div class="header_language block"><?= $rockfrontend->render("/site/templates/partials/header_language.latte") ?></div> <div class="header_navbuttons block"><?= $rockfrontend->render("/site/templates/partials/header_navbuttons.latte") ?></div> </div> But you can also use latte's include: https://latte.nette.org/en/tags#toc-include What more could I say than I love it? I'll share more examples here in the thread when they pop up in my work. And I'll release RockFrontend very soon (just need to do the showcase video...) Just wait for RockFrontend ? Or see here: https://latte.nette.org/en/develop1 point
-
Thanks @Jan Romero - I am running the latest version from the modules directory, but I see that your fix was implemented since it was last updated - looks like it needs a version number bump here to force an update.1 point
-
Are you on the latest version? That looks very similar to the error I mentioned above.1 point
-
1 point
-
How to enable archive support in PHP. Your web hosting provider must have these options enabled when running PHP. If you control this yourself, add these keys on the PHP command line: --with-bz2=/usr --with-zip --with-zlib Detailed instructions are here: https://bobcares.com/blog/enable-php-zip-extension-cpanel/1 point
-
There are already good guides on the internet on how to update ProcessWire! Look here: How to upgrade ProcessWire to the latest version or here ProcessWire Upgrade (ProcessWireUpgrade) - ProcessWire Module1 point
-
Hmm. Wordpress uses a script/styles wp_enqueue_scripts hook and a wp_enqueue_script/style function that is quite intelligent. It allows you to enqueue a script and any dependencies. WP then makes sure the dependency is loaded before the script that depends on it. Even if the dependency is not itself queued to be loaded on that page, the dependency argument will force it to be loaded. https://codex.wordpress.org/Function_Reference/wp_enqueue_script For instance, if your script depended on jquery but jquery was not loaded by default (or you wanted to ensure it was), doing this... function my_scripts_loader(){ wp_enqueue_script('my_script_handle', 'my_script_url', array( 'jquery' )); } add_action( 'wp_enqueue_scripts', 'my_scripts_loader' ); ...would load the script previously enqueued with the handle jquery. And then if your script was itself needed for another dependent script, you could: function next_script_loader(){ wp_enqueue_script('next_script_handle', 'next_script_url', array( 'my_script_handle' )); } add_action( 'wp_enqueue_scripts', 'next_script_loader' ); So the script load order would be: jquery my_script_handle next_script_handle Scripts/styles enqueued this way are spat out in the wp_head or wp_footer template function. There's an in_footer argument for putting a script in the footer. Probably wouldn't be hard to use that system in PW core, or roll your own. It's all about queueing the enqueued scripts and loading any given dependencies in the right order.1 point