Leaderboard
Popular Content
Showing content with the highest reputation on 09/05/2022 in all areas
-
Thank you for all your valued feedback so far. This is an opinionated setup, like almost all of webpack setups are in a way. I'm using this as a working starter and therefore tried to keep it as lean as possible, only concentrating on tailwind, postcss, babel. If I needed to add other libs like Alpine etc. it can be easily extended.3 points
-
With AppApi's new version 1.2.4 we now use URL Path Hooks! The old ProcessPageView::pageNotFound hook still remains, but is only used as a fallback if the ProcessWire version does not support the url path hooks. Thanks to @kongondo and @adrian who kept pushing me in the direction of including url path hooks! I also revised the logging a little bit. In the access log (which can be activated via the module settings) the correct paths from the request are now entered. And an entry in the access log really only occurs if no error has occurred. Otherwise an entry is triggered in the appapi-exceptions log. You can download the new version now in the ProcessWire modules page, Github or via auto-update in your ProcessWire UI. Thanks for using AppApi! ?3 points
-
That's true. Sadly I am a performance junky and interested in new and shiny things, and so I try out almost everything. Another hint: Use bun instead of npm for installing npm modules. It is sooooo much faster. It can do much more, but I use it just as a npm replacement for now.3 points
-
@pwired sure, here you are. site/templates/fields/sections_next.php This file is responsible for outputting rendered HTML for the field called `sections_next`. It's called with the `$value` set to the value to be rendered, which in this case is a field of type PageTableNext. <?php namespace ProcessWire; /** * @global Page $page * @global PageArray $value * @global Field $field * @global Pages $pages * @global Config $config */ ?> <div style="margin:1rem;border:solid 1px yellow; background:#ffffe0;padding: 1rem;"> This is sections_next.php <?php if(!($value instanceof PageArray)) return; foreach($value as $contentElement) echo '<div style="border:solid 1px #fc0;background:#eefff8;padding:1rem;margin:1rem;"> The following is rendered by ' . $contentElement->template->name . '<br />' . $page->renderValue($contentElement, ($field->pathToTemplates ?? '') . $contentElement->template->name) . '</div>'; ?> </div> site/templates/fields/sections/hero.php This file and the one that follow are two example possible section/paragraph/block types. For my proof of concept, I created a "hero" one and a generic "section" one. This hero one crudely renders a big background image with some big text over the top. <?php namespace ProcessWire; $image = $value->background_image; $thumb = $image->size(1920, 700); ?> <div style="background-image:url(<?php echo $thumb->url ?>); padding: 4rem;margin: 0 0 2rem 0;min-height:60vh;"> <p style="color:#fc0; font-size:3rem; font-weight:bold; text-align: center; line-height: 1.4;"> <?php print $value->title; ?> </p> </div> site/templates/fields/sections/section.php The 'section' type has a body field and a select field letting the user choose Blue/Mauve/None for the background colour. <?php namespace ProcessWire; // here, $page is the main page tht was requested; $value is the Page object being rendered, the 'section'. ?> <?php $map = ['Blue' => '#0284ea', 'Mauve' => '#f0ddff', 'None' => 'transparent']; $selected = $value->background_colour->title; $bg = $map[$selected ?? 'None']; ?> <div style="border:solid 1px #cf0;background:<?php echo $bg; ?>; padding:1rem;margin:1rem;">This is section.php, rendering <code>$value</code> <h2>title: <?php print $value->title ?></h2> <p>colour: <?php print $value->background_colour->title ?></p> body: <?php print $value->body ?> </div> Other files Now the instructions for PageTableNext (ptn) tell you to copy some other files into your templates dir, but I've not figured out why! e.g. The instructions made me copy a file from the module to site/templates/PageTableNext/ptn.php, however I put exit() at the top of that file to test whether it was ever used and I've not found it to be doing anything, so I don't understand that! Here's my demo page content: In the editor it looks like this: ➊ shows the three blocks/sections/... that I've added (with the buttons at ➌). I clicked the arrow to 'open' the third section and you can see it at ➋ rendered using just the site/templates/fields/sections/section.php file. The UI is pretty nice; you can edit each section, move them around etc. Oh, one other thing, in the main page template (e.g. basic-page.php) you need to render the field that contains all the blocks/sections/etc. like so: <?php // If using 'delayed' output: $content = $page->render->sections_next; // If using 'direct' output echo $page->render->sections_next; One interesting thing is that if you use delayed output then your site/template/{page-type-name}.php needs to populate $content (or whatever vars you use in _main.php). However, the field templates all just use echo/print because they are rendered with output buffering capture. Hope this helps! It might help me too when I come to actually make a site with PW instead of just playing!2 points
-
What about we make this some kind of universal profile which works with webpack, bun, npm, yarn, vite... whatever. Or at least use this a guide for setting up all of those different setups. I never really used any of these tools - at least six months or so ago - right now I use NPM due to other tools I use now and therefore kind of started to like it (and as it's super portable through all OS I use, have to use or play around with). As soon as I am back at home I could provide a NPM/TailwindCSS/AlpineJS/browser-sync setup. Pre-Version of the mentioned above can be found here: https://github.com/webmanufaktur/processwire-addon-tailwindcss-alpinejs-barbajs2 points
-
You cannot use $config (or other variables such as $page, $pages, etc) inside a function. They are out of scope. Use wire('config') instead.2 points
-
Hi @kalimati, Apologies for the late response. I wasn't able to use the excellent idea by @flydev ??, i.e. HX-Redirect. It wouldn't work for me. Nothing happened at all. However, we can use htmx:afterSettle and redirect using vanilla JavaScript. I have created a demo for the whole thing here in Demo-4 in the demos repo. See the README for more details. Please let me know if you have any questions. Next I'll work on a demo with respect to your question about a minimal checkout form.2 points
-
That sounds intriguing. I'm happy with my setup and the build time is pretty fast already. Seems like every couple of years a new tool is being hyped as faster, easier, better etc. I'll definitely have a look at vite but for the moment I'm going with webpack. A repo where we can look at some vite setup code with PW would be welcome. Don't think it is necessary to have a tutorial, though. I am sure there are tons out there already. But thank you.2 points
-
Hi @gebeer. Using webpack nowadays feels a little bit outdated for me, because with vite (from the creator of vue.js) setup is so much simpler and faster, and it comes with first-class support for most frameworks like Tailwind or vue out of the box. But it can't do all things webpack does (not yet). Two or three years ago I used a similar approach to what you did now, as you can see in my jmartsch/acegulpandpack: A set of gulp tasks with JS transpilation, webpack, SVG Sprites and minification (github.com) repo. With vite you use native ES modules instead of transpiling and bundling every time something changes. This makes the development process much (MUCH) faster. If you ever seen it in action, you would not like to go back to webpack. If you guys are interested in a modern build environment for your CSS and JS, I could see if I find the time to write a tutorial for it.2 points
-
I have setup a starter kit for developing PW sites with Tailwind CSS. You can find it at https://github.com/gebeer/tailwind-css-webpack-processwire-starter I know, I'm a bit late to the party with Tailwind. In fact I only discovered it a couple of months ago and found it to be a very interesting concept. It took quite some time to get a pure webpack/postcss/tailwind setup that features live reloading dev server, cache busting, supports babel as well as autoprefixing and works well with PW. For the cache busting part I developed a small helper module that utilizes webpack.manifest.json to always load the assets with the correct file hashes for cache busting. No more timestamps, version numbers or the like required. The little helper can be found at https://github.com/gebeer/WebpackAssets Having used it for the first time in production on a client project I have to say that I really enjoy working with Tailwind. The concept of using utility classes only really convinced me after having put it to practice. During the work on the client project, some quirks with webpack-dev-server came to surface. I was able to solve them with the help of a colleague and now it is running quite stable in both Linux and Mac environments. I am fascinated by the fast build times compared to using webpack/gulp or gulp/sass. Also the small file size of the compiled CSS is remarkable compared to other frameworks. So this will be my goto setup whenever I am free to choose the frontend framework for a project. If anyone feels like they want to give it a try, I shall be happy to get your feedback1 point
-
This week on the core dev branch we’ve got some major refactoring in the Page class. Unless I broke anything in the process, it should be more efficient and use less memory than before. But a few of useful new methods for getting page fields were added in the process. (A couple of these were also to answer feature request #453). Dot syntax You may have heard of dot-syntax for getting page fields, such as $pages->get('parent.title') where “parent” can be any field and “title” can be any field that has subfields. This is something that ProcessWire has supported for a long time, but it doesn’t get used much because it was disabled when output formatting was on. So it wasn’t something you could really count on always being there. Now you can — it is enabled all of the time. But it’s also been rewritten to be more powerful. When using dot syntax with a multi-value field (i.e. any kind of WireArray value) you can also specify field_name.first to get just the first value or field_name.last to get just the last value. i.e. $page->get('categories.first'); will take a value that was going to be a PageArray (‘categories’) and return just the first Page from it. Bracket syntax With bracket syntax you can call $page->get('field_name[]') with the (‘[]’ brackets at the end) and it will always return the appropriate array value for the type, whether a PageArray, WireArray, Pagefiles/Pageimages, or regular PHP array, etc. This is useful in cases where you know you’ll want a value you can foreach/iterate. Maybe you’ve got a Page field that set set to contain just 1 page, or maybe you’ve got a File/Image field set to contain just 1 file. But you want some way to treat all of your page or file/image fields the same, just append “[]” to the field name in your $page->get() call and you’ll always get an array-type value, regardless of the field settings. This bracket syntax can also be used for getting 1 value by index number. Let’s say you’ve got a page field named “categories” that contains multiple pages. If you want to get just the first, you can just call $page->get('categories[0]'); If you want to get the second, you can do $page->get('categories[1]'); This works whether the field is set to contain just one value or many values. Using the first index [0] is a good way to ensure you get 1 item when you may not know whether the field is a single-value or multi-value field. Another thing you can do with the bracket syntax is put a selector in it to filter a multi-value field right in the $page->get() call. Let’s say you want all categories that have the word “design” in the name. You can call $page->get('categories[title%=design]'); If you want just the first, then $page->get('categories[title%=design][0]'); What’s useful about using selectors in brackets is that this does a filter at the database-level rather than loading the entire ‘categories’ field in memory and then filtering it. Meaning it's a lot more memory efficient than doing a $page->get('categories')->find('title%=design'); In this way, it’s similar to the already-supported option to use a field name as a method call, for instance ProcessWire supports $page->field_name('selector'); to achieve a similar result. Dot syntax and bracket syntax together You can use all of these features together. Here’s a few examples from the updated $page->get() phpdocs: // get value guaranteed to be iterable (array, WireArray, or derived) $images = $page->get('image[]'); // Pageimages $categories = $page->get('category[]'); // PageArray // get item by position/index, returns 1 item whether field is single or multi value $file = $page->get('files[0]'); // get first file (or null if files is empty) $file = $page->get('files.first'); // same as above $file = $page->get('files.last'); // get last file $file = $page->get('files[1]'); // get 2nd file (or null if there isn't one) // get titles from Page reference field categories in an array $titles = $page->get('categories.title'); // array of titles $title = $page->get('categories[0].title'); // string of just first title // you can also use a selector in [brackets] for a filtered value // example: get categories with titles matching text 'design' $categories = $page->get('categories[title%=design]'); // PageArray $category = $page->get('categories[title%=design][0]'); // Page or null $titles = $page->get('categories[title%=design].title'); // array of strings $title = $page->get('categories[title%=design].title[0]'); // string or null // remember curly brackets? You can use dot syntax in there too… echo $page->get('Page “{title}” has {categories.count} total categories'); I’m not going to bump the version number this week because a lot of code was updated or added and I’d like to test it for another week before bumping the version number (since it triggers the upgrades module to notify people). But if you decide to upgrade now, please let me know how it works for you or if you run into any issues. Thanks for reading, have a great weekend!1 point
-
I'm not using yaml at all. That was just a quick test because many were asking for it. I'm still not convinced. For the same reasons as why I'm not convinced with your approach (at least how I'm understanding it). I guess the reason why our files are similar is no surprise, because our modules describe what PW has to do and of course the data structure of PW is the same for your module and mine. https://processwire.com/talk/topic/26635-add-better-configuration-for-fields-and-templates-and-make-them-version-controllable/?do=findComment&comment=220791 The point here is: I know that when it comes to migrations the "standard" way of doing it is to provide an upgrade() and a downgrade() code. I've started that way too (back in Jan/2019 https://github.com/BernhardBaumrock/RockMigrations/blob/a2b90ba4fc1aa2b4a6c4e1dc976ca644ae492888/.RockMigrationsDemoModule/RockMigrations/0.0.1.php ) Since then it turned out that writing downgrade methods is just a waste of time. I've never - really: never - had the need for a downgrade since then. Usually when developing and when reverting thins a simple db-pull from the staging system is enough and all the changes are gone. No need for a downgrade. If changes have already been pushed to staging/production then of course this method does not work. But the link above shows how easy it is to solve, eg by simply adding this to my migration: $rm->deleteField('my-old-field-that-is-not-needed-any-more') Some may call it an antipattern - but ProcessWire as a whole is a single antipattern and I really like that ? https://processwire.com/talk/topic/26635-add-better-configuration-for-fields-and-templates-and-make-them-version-controllable/?do=findComment&comment=220829 It's not really about liking it or not. It's just not usable for me. Why? It's simple. I like to do things in a modular, reusable way. Without any user input (beside maybe clicking an install button). I like to build modules that can be installed on many websites. And I like to deploy my websites on staging and on production automatically. Or to push changes to a project where another developer just has to do git pull and it will work. How would your module/approach do that? In case you hadn't realised, there is extensive documentation of the module at https://metatunes.github.io/DbMigrate/help.html. So you don't need to install and use the module to get an understanding of what it does. Specifically as regards running code on migrations, see the following sections: https://metatunes.github.io/DbMigrate/help.html#snippets and https://metatunes.github.io/DbMigrate/help.html#hooks. I was confused because you wrote a specific question in my module's thread that I tried to understand, that's why I was asking for a more detailed explanation. All I got was a RTFM-like answer. But you were right, I did not know about your docs. Looks like you have put a lot of effort into them. Still I don't get how you are actually working with the module. And that was what I was asking for. To understand and maybe find a way to get the best of both worlds. If you want to add some kind of yaml recorder or migrations GUI into RockMigrations I'm happy to pull that or to assist where I can. I'm just not adding it myself unless someone pays me to do it. Simply because I'm at the moment 90% sure that such a tool will not work for me and therefore I don't need it. But the "migrations code" inspector field is a feature coming from a push by the community, so maybe there'll be other useful things along the way as well.1 point
-
OK after some reverse-engineering, for lack of a better word… no actually reverse-engineering actually nails it. I found out that the fieldgroup's name needs to match the template's name. Once this is ensured, it works, then you can edit/remove/add/shuffle fields, all the good stuff. You're welcome ?1 point
-
1 point
-
You can do that: if($modules->isInstalled('YourModule')) { $m = $modules->get('YourModule'); echo $m->foo(); }1 point
-
If anything tries to access your module than it will auto-install it. Maybe you have a $modules->get('YourModule') somewhere in your frontend?1 point
-
1 point
-
1 point
-
Look at this example. Its made with the old version of RestAPI first made by @thomasaull years ago. To get the context, you can navigate to https://kingspark.fr and https://valideur.mykingspark.fr . I am speaking about a system which give the possibility to some of our client use their mobile or a barcode scanner device to give "free of charge parking" of their customer. Its composed with custom hardware, software and devices or mobile apps (you see it on GooglePlay). Image #1: List of Parkings // Image #2: The custom made SAGAS Terminal // Image 3: A configured User / Device available for registration and use. On the first picture, you can see a list of "Parkings", and some can have the "Valideur" functionality. We can configure attached devices and some users with specific role to get access for registration. And then, imagine the following. A customer land on the parking, grab a ticket and go to their rendezvous At the end, the guy in the office use his "Barcode Scanner" to "validate" the ticket of the customer; This mean that the customer will not pay anything when landing on the terminal to exit the parking, and when he will present the ticket on the barcode-reader installed on the terminal (the "black hole" you can see on the center in the picture), it will be recognized by another software and thought a call on ProcessWire Rest API backend. I made you two screencasts, the first is the software which once installed and registered, get the quota (number of validation available) from the user assigned to the license-code, and the second is my mobile which get notification sent from ProcessWire (by this module) from a monitoring system to get real-time information on registration. If you have any question, do not hesitate. There a more example, but you should get the whole idea ?1 point
-
Same here... used both in the past until now... almost each day I work with PW and forgot something however. Those are my most used bookmarks across all browsers. Maybe we (the Mods) could update the very first post or add an alert or something. Those resources are key!1 point
-
Regarding the required field, you are not only setting a value, but the first empty option also has a value. Try it like this: array( 'name' => 'content', 'label' => 'Content type', 'description' => 'What is this content for?', 'type' => 'select', 'required' => true, 'options' => array( '' => 'Choose One', '1' => 'category1', '2' => 'category2', '3' => 'category3', '4' => 'category4', '5' => 'category5' ) ) Regarding the memory errors - I don't think that can be specifically related to this module. As for outputting more content, so you output whatever you want by assigning the html to: $this->output = 'my HTML output';1 point
-
@dotnetic thanks for posting about bun, didn't know about that one. Never did anything with javascript outside of the browser. Going trough the docs on https://bun.sh/1 point
-
Thx for the links ? I remember I've also started with both and they were a great help! I just realised that it seems we have no list of all available hooks online somewhere? I'm always looking that up in my IDE (or tracy), but for newcomers such a list (as captain hook) is for sure interesting.1 point
-
I think the cheatsheet is here. Maybe just change the link in the original post? I remember starting my way with this cheatsheet. I learned a lot. Not sure if it is up to date, but even as is it could be of a great value to many. Captain hook is also available, just moved to github.io1 point
-
Ryan was quick with this one ? It's now easy and bullet proof: <?php $img = $page->get('images.first'); if($img) echo "<img src={$img->size(200,200)->url} alt=...>"; https://processwire.com/talk/topic/27528-weekly-update-– 2-september-2022/#comment-2263911 point
-
1 point
-
Hi Bitpoet, Eventually you are right. In multi-instance environment, you need to call the first object even the limit of the image filed is set to 1. Maybe this is a bug in multi-instance support. Gideon1 point
-
Hi Tobaco, my setup is always the same. Doesn't matter if I use PageTable or not. Here it goes (simplified): /templates - basic-page.php - home.php - /tpl - main.php - mainnav.php - subnav.php - footer.php The tpl/main.php is the overall template like: <?php include('tpl/mainnav.php'); include('tpl/subnav.php'); include('tpl/slider.php'); ?> <!DOCTYPE html> <html class="no-js"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <title><?= $page->title ?></title> <!--- styles and scripts --> </head> <body class='<?= $bodyclass ?>'> <header> <div class='wrap'> <a href="/"><img src='/site/templates/img/logo.png' class='logo' alt="Logo"></a> <nav class='main'> <?= $mainnav ?> </nav> </div> </header> <?= $slider ?> <?= $subnav ?> <section class="content"> <div class="wrap group"> <h1 class='v2 hide'><span><?= $page->title ?></span></h1> <?= $content ?> </div> </section> <footer> <div class="group"> <?php include ('tpl/footer.php'); ?> </div> </footer> <script src="/site/templates/dist/all.min.js"></script> </body> </html> basic-page template looks like this (every template renders the content and then includes the main template): <?php /** * basic page template * */ $bodyclass='inner'; $content = $page->body; include('tpl/main.php'); With PageTable the structure looks like this: /templates - basic-page.php - home.php - part_text.php - part_columns.php - part_gallery.php - /tpl - main.php - mainnav.php - subnav.php - footer.php The part_* templates are templates only for PageTable. part_columns.php could look like this: <?php $headline1 = ""; $headline2 = ""; if(!$page->checkbox1) $headline1 = "<h2>{$page->title}</h2>"; if(!$page->checkbox2) $headline2 = "<h2>{$page->text1}</h2>"; // Output echo " <div class='pageTableSection {$page->template->name}'> <div class='inner'> <div class='col one-half'> {$headline1} {$page->body} </div> <div class='col one-half'> {$headline2} {$page->textarea1} </div> </div> </div> "; And the basic page template gets enhanced by ("layout" being the PageTableExtend field): <?php /** * basic page template * including PageTable layout parts */ $bodyclass='inner'; $content = "{$page->body}"; if(count($page->layout)>0){ foreach($page->layout as $l){ $content .= $l->render(); } } include('tpl/main.php'); That way, the layout parts are easily renderable in the Admin with PageTableExtended. While writing this, I want to point to another feature of the module. If rendered by PageTableExtended, the template gets an option 'pageTableExtended' which you can use in your part template: // Output echo " <div class='pageTableSection {$page->template->name}'> <div class='inner'> <div class='col one-half'> {$headline1} {$page->body} </div> <div class='col one-half'> {$headline2} {$page->textarea1} </div> </div> </div> "; if(!$options['pageTableExtended']){ // we are not in the Admin, so we include our social media buttons which we only need in our frontend include('social/socialmediabuttons.php); } Hope that helps.1 point