Leaderboard
Popular Content
Showing content with the highest reputation on 01/06/2025 in all areas
-
The plan was to merge dev to the main branch today, but I’m still working through a couple of GitHub issues that I’d like to resolve or finish the conversation before finalizing the 3.0.244 main version. One example is this issue report where it was pointed out that there are some issues with UTF-8 page names. ProcessWire uses PHP’s IDN functions to manage conversion to and from the non UTF-8 version of the URL. PHP 7.4 changed the default arguments of the idn_* functions to settings that made them not work 100% for page names in a few cases, which I didn’t realize before this week. But this is not an issue that I can just fix and be done with it… There may already be page names in any given installation that are affected by the post PHP 7.4 behavior. If I were to just fix the issue, then some affected pages might no longer match when accessed directly by URL. So this had to be a carefully considered fix. What I ended up doing is fix it for any new PW installations that occur after this weekend. PW keeps track of its installation date, so can do this by way of its $config->installedAfter(“2025-01-05”) function. Existing installations will keep the imperfect behavior. Presumably it doesn’t affect that many installations since it only came to light last week and PHP 7.4 was released roughly 5 years ago. Nevertheless, existing installations that want the “fixed” behavior can get it by specifying this in /site/config.php: $config->pageNameWhitelist = 'v3' . $config->pageNameWhitelist; That essentially says to use version 3 of the page name conversion. Version 2 will also work fine, but may be slightly slower since it uses a dedicated Punycode library. And version 1 is the one that worked correctly until PHP 7.4, and still works mosts most of the time, but can produce imperfect results in some cases. Installations prior to 5 Jan 2025 use v1 by default and installations after 5 Jan 2025 use v3 by default. Chances are few (if any) will want to specify the version manually like above, but the option is there, just in case. That’s one example of why I’m waiting another few days before the dev branch merge to main. Another is that Adrian mentioned double-clicking on the “Move to Trash” button [in the page editor] makes it permanently delete the page rather than trash it. While I can’t duplicate that, despite multiple attempts, I just want to make sure there’s not something that needs fixing there. But unless any major new issues turn up, by this time next week we’ll merge to main and bump the version to 3.0.244. Thanks and Happy New Year!2 points
-
Hello PW fans, I open this topic to pick up where Ryan left off in his introductory article. Note that beside the technique detailed in Ryan's article, there is another supported technique to use custom page classes (which is also mentioned in his article briefly), and you can learn even more about that one by – for example – reading this closed issue. I'm in the process of completely re-thinking the way I implement sites so I am interested in how others integrate custom page classes in their codebase. Let's use this forum thread as a general discussion board of this topic.1 point
-
Happy new year everyone! I've been working on adding multiple tab support for the console panel. It works in conjunction with the snippets panel so you can load up multiple snippets, or create any number of temporary (unsaved) tabs of code. Each tab has its own execution history stack and the last result for each tab is also maintained so you can flip between tabs to see the differences between results. It automatically names tabs like a typical code editor does: Untitled-1 initially, and then using the first line of code. Of course when you save the tab to a snippet, the tab name will be that of the snippet filename saved to disk. I'll push it live soon, but if anyone sees this and would like to test and provide feedback beforehand, please take a look at this branch: https://github.com/adrianbj/TracyDebugger/tree/console-tabs Thanks!1 point
-
I haven't yet. The app that I wrote for a client wasn't resource-heavy enough to offload the DB to a separate server, and it was a single app/single database setup so there weren't going to be any shared resources. If you or anyone gets around to using one I'd be interested in hearing about the results though.1 point
-
ProcessWire should soon be listed under the DDEV Quickstart List: List: https://ddev.readthedocs.io/en/stable/users/quickstart/ PR: https://github.com/ddev/ddev/pull/68791 point
-
Hi, This is a basic module to add some classes and css to teh logs list page based on the amount of time since the log has been edited. less than a minute: Red -> purple -> grey less than a week https://github.com/benbyford/HighlightRecentLogs I hooked to the ProcessLogger module ___execute() function and basically overwrote it. Felt abit nasty to me, I wondered if there would have been a better way of doing it?1 point
-
@benbyfAppreciate this, thank you! When I have to look at the logs page, my brain is usually in a panic, so this helps surface the thing I want without further thinking about "and now click to sort", or worse, trying to mentally scan and parse the textual description column like x hours/minutes ago!1 point
-
@FireWire @Jonathan Lahijani @gebeer I've created a demo module that shows how to use the new config migrations. Please note that it needs the latest RockMigrations version from the dev branch! https://github.com/baumrock/ConfigMigrationsDemo1 point
-
Ever wondered when certain hooks get executed? Which hooks got fired along the request? Or need to debug why your hook does not fire as expected? Open /wire/core/WireHooks.php, find the method "runHooks" and paste this at the very top of this method: $logfile = wire()->config->paths->root . 'hooks.txt'; $tooOld = is_file($logfile) && filemtime($logfile) < time() - 5; if ($tooOld) unlink($logfile); $logData = get_class($object) . "::$method\n"; file_put_contents($logfile, $logData, FILE_APPEND); This will write a log of all hookable methods to hooks.txt and it will probably begin like this: ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\FileCompiler::compile ProcessWire\Fields::load ProcessWire\Fieldgroups::load ProcessWire\Templates::load ProcessWire\Fieldgroup::setQuietly ProcessWire\Fieldgroup::callUnknown (maaaany more lines) And it will most likely end with "ProcessWire\ProcessWire::finished" 🙂 Now you can play around with this logfile and view different pages. For example when opening a page for editing you will have a portion of this in the log (ProcessPageEdit::buildForm...): ProcessWire\ProcessPageEdit::breadcrumb ProcessWire\JqueryCore::use ProcessWire\JqueryUI::use ProcessWire\ProcessPageEdit::execute ProcessWire\HutPage::setEditor ProcessWire\ProcessPageEdit::buildForm ProcessWire\ProcessPageEdit::buildFormContent ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::changed ProcessWire\Field::changed ProcessWire\Field::getInputfield ProcessWire\Field::changed ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\Field::getInputfield ProcessWire\HutPage::viewable ProcessWire\Pages::find ProcessWire\PageFinder::find ProcessWire\PageFinder::getQuery ProcessWire\HutPage::addable ProcessWire\ProcessPageEdit::buildFormChildren ProcessWire\WireInputData::int ProcessWire\WireInputData::callUnknown ProcessWire\WireInputData::int ProcessWire\WireInputData::callUnknown You can also use grep to find the hooks you are looking for, for example: cat hooks.txt | grep ProcessWire:: ProcessWire\ProcessWire::init ProcessWire\ProcessWire::ready ProcessWire\ProcessWire::finished ProcessWire\ProcessWire::finished This has helped me today to find the correct spot to hook into. Maybe it also helps anyone else. Have fun! PS: Don't forget to remove this once you are done with inspecting, of course!1 point
-
And here comes the first talking point I'd like to open... Ryan in his introductory article did not mention whether there is a significant difference between "DefaultPage as a direct subclass" of Page class and "other subclasses of DefaultPage". He also did not mention anything about the recommended way of implementing our own custom "initialization" method for the object, in case we need to perform such a thing. EDIT on 2021-03-28 starts ------------------------------ Taking a look at wire/core/Templates.php it is the getPageClass() method which determines the class of a page. Here, $corePageClass = __NAMESPACE__ . "\\Page"; is used to set ProcessWire\\Page as expected, except when there is a custom page class being used. Then, PW checks if a page class has been set "in the admin" and – if it is valid to use it – then uses that one instead. If no valid custom page class has been found so far, then PW looks for a valid custom page class supported by the new technique of PW 3.0.152+ (that is: extending it in our own client code) and this is where the class name ProcessWire\\DefaultPage is hardcoded into PW like this: $defaultPageClass = __NAMESPACE__ . "\\DefaultPage";. If this class is used/exits as a custom page class, then it is set to take over the pace of the core Page class, like this: $this->pageClassNames[0] = $defaultPageClass; and afterwards: $pageClass = $this->pageClassNames[0]; So my understanding is that by using the name DefaultPage to extend Page, one can "ask" ProcessWire to use it as the bases of almost all page objects, except for users, roles and permissions which are treated differently. Taking advantage of the possibility of using DefaultPage is optional of course, one can just simply extend Page by using any other arbitrary names, but the string literal DefaultPage named subclass is treated as the new core class in case one needs to add some custom behavior to all "non-user related" pages. Correct me if I am wrong but this is what I gathered sot far.... EDIT on 2021-03-28 ends ------------------------------ What I mean is the following: //this direct subclass of Page is treated differently class DefaultPage extends Page {} //subclass of DefaultPage class ArticlesPage extends DefaultPage {} Ryan in his article suggests that using DefaultPage as a subclasses can be used. However, I found a shortcoming when relying solely on DefaultPage. Let's consider this: //direct subclass class DefaultPage extends Page { public function ___loaded() { /* *___loaded() is called when the page is "prepared" by PW, having all its properties loaded from the database. * Because of this, it can perhaps be used as an init() method, so that * we might further initialize the object before actually using it in our own "client code". */ } } The issue with using loaded() to do our own additional initializations is that in the case of DefaultPage this method gets called for ALL the pages that are instantiated during a normal HTTP request. What I mean is that any code placed into loaded() will be executed for all sorts of pages, not just for our humble DefaultPage object we wanted to instantiate in the first place. Even worse – for some reason unknown to me –, the same DefaultPage object's loaded() method will be executed twice during a single HTTP request of the frontend. All this behavior renders loaded() unable to fulfill the role of an init() method I am looking for. However, I found that the subclasses of DefaultPage work differently, let's say "normally". While DefaultPage takes the place of Page as far as ProcessWire is concerned, any subclass of it does not. This is a very important difference, because the following one behaves differently: //subclass of DefaultPage class ArticlesPage extends DefaultPage { public function ___loaded() { /* * Code placed here always runs just once during a normal HTTP request. */ } } In this case loaded() only gets called by ProcessWire when our own client code triggers the instantiation of the custom page object in any way (for example when the related page is rendered by requesting it in the browser). And in this case no other custom page objects's loaded() method gets called. Moreover, trying to use Tracy (eg. a bd() call) in the loaded() method of DefaultPage is not possible, however, Tracy is readily useable in the loaded() method of a subclass of DefaultPage. To summarize: I found that in the case of a DefaultPage I cannot use loaded() as an "init() method". However, in the case of any further subclasses of DefaultPage, it looks like it is fine to rely on loaded() because it is called only once (after the object has been prepared for us by PW). I'm interested in hearing how others implement a custom initialization method for their custom page objects. Maybe there are better ways to do it than relying on loaded()? Is using loaded() for such a thing is a good idea in the first place? //de1 point