-
Posts
6,671 -
Joined
-
Last visited
-
Days Won
366
Everything posted by bernhard
-
How would you opt to do a date field with optional DD/MM?
bernhard replied to cst989's topic in General Support
I think the simplest solution would be to use a regular text field and additionally create a hidden datetime field. Then you add a hook on saveReady that populates that datetime field via something like strtotime(...). But it depends who inputs dates... only you? Or also others? Then you need to be more careful with input and maybe provide 3 inputfields, one for day, month, year. That could also be done with a hook. -
[solved] Rock page builder & page references
bernhard replied to Atlasfreeman's topic in RockPageBuilder
Do you mean that the hidden field only get's updated when the page is saved in the backend and not when the block is edited via frontend editing? This is correct but can be optimised so that you don't even need a backend save. Are you using custom page classes for the page that the ArchiveFilter block lives on? -
Hey @FireWire could you please try the latest commit of the dev branch, that should make wire() etc available in all latte files π
-
[solved] Rock page builder & page references
bernhard replied to Atlasfreeman's topic in RockPageBuilder
Ok while reading this I think it's worth sharing the other technique as well, as this might be even easier... The trick is to add a hidden field to your $page, like "post_author". That could be a page reference field. Then you add a hook on "Pages::saved" and you populate that field based on the $block's selected author. Then you can use a selector as usual: $posts = $pages->find("template=blogpost, post_author=123"); This has the benefit that you can use efficient queries and sorting etc. and you can rely on PW's find() for only finding published pages and such. -
[solved] Rock page builder & page references
bernhard replied to Atlasfreeman's topic in RockPageBuilder
Hey @Atlasfreeman thx for your question. As you already mentioned correctly if the page reference field is in a block, when using a selector with that page reference field, you will get the $block and not the $page where the $block lives on. Let's say we have a block "Authors" and there we have a page reference field to select an author. We can get all these blocks like this: $blocks = $pages->find('my_author_field=123'); Then you can loop over these blocks and get the related $page: echo "<p>Blog Posts by this Author:</p>"; foreach($blocks as $block) { $page = $block->getBlockPage(); // maybe add some additional checks here, eg check if $page is published etc. echo "<div><a href='{$page->url}'>{$page->title}</a></div>"; } That should be all you need. If that is not performant enough because you have to query a lot of pages let me know and I'll show you a more advanced technique. Also it might be necessary to add something like "include=hidden" or "include=all" to the selector of the blocks, I'm not sure. If you need any more help with that let me know. Otherwise please share the working example once you are done and mark the topic [solved] thx π -
RockShell - a ProcessWire Commandline Companion β¨οΈ
bernhard replied to bernhard's topic in Modules/Plugins
We have a new command to create modules π The cool thing about it is that it creates all necessary files to get fully automated releases using the following file structure: This might be interesting for you @DrewPH -
Great π Have fun!
-
Sounds like a nice module π Just a FYI there is also https://processwire.com/store/pro-dev-tools/wire-request-blocker/ which blocks unwanted requests efficiently via .htaccess π
-
To be honest I'm not 100% happy with this feature either, but it is used on all of my websites and that would mean a lot of refactoring. There are several reasons why I built it like this (for example I advertised the module as "zero setup", so it needs to work without prior hunting through docs and adding scripts here and there), but there are also some problems that I didn't think of upfront. For example the current implementation does not work with template cache. RockFrontend has a setting for this in the module settings and now RockPageBuilder also has one. Please download v5.7.0 π
-
This sounds like a perfect use case for RockGrid, if your clients have 65β¬ left (docs are under construction but if you need help I'm around). But again you have several options. You could also use regular page listers. Or you can use Lister Pro. When using RockGrid you get any table shown at https://tabulator.info/ Or you could create a custom admin page and build a custom tabulator yourself. It's not that hard if you know JS and HTML. RockGrid comes with a lot of extras, like SSE for bulk operations, action buttons (including ajax operations) etc., but if you just need a table then it's quite easy to just add a tabulator table to the backend. Oh, and we have the relatively new PageListCustomChildren
-
We always have to deal with exceptions, right? I'm always using the $rm->setPageNameFromTitle() helper that will update the pagename according to the page title on save. That's easy to do in a MagicPage: public function init(): void { $rm = rockmigrations(); $rm->setPageNameFromTitle($this); } But what if we wanted to make sure that one page has a custom page name that can't be changed, so that we can rely on the url eg in a fetch() call? public function onSaveReady(): void { if ($this->id === 6840) $this->name = 'versandkosten'; else rockmigrations()->setPageNameFromTitle($this); } We have to use the magic "onSaveReady()" method, because in init() and in ready() we cannot use $this to access the current page, because init() and ready() are triggered on a NullPage object and not the page itself. The reason for this is interesting but not for this post π
-
Hey @nurkka thx for your questions! What do you mean exactly? Which modules did you install? This is expected. RockFrontend will only compile all .less files to one.css file. All other files will stay single files. This is because on some pages we might need some scripts, on others not. If all were compiled to one single file we'd have different files on different pages or we'd keep recreating this file over and over again when viewing different pages. At the moment no, for the mentioned reason. I thought about adding such a feature, but I think it would cause trouble. RF/RPB try to be as unopinionated about the frontend as possible, but some things need to be there to make it work. Can you please show me the content of these files?
-
I've mentioned several times that one reason why I love latte is that LATTE == PHP (almost) This tool shows what I mean: https://php2latte.nette.org/ @FireWire
-
Hey @FireWire thank you for the composer file, that helped! Sorry to say that, but this is nonsense π I didn't know for certain, but from my understanding if I do "composer require latte/latte" it should not matter WHERE I do that as long as I use the correct path in my require_once /path/to/autoload.php So I tried doing "require_once /path/to/rockfrontend/autoload.php" above the CustomLatteExtension class and that fixed my error. The reason is simple: In ready.php the latte autoloader was not available, because I have added the "require_once /path/to/composer/autoload.php" in the "loadLatte" method of RockFrontend, since I thought it would be more efficient to only load it if needed. I think that was wrong and I moved it into init(), because that's the whole purpose of the autoloader... to load things only if necessary, right?! So with the latest version on the DEV branch you can add your extension without installing anything in your root folder and without adding any require_once anywhere. I experimented with this: <?php namespace ProcessWire; use Latte\Extension; final class CustomLatteExtension extends Extension { /** * Define functions available in all Latte files * These can be anything ProcessWire related or not, any functions defined here will be available everywhere */ public function getFunctions(): array { $functions = []; foreach (wire('all')->getArray() as $key => $value) { if (!is_object($value)) continue; $functions[$key] = fn() => $value; } return $functions; } } But that is not a reliable solution. I'll ask for help in the nette forum. I think the only reliable solution would be to add the ProcessWire namespace to all compiled latte files. That sounds like side effects though. But we'll see...
-
This is what RockFrontend has in its composer.json: "require": { "latte/latte": "^3", "sabberworm/php-css-parser": "^8.4", "matthiasmullie/minify": "^1.3", "wa72/htmlpagedom": "^3.0", "baumrock/humandates": "^1.0" }, How does your composer.json look like?
-
I've recently hit 10.000 views on my youtube channel (over all videos since the beginning 2+ years ago) π₯³ I'm counting 218 subscribers and all have watched 800 hours of (almost only) ProcessWire content. The best performing videos so far are: Recent videos have been by far less popular. I don't know why. Maybe it's the thumbnail. Maybe the video length (the RockFrontend video is over 40min long!). Maybe it's the algorithm. Who knows. But Ive learnt a lot and recently I found a way to be more efficient with creating those videos - unfortunately I didn't get any feedback in that regard, but feedback is rare on my channel in general. Maybe that's part of the youtube game π So I'm asking here: What is your opinion about these videos? Are the videos helpful? Could anything be improved (easily π )? What would you like to see as a next video? RockMigrations Deployment RockMigrations in general More about RockFrontend More about the commercial modules Less about the commercial modules Anything else? Thanks for "watching" and have a great weekend π
-
In ProcessWire as always you have the freedom to choose from a variety of options. What fits best for you and the editors depends on a lot of factors, but I'd say your options are (from easy, but with default style and options to hard with full freedom): Stick with PW page tree, organise your pages well and properly define access of your users so they see only what they need to see. That's probably the easiest solution, but you get the default PW backend which has pros and cons. Use a module to adjust the backend to your needs. Possible modules are AdminRestrictBranch or the dashboard module. Or any other module that helps you to customise the backend. Create custom admin pages. This is still very easy and you stay in the "safe" PW backend, which means you don't have to take care of everything on your own and you can build on top of proven and battle-tested concepts and code. Create a custom backend. The ProcessWire backend is on its own just built around the PW api, so you can build something similar on your own. This is by far the option with most freedom but also the hardest option, as you have to take care of almost anything (access control, rendering, navigation, etc...) Somewhere in-between those options might be to enhance your frontend with some shortcuts, like buttons to "add new blogpost" or to "manage items" or whatever. These buttons could directly link to backend pages, so it might be easier for clients to find what they need, because what many often forget is that even though the PW backend is super clean and easy to use, there is a barrier or gap between "frontend" and "backend" that for clients is sometimes harder to grasp than one might think! RockFrontend, for example, comes with ALFRED, which adds hover info with an edit icon: And when clicked it opens the dedicated page from the backend directly in a modal in the frontend: There are other modules with similar solutions as well. You have the freedom to choose π
-
Thx, but I don't think it's very smart π It's really just PHP, that's one of the main reasons why I like latte so much. They don't reinvent PHP or invent another syntax, they just use PHP and add some helpers here and there. It's really easy to understand, for example create the file php-demo.latte: {file_put_contents('php-demo.txt', 'latte-is-cool')} This will do two things: It will create the file php-demo.txt in the folder of the .latte file It will output "13", which is the strlen of "latte-is-cool" You can think of { ... } being similar to <?= ... ?>. That's why tracy will instantly work inside latte via {bd(...)} as bd() is a globally available function without any namespace and it does not return/output anything. To prevent our previous example from outputting anything you can simply add "do": {do file_put_contents('php-demo.txt', 'latte-is-cool')} Also when using {var $foo = 'whatever'} there is no output. Now consider the following file "php-demo.latte": {wire()->page->id} This will cause the following error: You can click on "PHP" and then you see which file it actually renders and why wire() is not found: Once you click on that file link, it will open up in your IDE: So you can see that this is the compiled PHP file that latte uses to render your .latte file. And your IDE shows, that wire() is not available! So using our IDE we can fix the issue: Which will add this to the PHP file: Now since we can't add the use statement to our latte file like this: {use function ProcessWire\wire} {wire()->page->id} We just use the inline syntax for namespaced functions: {ProcessWire\wire()->page->id} And that's all you need to understand π But I'll probably add the functions api without namespaces to all .latte files once you help me get the mentioned issue sorted π
-
Hey @FireWire thank you very much for taking the time to explain everything. That's great and I understand now! I have an idea, but I tried adding your example to /site/ready.php and I get this: This is my ready.php: <?php namespace ProcessWire; if (!defined("PROCESSWIRE")) die(); /** @var ProcessWire $wire */ $rockforms->setErrors('de'); use Latte\Extension; final class CustomLatteExtension extends Extension { /** * Define functions available in all Latte files * These can be anything ProcessWire related or not, any functions defined here will be available everywhere */ public function getFunctions(): array { return [ 'wire' => fn(?string $property = null) => wire($property), ]; } public function getFilters(): array { return [ 'bit' => fn(mixed $value) => new Html(filter_var($value, FILTER_VALIDATE_BOOLEAN) ? 1 : 0), 'bitInverse' => fn(mixed $value) => new Html(filter_var($value, FILTER_VALIDATE_BOOLEAN) ? 0 : 1), ]; } } $wire->addHookAfter( "RockFrontend::loadLatte", fn(HookEvent $e) => $e->return->addExtension(new CustomLatteExtension), ); Do I have to require_once something? I have never added a custom extension yet.
-
Looks great. Wouldn't that be worth a PR?
- 2 replies
-
- 2
-
-
- module
- dependencies
-
(and 3 more)
Tagged with:
-
Hey @zoeck thx yeah that test2.l was helpful and I've fixed that in v3.21.2
-
Some of you may be interested to know that yesterday I released RockCalendar, which also has recurring events and will be actively developed and maintained for the foreseeable future:
-
Hey @zoeck thx. I just tried and it seems to work. What exactly do you mean by "didn't work"? Steps to reproduce please.