Jump to content

ryan

Administrators
  • Posts

    16,484
  • Joined

  • Last visited

  • Days Won

    1,464

Everything posted by ryan

  1. @Divinorum I don't have the full picture of what you are querying, but my assumption is that you are finding pages that have a "price_list" (Page) field with selectable pages that each contain a "price"(integer) field. The returned pages are going to be those that have a "price_list" field, not pages that have a "price" field. I don't know what's producing the output in your screenshot, so you may have to post the code.
  2. @Divinorum Since you are trying to match a range of prices, it looks to me like you'd want an AND condition for that price_list.price rather than an OR condition? The AND condition in your selector would be: price_list.price>=15000, price_list.price<=20000 Assuming that price_list is a Page field that lets you select multiple pages, a selector like the above says this: at least one page in your price_list field must match price>=15000 and at least one page in your price_list field must match price<=20000. It doesn't say that they have to be the same page in that set matching both of those conditions. If you want to tell it that the same exact page in that set must match both of those conditions (which seems more useful here), then prefix an "@" to both of the conditions (see subfield selectors for more details): @price_list.price>=15000, @price_list.price<=20000 For a single-page selection field, this use of "@" would not apply, as there's only ever 0 or 1 pages in the set of selected pages. Note that there is no such thing as double pipes "||" for an OR condition in selectors (from your example), but there is such thing as using 1 pipe "|" to match one field or another, or one value or another. See the Selectors doc page for more details. Also check out selector OR-groups, which I don't think are useful here, but seems like you might have been thinking of something like it when using those double pipes.
  3. This week, work continued on our next main/master version with 8 issue fixes (see dev branch commit log). In addition, the WireHttp class was updated with new delete(), patch() and put() methods which correspond to http methods of the same name, These might be used by web services in addition to the more common GET and POST methods. In prior versions of WireHttp, you could still use delete, patch and put methods, but had to use WireHttp::send() with the $method argument set to one of them. Now that there are separate class methods for these http methods, it makes them a little simpler to use and more clear in code. It may be that you never need these methods, or it may also be that you use a web service that uses them extensively. The more web services I work with, the more I come across them, and figured it would be good for WireHttp to have more clear support for them. I know things slow down in the summer, but we haven't had many submissions to the sites directory lately. If you have launched any sites using ProcessWire in the last year or so, and haven't submitted them to our sites directory, please submit your websites to the directory when you can. We really enjoy seeing what what people are building in ProcessWire. Thanks and have a great weekend!
  4. @Jim Bailie In addition to the options you mentioned, if you put $myObject = new MyObject(); in your /site/templates/_init.php, then $myObject will also be available to all the page templates and the _main.php file, i.e. echo $myObject->value; As a benefit, it'll be automatically excluded from template files that don't use _init.php, such as the admin.php template file. If it's something that you might need on every page/template, but not necessarily, you may want to use it as a function in /site/ready.php that constructs it on first access, and then returns the same object on any later accesses to the function: function myObject() { static $myObject = null; if($myObject === null) $myObject = new MyObject(); return $myObject; } In this case, you'd use it like as a function with () appended rather than $ prepended, i.e. echo myObject()->value; This also has the benefit of using the same object (rather than creating another) if you happen to be calling $page->render(); on other pages in your template file(s). Another option: The way that ProcessWire does it is to use API variables, and you can add your own if you want. If you go that route, put in your /site/ready.php file: $wire->wire('myObject', new MyObject()); Then $myObject is available in any template files. The downside here is that it'll also be available to template files where you might not need it, such as the admin.php template file. So you may want to create it conditionally: if($page->template->name != 'admin') { $wire->wire('myObject', new MyObject()); }
  5. I was in New Orleans at the gymnastics Nationals most of this week. In her age group and level, my 10-year old daughter won 4th overall and 3rd on bars and beam. After a long drive, we're now back home in Atlanta and it's been a very short work week, but there's still a new dev branch version to write about. ProcessWire 3.0.221 continues primarily with minor issue fixes, working towards our next main/master version. Included are 11 resolved issues, 2 PRs, and code contributions from @matjazp and @dotnetic. In terms of new features, this version updates the language translating _n() function to support languages that consider 0 quantities as singular rather than plural in calls like _n('%d item', '%d items', $quantity); Previously this call has always used the plural "items" version for 0 quantities (i.e. "0 items"), which is correct in English, but may not be in other languages like French (as I've learned from issue #1757, though I think it has come up once before too). To define whether a language should consider 0 quantities plural or singular, use ProcessWire's language translation tool: Setup > Languages > [any language] > Find files to translate > wire/modules/LanguageSupport/LanguageTranslator.php ... when translating that file, you'll see the setting at the top labeled "Is zero (0) plural or singular?": That screenshot above also shows another new feature that was added, which is the ability to use Select and Radios fields when defining translatable text. Previously you could only use text, textarea and number fields. Let's say you wanted to have the person translating choose a color name for the language as part of the translation: $color = __('Red'); // What color? type=radios options=[Red, Green, Blue] As before, the "What color?" part is an optional description for the translatable text. Also as before, the "type=..." defines what Inputfield type to use. The supported values are any Inputfield name (minus the "Inputfield" part). Known to work values for this include: text, textarea, integer, float, radios and select. The "options=[...]" is the newly added part, and this enables you to define the selectable options for select or radios inputs. If you wanted to use separate value and label, you can also do that. In the example below, city abbreviations are used for the values and full city names as the labels: $city = __('ATL'); // What city? type=radios options=[ATL:Atlanta, CHI=Chicago, NYC:New York City] Another example is the one we used in the core for plural vs. singular here. By the way, if any of your values or labels need a literal comma, you can optionally use a pipe "|" as the separator rather than a comma. This ability to use Select and Radios is a fairly minor addition, but does open up better support for having certain language settings (rather than just translatable text) be part of language translation packs going forward. The plural vs singular setting for 0 seemed like a good first one to support with this. Next week we'll continue preparing our next main/master version. Thanks for reading and have a great weekend!
  6. ProcessWire might still work on older PHP versions, but it's not being actively tested on anything prior to PHP 7.x anymore. I'll update the version requirement to: "PHP 8.x recommended (PHP 7.x versions also supported)". I run on PHP 8.2 here, and I think that's the preferred version to run for the dev branch at least.
  7. Before the recent and major core updates to WireCache and Modules, we were on track to get a new main/master version out. I'd like to get back to that, as we are now 10 dev versions ahead of the main/master branch, and with some pretty good and major improvements. That's why I've been focused largely on minor issue fixes the last couple of weeks, getting into more of the fine tuning stuff, and likely will be the next couple of weeks as well. Thank you for opening issue reports as you come across stuff to report. Thanks also to @matjazp who's been helping out in the issues repo, maintaining existing reports and often helping to solve them too. I'm thinking we may have a new main/master version ready soon as July, next month. Most of next week I'll be in New Orleans attending the gymnastics nationals where my 10 year old daughter is competing. Since I'll be out of town, there likely won't be a lot of commits next week. Though there may be enough to bump to the next version, 3.0.221, I'm not sure yet. In any case, have a great weekend and week ahead!
  8. @heldercervantes Great description. This is amazing to me coming from traditional HTML/CSS/JS, to see something like this, and read how it was built. I wasn't familiar with the threejs library before, this looks really interesting. The planets are 3D objects? How did you make those, or where did they come from? It all looks very realistic, it really is something special. Very cool how ChatGPT helped out with the game part too. 🙂 Thanks.
  9. I've just bumped the dev branch version to 3.0.220. Relative to 3.0.219, this version is largely focused on issue resolutions, and there are 11 of them, among 14 commits. See the dev branch commit log for details. This is just a brief update so I don't have more to add other than that I hope you are having a great week, and have a great weekend!
  10. Wow, that's amazing, how did you make it?
  11. @Juergen I'm updating this in wire/core/Modules.php: public function ___saveModuleConfigData($className, array $configData) { return $this->configs->saveConfig($className, $configData); } to this: public function ___saveModuleConfigData($className, array $configData) { return $this->saveConfig($className, $configData); } I think that'll fix it, though let me know if you find it still doesn't work. Thanks.
  12. @olafgleba As I understand it, you've got pages that live at /members/blog/<name> and you want them to be accessible at /blog/<name>. First thing is to make it so that the blog post pages ->url property reflects the URL you want them to use. You can do this with a hook in /site/init.php: $wire->addHookAfter('Page::path', function($event) { $path = $event->return; if(strpos($path, '/members/blog/') !== 0) return; $event->return = str_replace('/members/', '/', $path); }); Next, you want to make it so that ProcessWire will deliver those blog post pages at the /blog/<name> URL. You can do this either by enabling and handling URL segments on a /blog/ page, or you can use a URL/path hook, again in /site/init.php. I'm going to assume there is no /blog/ page, so a URL/path hook may be the best bet: $wire->addHook('/blog/{name}', function($event) { $name = $event->arguments('name'); $blog = wire()->pages->get("/members/blog/$name"); return $blog->id && $blog->viewable() ? $blog : false; }); Are those /members/blog/ pages are access protected from public users? If so, the above hook is not going to let them through because of the $blog->viewable() condition at the end. You could remove that, or better yet, replace it with a different condition: if($blog->isUnpublished()) return false; return $blog->id && $blog->template->name === 'blog-post' ? $blog : false; I can't remember at the moment if ProcessWire does another access control check on the returned page ($blog). So if you find it doesn't work returning the $blog page, try having it return $blog->render() instead.
  13. @orchardheightsdental Netcarver is right that you need to get a look at the /site/assets/logs/errors.txt log and see what the last entries are in it. If you don't have SSH access you can also grab it through FTP. My best guess is that your web host upgraded to PHP 8.1 or 8.2 and that you are running a much older version of ProcessWire. PHP 8.1/8.2 upgrades can sometimes break old versions and old sites. I can tell that you are running a pretty old version because it is missing the JS files for AdminThemeUikit, which was added more than 6 years ago. The good news is that the front-end of your site seems to be working. A major PHP upgrade on an old site would be more likely to break both the front and back end. Most likely an upgrade to a more recent PW version (like 3.0.210) would resolve the issue. Though it's also possible that the issue is coming from a 3rd party module that's installed, or something else, and that's what the errors.txt log would tell us.
  14. @bvfbarten @zoeck I'm not sure why this error didn't appear in earlier versions, but the issue was that the InputfieldSelector module (when installed) was attempting to access the $session API variable before the API "ready" state. I noticed the same issue here and it should already be fixed in 3.0.219, though please let me know if you still run into an error.
  15. @zoeck Just ".Modules" and not ".Modules.info" ? in 3.0.218+ there should be rows with these names: .Modules.info .ModulesVerbose.info .ModulesUninstalled.info .ModulesVersions.info .Modules.site/modules/ .Modules.wire/modules/
  16. @wbmnfktr ProcessWire 3.0.218 moved its cache storage from $cache to the modules table, so those module names you see there are actually the cache names from 3.0.218+. This error would be expected if downgrading from 3.0.218 or 3.0.219 to 3.0.217 or prior, since prior versions don't know about those caches in the modules table. It's not a fatal error and it's okay to delete them from the modules table if you downgrade to a previous version. (or it's okay to ignore them). But this error wouldn't be expected if upgrading to 3.0.219. Your message suggests this is what you saw after UPgrading, but this is what I'd expect to see if DOWNgrading, so just wanted to confirm?
  17. If you upgrade to 3.0.219, grab the latest commits, as the commit labeled "Bump version to 3.0.219" still had a couple of issues that I ran across since then and have fixed. (The issue may have originated in 3.0.218 or 3.0.217 actually). It was primarily "class not found" errors, and I didn't notice at first because the errors didn't appear when doing minor version upgrades and instead would appear when upgrading older versions to 3.0.219.
  18. @thetuningspoon @cb2004 Try the most recent dev branch commits. The "class not found" error at least was coming from upgrading an older version of PW that had certain modules in different parent directories. For instance, /wire/Fieldtype/FieldtypeFile.module was moved to /wire/Fieldtype/FieldtypeFile/FieldtypeFile.module many versions back. But if upgrading from that older version (that had the file in a different location) to 3.0.218 then you'd see this error. At least, that's the issue I ran into (and fixed) here.
  19. ProcessWire 3.0.219 on the dev branch focuses primarily on a major overhaul to the core $modules system. The Modules class had grown into more than 5000 lines of code — all related to modules, but with lots of different areas of focus within that. It had become a little bit messy, fragile and hard to maintain at that size. I've had @todo notes in the class to "clean it up" for quite awhile, but this week I finally got to it. The approach is similar to that of our $pages API (Pages class), which is split into separate classes for page finding, loading, editing, caching, etc. The Modules class has been split into several much more focused classes for module information, installers, loaders, files, flags, duplicates, and configurations. This leaves the main Modules class as the gatekeeper, making it less fragile and easier to maintain. If this overhaul was perfect, you shouldn't notice any difference, and the public $modules API remains as before. But with such significant overhaul that took a full week to complete, there's also an increased potential for temporary errors, so please let me know if you encounter any. Thanks for reading and have a great weekend!
  20. @MarkE What I'm intending to communicate is that it's up to the module developer how many of the WireCache features they want to support. That's because, as I understand it, it's not possible to support the the full WireCache feature set with something like Redis. The core WireCache (WireCacheDatabase) will continue to support the full feature set, as it always has. For 3rd party WireCache modules, the required feature set would just be the ability to get, save and delete cache by name ... what the majority of cache use cases are. If they can support more than that, great. But I think it's better to keep the door option to more cache options by not requiring specific and lesser-used cache features unique to PW. If a 3rd party module has to support the full WireCache feature set then likely there won't be 3rd party WireCache modules. For cases like yours, where you are depending on specific features, you'd probably want to stick with using the core default (WireCacheDatabase), unless future 3rd WireCache module is able to support them. @BitPoet Great! Yes, that's correct, the core does not use anything but get/save/delete by name. But it does use wildcard matching (for FileCompiler). Does Redis allow for matching by partial cache name? For instance, a cache name that has a wildcard at the end like "MyCache*"? If not, there are ways around it, but I was just curious. Maybe that is a good way around it. Though having to hit the database in addition to Redis might reduce the benefit, or make it slower than just using the database cache. Maybe another way around it is for WireCache to fallback to the WireCacheDatabase when a particular feature is needed that's not supported by the WireCache module. Good idea, I will add that. @kongondo I don't think so because the cache would have to write and read from the same place, otherwise I don't know how it would find caches that it wrote. But PW does support separate read and write connections for the database (WireCacheDatabase), and it will use them when they are provided.
  21. @adrian I don't think there's any need to change it, as cache handlers that don't support past dates can substitute a future date, i.e. if($expires === WireCache::expireNever) { $expires = wireDate(WireCache::dateFormat, '+1 YEAR'); }
  22. @BitPoet This is for the maintenance processes. WireCache performs maintenance every 10 mins and whenever any page or template is saved. The page/template save maintenance only happens if rows have expiry dates prior to WireCache::expireNever. Finding by expiry dates can be optional if the cache (Redis) handles expiration on its own. I'm also not sure how much need for these two constants anymore since the modules are now decoupled from the cache. Though I think TracyDebugger uses expireNever. You can just replace WireCache::expireNever with some date far in the future (a year?). The WireCache::expireReserved can be treated the same as expireNever. It was primarily for the modules-system and I will likely deprecate this option since it's no longer needed. Its only purpose is to behave like expireNever but also prevent the rows from being deleted when a "delete all" action is being performed. We don't need that anymore. There are a few expirations prior to expireNever that could also considered. Either that, or the WireCacheInterface module could just indicate it doesn't support them. Since these are all dates before WireCache::expireNever, they can be easily filtered in the same way. If the cache can't search by expiry, then implementing them would mean mapping to some other property that is searchable by the cache handler. Any WireCacheInterface module doesn't need to know about any of these since all the logic for finding them is mapped to expiration dates: WireCache::expireSave - This expiration means that the cache row should be deleted whenever any Page or Template is saved. WireCache::expireSelector - This is like expireSave above except that it indicates the cache value is JSON-encoded along with a property named 'selector' and this contains a page-finding selector. WireCache loads them all and when the saved page matches any selector then the cache row is deleted. WireCache maps template IDs to dates by doing $expire=date('Y-m-d H:i:s', $template->id); and that can be reversed with $templateID=strtotime($expire); When a page having that template ID is saved, the cache row having that templateID-based expire date is deleted. Like with the above, the WireCacheInterface module doesn't need to know anything about this other than finding rows having those expiration dates, and presumably those could just be mapped to something else. I'm not sure it's necessary to support these other than mapping expireNever to a future date, as I think very few actually use these features. From what you've described, Redis handles a lot of the stuff that WireCache does on its own. If the cache handler (Redis) can handle these tasks on its own, that's great. If I'm understanding what you've described correctly, here's how I would handle it: When find($options) receives a request containing $options['names'] to find, then ignore anything in the $options['expires'], since Redis is never going to return an expired row. When find($options) receives a request with empty $options['names'], and a populated $options['expires'], just return a blank array (no results). When save() receives an $expire date of expireNever or expireReserved, substitute some far future date instead. When save() receives an $expire date prior to expireReserved, throw an Exception to say the feature isn't supported, or substitute 1 hour, 1 day, or whatever you think is appropriate. Once it works with those, if you wanted to support the full feature set, then you could always go back and see about mapping expiration dates less than or equal to WireCache::expireNever to some other searchable property (and using a far future expiration date). But very few people actually use the page/template/selector clearing features (as far as I know), and the core doesn't need them, so they could be considered optional.
  23. Continuing from last week's post and discussion, ProcessWire 3.0.218 decouples the modules system from the cache system. Now the modules system maintains its own internal caches (at least once you do a Modules > Refresh). It'll still use the $cache API as a backup (temporarily), but now you can safely export the database without the "caches" table, or even delete the "caches" table, if you want to. It'll get re-created as needed. In this version, work also continued on the new WireCacheInterface (and major updates in WireCache) so that we could support external modules to handle cache storage. This capability is kind of similar to how we support 3rd party WireMail and WireSessionHandler modules. The first example is WireCacheDatabase, which is the default cache storage handler for the core. And today we have a new module called WireCacheFilesystem that replaces the default WireCache database storage with a file-system based storage, once installed. It's not yet clear if there are major benefits one way or the other (cache in database vs. file system), as I've not been able to put all this new code through performance testing yet. I'd definitely be interested to hear if anyone has a chance to test things out. I expect the file system might be faster for reading caches, while the database may be faster for writing caches. At least that's what I found with a few preliminary experiments, but they haven't been very thorough, so take that with a grain of salt. I thought we needed at least 2 examples of classes implementing WireCacheInterface before we'd be ready to support potential 3rd party WireCache modules. I imagine that 3rd party modules getting into dedicated cache options independent of database or file system is where we'll start to see major performance benefits. At least for sites that use the cache heavily. That's all for this week, have a great weekend!
  24. @bernhard Usually ProfilerPro would be great for this, but in some cases I can't use it because ProfilerPro is a module and I'm timing something that happens prior to modules loading. When PW is in debug mode, it times all of the boot processes, so I can just look at those. I also add other Debug::timer() calls as needed to time specific things. When testing in the admin, you can finish a timer with Debug::saveTimer($timer); and it'll show the result in the Debug > Timers section of the admin. But you can't look at any one instance of a timer. You've got to take several samples before you really know if there's a trend in the numbers. I'm usually looking for consistently 10 ms or more when it comes to improvements. @Ivan Gretsky The cache supports an expiration flag represented by the WireCache::expireReserved constant. It means that rows with that flag are reserved and should never be deleted. If you use the $cache API to clear the cache, it'll do it in a safe way. But if you just omit the caches table from a DB dump or manually delete all the rows in the caches table, then it would be problematic. I agree it would be better not to have to consider this. I'm not sure we need to keep that flag other than for modules, so this is one reason why I'm looking to have the modules use some other storage method for its cache. Though if new caching options came along (Redis, etc.) it would sure be nice for modules to be able to utilize that caching method too, so there are tradeoffs. Ideally, the modules would still use WireCache, but be able to recover easily if its caches get deleted, so that's probably what I'm going to work towards, but it's not as easy as it sounds. @teppo Sounds great! I have no experience with Redis but this server seems to have it and I've also been curious about it. I really like the idea of dedicated cache systems independent of the DB or file system. I'd definitely like for PW to be able to support them, and am glad to hear you are interested in it too.
  25. This week I've done some work on the core $cache API (WireCache) to make it able to support other cache storage options. To do that, I had to move all the storage code out of the WireCache class and into a separate class that implements the new WireCacheInterface. So it was kind of a major refactor. Now the WireCache class is independent of storage method, which will make it more flexible in the long term. The first class that implements the new interface is the new WireCacheDatabase. This contains the cache database-storage code that was previously in the WireCache class. But the plan is to also add a WireCacheFilesystem (in progress), and make it possible for others to develop WireCache modules, perhaps for Redis, Memcache, etc. I've been wanting to do this because in some cases I've noticed significantly better read performance from file-based caches. (Though admittedly, at the expense of write performance.) But it made me think it would just be better to have more cache storage options, and also be nice to take advantage of even better cache options available in different environments, like in the AWS environment we run this site on. One of the issues with changing the cache used by the system is that the $modules API (Modules class) depends on WireCache for quite a few things. And the modules basically can't load without the relevant caches being available. At present, $cache has to load before $modules, which makes the whole idea of WireCache-modules a bit of a chicken-or-egg first situation. So I've been working to decouple $modules from WireCache, or at least make it able to function if its cache isn't available on occasion. I made some good progress there, but found that there was a little bit of a performance hit in doing so, so I reverted those changes and put them behind a toggle in the Modules class to experiment with further. But while doing that, I found some other ways to improve the performance of the modules loader. So you'll find the dev branch boots a little faster this week. Maybe not noticeably so (since PW already boots fast), but measurably so. I'm always looking for opportunities to improve performance — even small performance improvements amount to large savings over time. While on the topic of caches, I've also added an experimental $pages->loader()->findCache($selector) method which works exactly like $pages->find($selector) method, except that it caches the page IDs that were found for a period of time that you specify in the 2nd argument (default is 60 seconds). I imagine this method would be useful for complicated or slow page finding operations that don't need to restart from scratch on every request. This is an alternative to markup caching for greater control. But since it caches the result of the find operation (page IDs), and not the actual pages, it has a different set of benefits (and drawbacks) relative to markup caches. I'm still experimenting with this method to get more feedback and make sure it's worthwhile, so far it appears to be. This will likely become accessible at $pages->findCache() once out of the experimental stage. That's all for this week. Thanks for reading and have a great weekend!
×
×
  • Create New...