-
Posts
1,331 -
Joined
-
Last visited
-
Days Won
61
Everything posted by BitPoet
-
From PW's point of view, the error message is correct. It shows if you add the hook very early (like in site/init.php). PW, under the hood, calls find() with a numeric id, and that is when the error is triggered. With the numeric id, your selector becomes something like "32, loremipsum_field!=1". This has a comma and thus is a compount selector, so PW parses it into multiple expressions that need to match the form FIELD OPERATOR MATCH. The first expression, by these parsing rules, has an empty (missing) operator. Still, you should be able make the hook work for most cases with a little type checking and conditional logic. <?php wire()->addHookBefore('Pages::find', function(HookEvent $event) { // Get the object the event occurred on, if needed $pages = $event->object; // Get values of arguments sent to hook (and optionally modify them) $selector = $event->arguments(0); $options = $event->arguments(1); $customfilter = ", loremipsum_field!=1"; /* Your code here, perhaps modifying arguments */ if(is_numeric($selector)) { // The selector is a numeric page id $selector = "id=" . $selector . $customfilter; } else if(is_string($selector)) { // Regular selector, FIELD OP MATCH $selector .= $customfilter; } else if(is_array($selector)) { // Array of page ids $selector = "id=" . implode('|', $selector) . $customfilter; } else if($selector instanceof Selectors) { // Already parsed Selectors object $selector->add(new SelectorNotEqual("loremipsum_field", "1")); } else { // Unknown selector argument format! } // Populate back arguments (if you have modified them) $event->arguments(0, $selector); $event->arguments(1, $options); });
-
That's a bit dangerous, since not every template may have the field you're adding a search for. Also, the value passed in $selector may be a regular selector string, a page id, an array of page ids or even an instance of the Selectors class. For most of those, simple concatenation isn't an option, and I'm suspecting that the error is caused by that. Perhaps peeking at $selector with Tracy Debugger can give you a quick insight into what exactly $selector contains when the error occurs.
-
Abort module Uninstall on condition
BitPoet replied to cosmicsafari's topic in Module/Plugin Development
I think you just need to make sure you don't return from ___uninstall. Throwing an exception should be sufficient, though I haven't tested it. if(! $this->canWeUninstall()) { throw new WireException("Whoops! Module cant be uninstalled as it appears to be in use."); } -
If you only ever have one category per recipe, putting the recipes in their category is perfectly fine. One usually uses url segments if one item can belong to multiple categories, like a bread roll recipe belonging to bakery, bread and vegetarian at the same time, and/or if you have (or are expecting to add) other filtering criteria similar to categories (ingredients, preparation time, rating, year...) on the same list page so you might end up with a query link like /recipes/category/bakery/ingredient/flour. It all depends on how complex you plan your site to get. You don't have to touch the recipe template/pages themselves, you could simply assign the categories-list template to the recipes' parent and pull in the found recipes. But, as I wrote above, you can keep with your current approach and do things the straight forward way. It would probably be best to toy around with url segment based searches a bit before you implement them in a real life project. I've always got a few "playground" sites on my dev machine for testing things like that, sites which I just delete when they get too convoluted and replace with a fresh install of PW.
- 28 replies
-
- 2
-
-
- urlsegment
- filter
-
(and 1 more)
Tagged with:
-
Your setup is currently a mix of two approaches. The urlSegment approach clashes with your category site structure, since urlSegments only work for sub paths that don't exist in the site tree. To match up your design with Ryan's events example, the category page wouldn't have a template that is supposed to be rendered on the website. You would assign your categories-list template to /recipes, then url segments would be active for every request for /recipes/something for which there isn't a real "something" page under /recipes. Then you could call /recipes/category/bakery and have "category" in urlSegment1 and "bakery" in urlSegment2. The /category tree would just be there to hold data, not to be rendered.
- 28 replies
-
- 3
-
-
- urlsegment
- filter
-
(and 1 more)
Tagged with:
-
3.x: To many languages breaks MySQL index limit
BitPoet replied to phiro's topic in Multi-Language Support
To my knowledge, recompiling is the only way, since the index count limit depends on the storage engine itself, not the row format used (unlike index length / column count). Even then it's only possible to double the number of languages - though 64 languages is quite a lot. There might be a MySQL compatible database system without that limitation. I haven't found a list of limitations of Amazon Aurora yet, but it might be worth checking out where its limitations are. -
That's probably because MySQL strict mode is enabled. sortRebuild() uses a "shortcut" notation for multiple updates using an "INSERT ... ON DUPLICATE KEY UPDATE ..." statement that fails in strict mode. Both disabling strict mode globally or adding the following in site/config.php should help: $config->dbSqlModes = array( "5.5.0" => "remove:STRICT_TRANS_TABLES,ONLY_FULL_GROUP_BY" ) This is already the default for MySQL >= 5.7, but both features may be active in 5.5 and 5.6 installations as well. There's already an open issue for this here.
-
You could either remove the page-add permission from the role completely or remove the "add children" permission in the page's template for the exponent role.
-
Reading and writing times shouldn't be (noticeably) influenced by the pure size of a volume (unless the physical disk underneath is nearing the end of its capacity or the underlying FS becomes highly fragmented). Enumerating large number of entries (files/subdirectories) in a single directory would likely be a factor, so if you have more than 10k pages, breaking up the flat hierarchy of site directories could be worth thinking about - but even then, structuring them by year wouldn't be my first approach as it is counter-intuitive and has a number of pitfalls (e.g. timezone changes, duplicate files when overwriting, code that assumes all files for a page can be found in the same directory). Here's an example that adds a three-digit parent directory based on the page id that could be a starting point. It ignores the pageFilesSecure option, so be careful with it. You can look at PagefilesManager::___path and Pagefilesmanager::___url how they deal with that and other "magic". Of course, instead of that purely id-based dir, you can have the getPageSubdir function return anything you like. If you want to split your data between volumes, it could just return "old" for page ids < 5000 (or whatever the latest page id on the old volume is) and "new" for those above. /* * Change files path, insert a three-digit directory above, left-padded * with zeroes. This way, there won't be more than 999 directories under * site/assets. * * Subdirectory count won't be an issue unless you cross the million pages * mark. */ wire()->addHookAfter("PagefilesManager::path", null, "modifyPath"); function modifyPath(HookEvent $event) { $p = $event->return; $p = preg_replace_callback('~^(.*/)([^/]+)/~', function($match) { return $match[1] . getPageSubdir($match[2]) . "/" . $match[2] . "/"; }, $p); $event->return = $p; } wire()->addHookAfter("PagefilesManager::url", null, "modifyUrl"); function modifyUrl(HookEvent $event) { $url = wire('config')->urls->files . getPageSubdir($event->object->page->id) . "/" . $event->object->page->id . "/"; $event->return = $url; } function getPageSubdir($id) { return str_pad(substr($id, 0, 2), 3, '0', STR_PAD_LEFT); }
-
It was far easier than I had first expected, as I started without much external input and CI restraints, so I could stick with UIKit defaults and had no usability expectations to meet. So I stuck with the "keep it simple" philosophy. I'm tentatively planning to make a release bundle out of it (time is as always the factor), but need to strip out a few specifics first and replace them with more generic code. There are also a few things which I simply stuck into site config but would merit a dedicated config page (think addresses, currency, holidays, time constraints and all that).
-
Between a lot of big, not-web-related projects at work, I could squeeze in having a little a fun with ProcessWire too. What was needed was a shop-like solution where employees can order lunch snacks from our local butcher. Previously, this was handled with hand-written lists in each production hall that would be forwarded over fax to the butchers, leading to all kinds of transliteration and pricing errors. Our Central Services department looked at different software packages for that, but none of them did exactly what they needed. ProcessWire to the rescue. In little more than two days, I got a fitting solution up and running: PW 3.0.52 The only two non-standard modules used are @adrian's AdminActions and my own DatetimeAdvanced Role based template access UIKit 3 with modals, flex layout, mobile-ready with hamburger menu on smaller devices Everything is a page Synchronisation of employee accounts from time management software (> 600) into PW (120 lines, runs twice a day) Mixed authentication (Windows Active Directory if user is available there, local password if not) Account balance system with manual deposits and automated checking / detuction / refunding for orders, complete transaction history visible for the user Article categories (page reference), product images (not used yet), simple product variants (1 level, text + price) Ordering contents of a shopping cart for a single day or multiple days ahead of time within (admin configurable) time constraints (order window for following day ends X hours before, holidays excluded, etc.) Delivery locations (buildings) changeable by users themselves Integrated favorites system Management area in frontend for balance bookings, managing articles, previewing orders Daily collected orders for the butchery are printed into PDF through fpdf with a tiny wrapper Product images option with thumbnails (currently not used) Small additions like price validity dates or saving and re-using shopping carts will be added over the next months The shop landing page with all relevant information: Articles are grouped by category and have dropdowns for variations (with optional price addition/discount): Editable shopping cart with option to order same selection for multiple days: Minimallistic product item editor:
- 111 replies
-
- 18
-
-
Untested, but it might be possible to change the template object's noMove property before and after moving the page: <?php $nomove = $page->template->noMove; $page->template->noMove = false; $page->of(false); $page->parent = $pages->get('/my/new/parent/'); $page->save(); $page->of(true); $page->template->noMove = $nomove;
-
Developing, I must keep deleting the assets/cache/FileCompiler folder
BitPoet replied to Xonox's topic in General Support
Is opcode caching active on those sites (opcache, APC)? If yes, one of those could be responsible. If the site used opcache, make sure that opcache.validate_timestamps is true, for APC make sure that apc.stat is enabled. -
Loading of regular pages might benefit a tiny bit from using my module, but managing images would still be prone to the same delays if you put all images into a single library (which is just a page behind the scenes). You might still be able to make use of it if you can separate images into different libraries (e.g. by categorizing them into logos, photos, product images etc.) so numbers stay manageable. Media Library uses PW's native tools (file/image fields, CKEditor pwimage plugin), and I have to admit, I haven't tested those (and my module) with a big number of images - the module is a result of an internal requirement at work, where the number tends to stay well below 100. I'd say give it a quick try in a test system (perhaps in conjunction with the FileFieldTweaks option of @tpr's AdminOnSteroids). If you find you need something more elaborate though, @kongondo's Media Manager pro module might be worth a look.
-
AddHookAfter("save"...) on Page template ==("")
BitPoet replied to Mathroth's topic in Module/Plugin Development
You have to perform the check for the template name inside your hook function. $this->page or wire('page') returns whatever page in which the module code is executed (admin page editor, custom page with the code...). Pages::save on the other hand is called with the page object being saved, which is what you're looking for. public function init() { $this->pages->addHookAfter('Pages::save', $this, 'syncMobileDE'); } protected function syncMobileDE(HookEvent $event) { $page = $event->arguments(0); if($page->template->name == 'TemplateName') { // Run your code } } -
<?php $pagearr = $pages->newPageArray()->add($page->myfield);
-
You can hook before ProcessLogin::executeLogout and set the desired url. <?php wire()->addHookBefore("ProcessLogin::executeLogout", null, "setRedirect"); function setRedirect(HookEvent $event) { $event->object->setLogoutURL($pages->get('/')->httpUrl); }
-
Since I am the one guilty of adding UTF-8 support to WireMail, I could take an educated guess WireMailSmtp uses some external libraries that have evolved over the years and have their own routines to handle character encoding in address headers. I'll take a look at what is done differently there (I have an idea, but I'll have to run some tests to be sure) . In the meantime, if using wireMailSmtp is an option, I'd go with that.
-
Could you try and shorten the fromName and toName (or replace it with plain ascii ones) for testing and see if that fixes it? It might be a line wrapping issue in one of those two.
-
Is the first line complete? The missing from: header start and quoted-printable preamble is the only thing I see that's incorrect. If it's not, can you make sure that there are no line breaks in the fromName? setLocale shouldn't have any influence on WireMail's behavior.
-
So the fields are named Tab1...Tab9 resp. TabContent1...TabContent9? In that case, two possibilities immediately come to mind, but both require you to assemble the name outside of the quotes (there might be a way inside the strings, but I can't think of one right now). <?php //... $tabname = "Tab" . $i; echo "<label for='tab{$i}' class='labeltab'>{$page->$tabname}</label>\n"; Or, in one go: <?php //... echo "<label for='tab{$i}' class='labeltab'>" . $page->get("Tab" . $i) . "</label>\n";
-
$page->children() unpublished pages are still shown ...
BitPoet replied to jrtderonde's topic in API & Templates
Does that happen for all users or only when you're logged in as superuser? -
Since I'm doing a lot of detailed logging in our internal PW-based systems, that has become a bit of a bottleneck under heavy load and I was missing a centralized view with the growing number of separate PW instances. So I dug into the core a bit, namely WireLog.php and FileLog.php as well as ProcessWire.php. I managed to whip up my own WireLogDatabase and DbLog classes mimicking the behaviour of the regular logging classes, but not without a little bit of tweaking to the ProcessWire class itself to replace the regular logger. Now I'm logging to a MySQL server instead of plain files and ProcessLogger works smoothly with it without tweaking. I thought it would be shame to keep this all to myself, but a release-worthy version would need or could benefit from: a bit of polishing in regards to error handling and proper treatment of conflicting concurrent operations without too much lock overhead (drop table vs. insert especially) more source code documentation a little more abstraction so all csv operations are deprecated in favor of database columns where avaible last but not least, an approved way to configure the substitute logger and load it early on, which means touching the core ProcessWire class Before I invest too much into that, I'd love to hear all thoughts on this, especially if you think such a module may fit your requirements, and I would be especially happy to hear from @ryan - could you see such a mechanism in the core?
-
Have you tried linking s3fs to assets/files instead of the whole assets folder, just to see what difference that makes? Also, I could imagine that it's not only the cache folder that may slow things down at some point but also session and log, both of which could benefit from something with less round trips (and that handles concurrent writes better) than s3fs. Sessions could (and should) thus probably be switched to SessionHandlerDB. I think goofys is at a disadvantage since it doesn't have local caching. The scenarios where it overtakes s3fs (e.g. creating many files at once) fall short when s3fs can use its cache (that's why the benchmarks on the goofys page only compare uncached operations).
- 10 replies
-
- 1
-
-
- remote file system
- s3fs
-
(and 2 more)
Tagged with:
-
It should be possible to do this by specifying a base: <base href="<?= $config->urls->templates ?>myAppDirectory" /> in the header of the page. That means that relative link behavior changes as any url that doesn't start with a slash will be searched inside myAppDirectory.