-
Posts
5,484 -
Joined
-
Last visited
-
Days Won
246
Posts posted by bernhard
-
-
I've never tried it myself, but you should never change anything inside the /wire folder. Use /site/config.php instead
-
Why do you want to do that?
You can configure that via $config->pageNumUrlPrefix, but what you are trying to do is not possible by default (and maybe not a good idea at all). By adding the slash you basically let it look like another layer of the pagetree (or of your sitemap), but that's not the case, so I'd say it's logically incorrect. Also see here:
-
1
-
-
Hey @Robin S thx for the helpful module. Used it today for the first time and unfortunately the "open in new tab" checkbox has no effect. I didn't find any occurences of "target" or "_blank" in the module's code, so I think it's missing 🙂
-
1
-
-
2 hours ago, Rasso said:
Not a problem in either WordPress or Kirby. Both allow to create re-usable templates, types and fields and put them in a plugin (=module)
Could you please explain or show how they do that?
-
1 minute ago, Rasso said:
@bernhard do you have a pointer how I could setup that behavior using RockMigrations? I don't want to overstrain your patience, but if you have a few quick links for me I'd be very grateful. I'll make sure to RTFM 😉
Hi @Rasso and also welcome to the forum. I'm always happy to answer questions and I always welcome constructive feedback. I just don't like if people post wrong information about my modules or put them in a wrong context.
Before I explain some things, please have a look at the intro video that I did one year ago. Some parts are outdated, for example the module will not automatically copy snippets to your project, it will ask you before doing so. But all the main concepts do still apply and will likely not change for a long time.
Actually @gebeer the video also shows how to move migrate() code into the pageclass. Totally forgot that 😄
25 minutes ago, Rasso said:*automatically* generate and save migration files every time I create / update any field or template locally
That's not how RockMigrations works. At least not at the moment. And that has several good reasons. I'm not saying that such an approach is bad. But it is very complicated to implement, it comes with a lot of (maybe unsolvable) problems and even if everything worked it has a lot of limitations by design.
I didn't want that for RockMigrations, so I built it differently.
I can understand that it looks overwhelming to write migrations by hand. That's why RockMigrations does a few things more than only migrations. For example adding snippets (if you want and if you are using VSCode), so that you don't have to remember migration code by heart:
If anything is missing in those snippets you can just create that field manually and then inspect the field's migration code:
Or alternatively you will get the key-value pair by just hovering over the setting in 90% of the cases - for example changing the visibility state of the field to "open + locked (not editable)" you'd have to add "collapsed" => 6 to your migration code.
This might be a bit slower than using the gui. And it needs a little time to learn the basics. But once you get the concept it's often a lot quicker than working with the gui. Especially if you have a more professional setup and take the whole picture into account (having a staging / production system for example or working in a team).
But for a quick start: Just install the module and play around with /site/migrate.php
The beauty of that manual approach is that you only write code that you really need. Having a gui that stores a snapshot likely means that you get a bloated json or yaml with a trillion of settings that you don't need and that you might never understand, because you didn't take the time to inspect the whole json.
Manually writing migrations on the other hand means that you get beautiful diffs in your project's codebase:
If you can read diffs you can instantly understand what that migration does, right?
And if you have a look at line 71 you see that I'm using the Inputfield::collapsedHidden constant instead of the integer value 4 which you would get from a gui-based JSON/YAML migration file. I think that's much more readable and a lot easier to understand. And that's just another benefit of taking that extra step of writing migrations by hand instead of letting a tool do it for you.
Another huge drawback of a gui based migrations tool with a central place of migrations is that you limit yourself to the project. Everything you do you do for the project. With RockMigrations you can split migrations into reusable components and place migrations where they logically belong.
You might want to build a blog module that needs to create a "blog-overview" template and a "blog-post" template. Nice! Create those two pageclasses, add a migrate() method with all the template and field settings and voila, you have a module that you can reuse from project to project and only install it where you need it.
Imagine you have built that blog for your project with GUI based migrations... You have another project request with a blog? Have fun, do everything again. Of course that comparison is exaggerated, but you get the point.
RockMigrations is by far my most valuable module. It's stable, actively maintained for years and in daily use in many of my and many others' projects. I released it for free, because I think that this functionality should be built into the core and should be part of every more professional project. I thought we'd see more modules being released by the community, because RockMigrations makes it so simple to create modules that need fields/templates/etc. which is a pain to do with the API. I thought maybe Ryan might see what is possible and join the discussion. And I think it's a shame that ProcessWire is still said to be a good tool only for smaller projects.
Unfortunately I was wrong in many points. But fortunately that does not matter too much. RockMigrations is stable enough so that I don't need a core solution any more. I'm very happy with how it works and how well it plays together with ProcessWire and it's fundamental concepts.
On 11/27/2023 at 12:20 PM, Rasso said:A clean solution for deploying fields between environments and committing them to version control.
RockMigrations offers exactly that.
If you try it and have any questions or you have any suggestions for improvements from your experience with WP/Kirby let me know.
-
1
-
-
2 hours ago, Violet said:
... so it seems a lot more flexible than I first thought! It's not just a "look at stats in the admin panel" thing, it's way more than that. I can query actual numbers of hits for a particular page, sort pages by number of hits, etc.
Note that the module only stores the current count and not all the timestamps of each visit. That means you can get "trending topics" in terms of most views from the very beginning but not trending topics in terms of most viewed in the last 2 days for example.
But you could certainly achieve something like this by hooking into the pageViewTracked event like I did with RockHitCounter: https://github.com/baumrock/RockHitCounter/blob/1bfe2531810d2e9e18177d9975fd4d868fda96a4/RockHitCounter.module.php#L34
-
1
-
-
-
Hi @gebeer no, of course the page class' migrate() method can only be called once the template exists. But that is done automatically by RM if you use the createTemplate() method:
That means all you need is to create your pageclass in /site/classes/FooPage.php and then in your Site.module.php (or wherever else) you do $rm->createTemplate('foo');
This is an example of my modules overview page on baumrock.com where I'm even too lazy to create the view file manually to make the page be publicly accessible, but you can do that manually if you prefer:
<?php namespace ProcessWire; use RockMigrations\MagicPage; class ModulesPage extends Page { use MagicPage; const tpl = 'modules'; public function migrate() { $rm = $this->rockmigrations(); $rm->createViewFile($this); $rm->migrate([ 'fields' => [], 'templates' => [ $this->getTplName() => [ 'fields' => [ 'title', RockPageBuilder::field_blocks, ], 'childTemplates' => [ 'module', ], 'sortfield' => 'title', ], ], ]); } }
This is my migrate() in Site.module.php:
public function migrate() { /** @var RockMigrations $rm */ $rm = $this->wire->modules->get('RockMigrations'); // cleanup/reverts $this->cleanup($rm); $rm->installModule("RockPageBuilder"); $rm->setPagenameReplacements('de'); $rm->setModuleConfig('AdminThemeUikit', [ // use consistent inputfield clicks // see https://github.com/processwire/processwire/pull/169 'toggleBehavior' => 1, ]); $rm->setModuleConfig('ProcessPageList', [ 'useTrash' => true, // show trash in tree for non superusers ]); // install german language pack for the default language // this will install language support, download the ZIP and install it // $rm->setLanguageTranslations('DE'); // $rm->installModule("LanguageSupportFields"); // $rm->installModule("LanguageSupportPageNames"); // $rm->installModule("LanguageTabs"); // $rm->setFieldData("title", ['type' => 'textLanguage']); $rm->installModule("RockPdf"); $rm->installModule("RockMoney"); $rm->installModule("RockSearch"); $rm->installModule("RockMails"); $rm->installModule("RockForms"); $rm->installModule("RockCommerce"); ... // create global fields $rm->migrate([ 'fields' => [ self::field_search => [ 'type' => 'RockSearch', ], ], ]); $rm->createTemplate('pdf'); $rm->createTemplate('modules'); $rm->createTemplate('module'); $rm->createTemplate('release'); $rm->createTemplate('releases'); $rm->createPage( template: 'releases', parent: '/', title: 'Releases', status: ['hidden'], ); ... }
Language specific migrations are commented out for performance reasons and only necessary once or maybe if new updates are available.
-
Thx! Looks like I should update 😄 And great to hear that as this plays well with RockMigration's deployment 👍
-
1
-
-
The "correct output" you are showing is an absolute file path. On websites in the <img> tag you need an url relative to your site's root folder. That would typically be something like /site/templates/img/foo.jpg
Not sure why your path shows "site-news" instead of just "site" though.
-
A note for anybody using RockMigrations deployments: You have to add one line to your /site/deploy.php file:<?php namespace RockMigrations; require_once __DIR__ . "/modules/RockMigrations/classes/Deployment.php"; $deploy = new Deployment($argv); // add this line $deploy->share("/site/assets/div-queue"); // DelayedImageVariations $deploy->run();
Otherwise the queue-folder does not exist after the next deployment and the module throws errors, because the module creates this folder only on installation. -
@iank thx I've just pushed an update to RockFrontend DEV which will soon be merged into main.
Can you please check if it works for you and mark this thread as [solved]? Thx 🙂 And thx for your help in finding the issue!
-
@Atlasfreeman if you find time it would be nice to mark this topic as [solved], thx 🙂
-
@Klenkes if you find time it would be nice to mark this topic as [solved], thx 🙂
-
I don't know of a PW way to do it, but you can quite easily query the DB directly:
<?php // do proper sanitization when using direct SQL queries!! $sql = "SELECT pages_id FROM field_title WHERE data1034 LIKE '%plan%'"; $result = $database->query($sql); $pageid = $result->fetch(\PDO::FETCH_COLUMN);
This returns 1170 for $pageid
So if you modify the query to search for "Paket" in "data1034" this would return false. With a regular PW page selector it would still return 1170 as it also searches in the "data" column.
Note that this query does not take any access control into account.
-
1
-
-
Hey @gebeer it's really the same as with hooks. In the beginning placing all hooks in ready.php is the easiest. Later or on more complex projects it's better to move those hooks into their dedicated page classes.
The concept is simple:
- Everything that belongs logically to FooPage goes into FooPage::migrate()
- Everything that belongs logically to BarPage goes into BarPage::migrate()
- Everything that belongs to the project and nowhere else or that needs to take care of circular reference issues goes into Site.module.php
Site.module.php is a concept that I'm using for several years now and it is great. It's an autoload module that holds all the project specific stuff that belongs nowhere else. Similar to _functions.php but with all the benefits of OOP. Years ago I've created modules named after the project, like for the Foo project it was Foo.module.php and for the Bar project it was Bar.module.php; But I much more prefer Site.module.php which is why RockMigrations offers you to create this module for you (if you want).
Nowadays whenever I'm working on any of my projects I instantly now where to look for: Site.module.php - that saves brain power for more important tasks 🙂
I've done a video about hooks and custom page classes and the same concept applies to migrations (the video starts at the interesting part):
All you have to do is make your custom pageclass a MagicPage and add a migrate() method:
<?php namespace ProcessWire; use RockMigrations\MagicPage; class BasicPagePage extends Page { use MagicPage; public function migrate() { $rm = $this->rockmigrations(); $rm->migrate(...); } }
Then as soon as you save that file those migrations will be fired. And only those. 🙂 There's a reason why these features are built into the module...
-
3
-
Glad to hear some facts from someone actually using my module and not just guessing 🙂
11 hours ago, gebeer said:I have a project with about 4000 lines of migrations for templates, fields, pages and roles in my main migration file and then some additional 1000 lines spread throughout modules and these take about 20 seconds. Since you are not doing migrations all too often, this is very tolerable. Migrations on smaller projects are almost not noticable.
I want to add here that during development it's never ever 20s for me and I'm using migrations all over and all my projects would simply not be doable or manageable without the module. The reason is that I've split migrations into smaller pieces rather than having them in one huge file. If you do that, RockMigrations will take care of only migrating the file that has actually been changed, so migrations during local development are a matter of milliseconds.
For example I'd have a FooPage.php custom pageclass and there I'd add migrations that do stuff related to the FooPage, for example adding foo_field_body and foo_field_description. One of these "few things too many" aka MagicPages takes care of triggering the init() and ready() method of this pageclass, so that I can watch these files and trigger the migrate() method whenever the file is saved. I'd prefer if that was a core feature, but it is not.
On deployment RM will run all migrations and that might take a little. But I don't know how long exactly because Github does that for me with the help of RM's deployment tools. Usually a full deployment with copying files etc. takes about a minute.
Let's say that's a client project and the client contacts me 2 months later that something doesn't work. What I'd do is to execute "rockshell db:pull production" and some seconds later I'd have the current state of the project with all the new data on my local environment. While browsing the new content one of these "few things too many" aka filesOnDemand takes care of downloading all the images that the user has uploaded in the meantime that were not transferred by the db:pull. It does that in the background and only if I want it and have $config->filesOnDemand = ... in my config file.
Does RockMigrations have a fancy "revert" button? No. Is it possible to revert changes? Yes! If you need that, do it. Just write the according revert migrations and trigger them. I don't do that for every migration, because I don't want to do work that I never ever need. If I change my mind during development and want to go another route all I need is "rockshell db:pull" and all changes are "reverted". Sometimes (in maybe 0.5% of all migrations) it still happens that I want to revert changes that I've already pushed to production. What I do in that case is to add some "cleanup" (you could also call it "revert") migrations at the top of the actual migrate() method. Something like $rm->deleteField('fooclass_bodyfield', true).
You could even remove that line of code later, once that change has been applied to production. "Waaaah, you can't do that! What if others are working on the same codebase and never triggered that migration?" I hear you say... Well, I can. Everybody working on my codebase has to do two things before starting to work:
1) "git pull" to get the latest code state
2) "rockshell db:pull" to get the latest database stateSo there will not be any "fooclass_bodyfield" for him/her and therefore it's fine to not have the deleteField() call in their migrations.
Another benefit of splitting migrations into pieces is best shown by RockPageBuilder. There all blocks have their dedicated migrations. A slider block needing an images field for example would create it's own field once the migrate() method is called. That makes it possible to just drag&drop the folder of this block into another project and boom, everything is there. If I had a central place for migrations that would not be possible.
I know that this approach might look unconventional to some. So does ProcessWire itself with its "everything is a page" philosophy. But it works. Great.
On 11/27/2023 at 1:14 PM, d'Hinnisdaël said:I'd prefer a module that limits itself to migrations, if not just for performance.
I invite anybody that actually used my module and notices a performance penalty to report it and I'll do my best to improve the module. I'm relying on RM every day (and have been for some years now), so reports like this would be highly appreciated. Thx.
BTW: There's also $config->useMagicPages = false 😉
-
2
-
-
Ah sorry, you are right! 🙂 I'd have an idea but I'm on the go, so let's see if others know a good solution in the meantime.
-
1
-
-
You can set the language before the $pages->find() operation:
-
1
-
-
I'd also love to have a PW based forum software 🙂
Check out this thread:
-
Just now, Klenkes said:
If it happened once, it could happen again. Or maybe not.
Yeah, I agree and understand. But if it only happens once it's impossible to debug and fix 😞
-
Hey @Klenkes sorry for the trouble. Never seen this in my 3 years of using the module. I'd unhide the block via API in the tracy console and see if the error occurs a second time on another block at some time.
$pages->get(#your-block-id#)->removeStatus('hidden')->save();
-
1
-
-
1 minute ago, cwsoft said:
Another option may be RockMigrations from Bernhard https://processwire.com/modules/rock-migrations/.
Don't think that RockMigrations would help a lot here as the ->deletePage() method is not meant to be used for scalable scenarios. Though RockShell could help, because it's super simple to create new commands (see the docs here: https://www.baumrock.com/en/processwire/modules/rockshell/docs/custom/) and you can then execute this command via CLI whenever you need it, provide custom options if you want etc etc.
If it's a one-off task then bootstrapping PW and calling that file manually would be fine as well.
-
How to add dynamic "background-image" from images field?
in Dev Talk
Posted
I'm working on a website where I want to add an image as background:
The image comes from a PW images field. So I can't add the image via CSS... I'm doing it like this:
In CSS I have this:
So far, so good. But I don't need that image on mobile, as it will never be visible. I only need it for screen sizes > 1440px.
Any ideas how I could do that? I tried adding a <style> tag with @media(min-width: 1440px) { ... } </style> but that did not work. As soon as I placed it as "style" attribute of the html tag it worked.
Thx for your help 🙂