Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


teppo last won the day on September 15

teppo had the most liked content!


About teppo

  • Birthday 08/21/1984

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location

Recent Profile Visitors

69,480 profile views

teppo's Achievements

Hero Member

Hero Member (6/6)




Community Answers

  1. As it happens, I'm about to hop in a project where invoicing is a key part; while I don't know if I'll be able to use your site profile directly, at the very least it'll be interesting to dig in for ideas. What we see here already looks awesome 🙂 Would be nice if this was implemented in a way where one can easily swap the payment processor, kind of like what Antti did with PaymentModule (and PaymentStripe, PaymentPaypal, etc.)
  2. Definitely sounds like a job for ProDrafts. Version Control keeps track of changes after they've occurred, but there's no (automatic) way to put them on hold and apply after some action/trigger. In theory one could restore the page to previous revision automatically and step "forward" again once changes are approved, but that would get very complicated very fast, and going back and forth could also result in "conflicts" where updates applied meanwhile would simply get discarded. Anyway, that's not something I would recommend doing 🙂
  3. README lists three supported multilingual fieldtypes: Text (regular and multi-language) Textarea (regular and multi-language) Page Title (regular and multi-language) Technically other multilanguage fieldtypes should be supported as well, but these are the ones I've tested. Version Control has a config setting for enabling fieldtypes that are available on the site, but not listed as compatible by default.
  4. Out of curiosity, which version of PW are you using? PW auto-corrects the rotation, and some issues related to this were fixed in version 3.0.197. Just wondering if updating to the latest stable version (3.0.200), for an example, would resolve this problem. My understanding is that PW doesn't remove EXIF data from uploaded image, just resized images — though I could be wrong here! One exception at least is that if you have configured a max image size for your image field, then it will be automatically resized after being uploaded, which means that PW no longer has any version of it with EXIF data in place. Anyway, I'm not sure which one you're talking about here: original uploaded image, or a PW generated size variation of it? If it's the latter, then currently there's no way to retain EXIF data, but the image should still be automatically rotated according to what was in said EXIF data. (There is an open issue about keeping EXIF data, at least in some cases, but no clear solution yet: https://github.com/processwire/processwire-issues/issues/1055.)
  5. Just wanted to point out that when it comes to building menus, it can get a bit... complicated. This is why modules such as MarkupMenu exist. I'm not saying that you can't build your own menu logic without a module using custom code, just that it's — in my opinion — one of those things that you don't necessarily need to 🙂 Depends a lot on your use case, of course; some sites have a super simple menu logic. And sorry for going off-topic, as well as shameless self-promotion via MarkupMenu 🙂
  6. Pages::___save() method has a forceID parameter: * - `forceID` (integer): Use this ID instead of an auto-assigned one (new page) or current ID (existing page). I've never tried to do anything like this, but it seems like this would be a good place to start, e.g. hooking before this method and forcing the ID in case of a new page using the user template. You would still have to figure out some way to share auto-increment ID values between instances 🙂
  7. A few new additions to this old module, available as of version 1.8.0 (session.txt import) and 1.9.0 (new API methods): There's an option in ProcessLoginHistoryHooks module config to import login history from session.txt. This can be useful when adding this module to a site with existing history, since ProcessWire (by default) collects data about successful/unsuccessful login attempts to said log file. This option is intentionally hidden under collapsed "advanced" fieldset. It's not super well tested yet, could result in a very slow request in case there's a lot of data to import, and in case disk timezone is different than the one in database duplicate records may be created on first run. $this->modules->get('ProcessLoginHistoryHooks')->getUserLoginHistory($user, $start, $limit, $login_was_successful) returns login history data for provided ProcessWire User object. Default values are 0 for "start", 2 for "limit", and 1 for "login_was_successful", which means that by default this method will return latest successful login and the one before that. Return value is always an array; in case there are no results, an empty array is returned. $user->getLoginHistory($start, $limit, $login_was_successful) does the same as previous command for a specific User object. All arguments are optional. This method returns a single timestamp (when limit is 1, or an integer value is provided for the "start" argument and "limit" argument is omitted), an array of login history, or null in case there are no results. By default timestamps for last two successful logins are returned.
  8. If you're not a ProDevTools user yet it might be a bit overkill, but just wanted to mention that ProfilerPro is brilliant for this type of use case 🙂
  9. Just my two cents: used to avoid Repeaters as well, because in the beginning they were quite unstable, but from my point of view they have matured nicely. For years I/we have used them a lot — in fact nearly all sites we've built last couple of years have used a Repeater Matrix based page builder. Can't remember the last time I had an issue directly related to repeaters 🤷‍♂️ That being said, I do try to keep things simple, just in case. Field dependencies is an example of a feature I've not tried with repeaters 🙂
  10. Page Table was developed/intended as a part of the ProFields bundle, but later bundled with the core package, so "ProFields" in the name is kind of a nod towards that history 🙂 There are many ways to handle rendering, but here's one solution that may help you: Create a shared root for your content elements — something like /blocks/ or /content-elements/, perhaps. Configure your Page Table field to save new items below aforementioned root path, and make sure that you only enable templates that you've created for this purpose. You don't want to allow a "regular basic-page" (or anything like that) in your Page Table field as a "content element". For each of your "content element templates", leave template file empty (so that these pages can't be reached with their actual URL). Now even though your content elements will be actual pages in the page tree, they won't be reachable by visitors. You can render them in any way you see fit, but here's one approach using ProcessWire's native field rendering feature that, in my opinion, works pretty well. Here I've assumed that the Page Table field is called "blocks", and it's used on template called "basic-page". /site/templates/basic-page.php <?php namespace ProcessWire; ?> <?= $page->render('blocks') ?> /site/templates/fields/blocks.php <?php namespace ProcessWire; ?> <?php foreach ($value as $item): ?> <div class="block"> <?= $item->render(__DIR__ . '/blocks/' . $item->template . '.php') ?> </div> <?php endforeach; ?> /site/templates/fields/blocks/block_template_name.php <?php namespace ProcessWire; ?> <h2> <?= $page->title ?> </h2> <?= $page->content ?> Anyway, as I mentioned that's just one approach 🙂 I'm not entirely sure what you're referring to here, but if you mean the processwire.com website, then yes — that's technically proprietary. In my experience that's a common thing for open source projects. API reference, on the other hand, is automatically generated from ProcessWire's source code, so that is technically open source 🙂
  11. Thanks @flydev 👊🏻 for identifying the error, and sorry @Roych for the inconvenience. This is now fixed in version 1.7.2 of Login History, display date format should no longer intervene with date difference calculations 🙂
  12. Out of the box (without third party modules) your best option is the Page Table ("ProFields: Page Table") fieldtype. It's included with the core package, but might be uninstalled by default. The user interface for Page Table is a bit different in that you'll edit content in modal windows instead of "in context", but I'd suggest that you give it a try. You can save your content items under current page, or a different location in your page tree. If third party modules are an option, the Repeater Matrix module is worth checking out. It's commercial (paid) module, but if that's not an issue, it's really quite amazing. Other (non-commercial) module options include PageTableNext and PageTableExtended.
  13. wire('pages')->get('template=template_custom_orders')->delete() uses $pages->get(), which means that it will include pages that are either in trash, or unpublished/hidden. Meanwhile this part... $tcos = pages('template=template_custom_order'); foreach ($tcos as $tco) : $tco->delete(); endforeach; ... will only find non-trashed public pages. One thing to check is that it matches every possible page: $tcos = pages('template=template_custom_order, include=all'); foreach ($tcos as $tco) : $tco->delete(); endforeach; BUT that being said, there's potentially an even easier method: wire('pages')->get('template=template_custom_orders')->delete(true); If you pass "true" to the delete method, it will automatically (attempt to) remove child pages.
  14. Hey @Zeka! I assume you're referring to "method aliases" from MethodPropsTrait? If so, this is a feature that, to be honest, I've not had much use for myself. As far as I can remember, the original intention was two-fold: 1) Whether to make code cleaner or to mitigate issues resulting from partial rewrites, one can create an alias or "virtual method" that calls another local method behind the scenes. Say, if a controller class had method called "words", but later it was decided that it should be "terms" instead (or for some reason front-end code requires it to be that) yet changing it now could potentially cause other issues, one could handle this via an alias: class DictonaryController extends \Wireframe\Controller { protected $method_aliases = [ 'terms' => [ 'callable' => ['self', 'words'], 'params' => [], ], ]; public function words(): array { return $this->pages->findRaw('parent=' . $this->page->id . ', template=Word', [ 'name', 'title', 'dictionary_category.title', ], [ 'objects' => true, 'entities' => true, ]); } } Here I'm defining the $method_aliases property directly on class declaration, but in some cases it could make more sense to define individual aliases via the API: $this->setAlias($alias, $callable, $params). 2) Another use case is referring to a method defined somewhere else — another controller, utility class, third party library, etc. Essentially this makes it easy to inject new methods or properties into classes implementing the MethodPropsTrait (such as controllers and components): class DictonaryController extends \Wireframe\Controller { public function init() { $this->setAlias('terms', '\Wireframe\Lib\Utils::getWords', ['page' => $this->page]); } } You can do the same with ProcessWire hooks or just have a method that calls another method, so this is largely a matter of preference 🙂 --- As I mentioned above, I've not had much use for this feature myself. It's been there since the very beginning, and it's a concept that seemed potentially useful (not to mention fun) while I was working on the initial implementation of Wireframe, but real world use cases have been few and far between. If you can think of other use cases, let me know 🙂
  15. What the error you posted says is basically that your code doesn't found a page matching the path you've provided. This is why it returns a NullPage object, which is kind of like saying "sorry, didn't find anything, here's a placeholder object for you instead". And since you can't remove a NullPage, that explains the error you saw. Now, what you're describing here sounds like some kind of a bug, though it's a hard to pinpoint exactly without access to the code, site, and/or database. Couple of suggestions: When this happens, I would first check if logging out and then in again removes that "page" from the menu. Admin menu is cached independently, so this could be the reason. Though I'm not sure why said cache wouldn't reset automatically. If that doesn't help and there is indeed an actual page there, it would be interesting to know what kind of data it has in the "pages" table in the database. Another reason why this might happen would be if a page is somehow corrupted. A typical signal of that would be that it exists in the database, but has a strange value in the "status" column. If you post your current code, I would be happy to take a closer look (at some point) in case there's some sort of issue there 🙂
  • Create New...