• Content count

  • Joined

  • Last visited

  • Days Won


teppo last won the day on August 13

teppo had the most liked content!

Community Reputation

3,687 Excellent

About teppo

  • Rank
    Captain Earth
  • Birthday 08/21/1984

Contact Methods

  • Website URL

Profile Information

  • Gender
  • Location

Recent Profile Visitors

38,871 profile views
  1. teppo

    @thetuningspoon, it would be helpful if you could provide a limited test case (i.e. a minimal setup where this performance problem occurs), or if that's not possible/feasible, a description of the structure and this particular feature in as much detail as possible. For an example: What's the page structure like, and which part of it is cloned? Are users actual users or do you have "user" pages in a custom page structure – and if, do each of these have multiple orders? Or are you linking users to orders via a Page field or something along those lines? How many fields do your orders (if order pages is what you are cloning) have? How many Repeater fields there are, and approximately how many Repeater items (real content or ready items) do they contain? How many users/orders are you dealing with? Where in your page structure are you storing cloned orders? Are there any third party modules (or modules/hooks you've created) that could affect this? As you can see, this raises quite a few questions, and that's just the tip of the iceberg I'm afraid. All in all this sounds like something that would be easiest to debug by setting up a test case – otherwise it's difficult to isolate the issue. As @LostKobrakai already pointed out, 20 seconds for cloning a relatively small page structure is not normal, unless there's a massive amount of data to copy (in db or on disk). If you're dealing with a large number of items, Repeaters could of course also play a role in this: after all each repeater item is a Page, and their storage method can also result in bottlenecks at large enough scale
  2. Happy to do this, so thanks for the heads-up. Personally I've avoided commenting on existing issues unless I've actually got something valuable to add, mostly out of fear that a pile of "me too" comments would just make it harder to keep track of for Ryan or anyone else following the discussion. This is why the thumbs-up emoji seemed like a good alternative
  3. teppo

    Absolutely. The best approach depends entirely on the needs of a specific project and client For an example, while (re)building a large news site some time ago we first considered going with a page builder, but in the end implemented a single RTE field for the main copy of each article, with some minor layout customisations. The thing is that their old system was based on blocks, and one particular pain point with that was that since the authoring process itself relies on producing the whole text as a single document, it had to be manually split for the site. It's also true that new tools tend to require some getting used to. That first review is a good example of this: when you've had 15 years to get used to doing things in a specific way, migrating to a new set of tools can feel rather awkward. I'm not saying that Gutenberg is the "perfect" page editor, but it's not necessarily quite as bad as that text makes it seem: "Oh …. need an image in the middle of a text block … grunt. Create new text block, copy paste the first part of the text into the new text block, insert the image block." Actually you can just move the cursor to where you want the image, hit enter to create a new empty block, and then insert an image. Or you can insert the image right into the paragraph block if you want it inline with the text. "Oh … I needed the image one sentence further down. Old way – cut image paste where I want. " In this case you have a couple of options: click the arrows next to the image block to move it up or down, drag it where you want it, or copy and paste it to the right position. Admittedly the work in progress state of Gutenberg shows here: while "copy" already works, "cut" doesn't, so there's an extra step of deleting the old image. It is still a beta version, so I'd cut them some slack In my opinion a true professional is able to choose the best tool for the job, thus avoiding a cognitive bias commonly known as "the law of the instrument" (or "the law of the hammer"). If I run into a project where the client clearly needs a page builder, then that's what I'll use. The great thing about working with a system like ProcessWire is that we have so many options: one can implement a page builder together with a set of template specific predefined custom fields and all the benefits that come from being able to precisely define content hierarchies and URL structures. In other words it's all about having options – and of course having an open mind when it comes to exploring potential new solutions
  4. teppo

    By the way, since we're talking about page builders, I assume that everyone here is already familiar with Gutenberg? If not, in a nutshell it's a flexible and extendable (new custom blocks can be registered by third party plugins) page builder developed by core devs as an official alternative (and perhaps at some point in the future as a full replacement) for the current WP editor interface (which is essentially a customized TinyMCE field). Gutenberg has caused a bit of turmoil among the WP folks, with some considering it the best thing that has happened to WP and others wishing that it would just go away. Personally I think that it's a brilliant move from the core devs, and fits the WP ecosystem like a glove – not to mention that it has already spawned an entirely new category of third party plugins (Advanced Gutenberg Blocks, Stackable, Atomic Blocks, and so on). In other words it seems that the WP core devs are taking the page builder approach very seriously, while other approaches – such as custom fields and content types – remain in the realm of third party plugins.
  5. teppo

    I agree that there are valid use cases for page builders. In fact some of the biggest projects I've built on top of ProcessWire have utilized some form of that. Not just for fast mockups, but also because these sites often have hundreds or thousands of pages with varying layouts, meaning that a predefined fields approach would become a hot mess of dozens or even hundreds of separate templates and fields. That's simply not feasible. Regarding the idea of porting one of those tools to ProcessWire... if you're talking about a direct port, so far I'm not convinced. Elementor advertises itself as the only fully free and open source editor, and if that's true, then it's the only one we could port, and even then we'd have to convert a lot of WP specific code over. Elementor consists roughly of some 20k lines of JS, 20 external JS libraries, and plenty of PHP on top of that. In short it would be a massive project, and maintaining such a fork would be a full-time job. That being said I haven't had a closer look at the Elementor JS part, so it may be more portable than I currently think – but considering that it probably wasn't designed with portability in mind, that seems unlikely If only there was some sort of a CMS agnostic page builder framework, that'd be awesome
  6. teppo

    Hey @Soma! Sorry, finnish UI in the screen capture might've been a bit confusing. Hakutulokset = search results, tulokset = results. Anyway, the point was that I tried a dozen or so addresses and some local landmarks, and the only response was that error in red. Now it seems to work.
  7. teppo

    Probably a dumb question, but in $_form->render($form, function($form, $template) { ... }) what exactly is $_form? I'm assuming it's a instance of InputfieldForm, but is that right? Also, how are you adding callback support? As far as I can tell, by default InputfieldForm->render() doesn't take any arguments You mentioned that you "placed some bdb() calls in the createUser callback", but if you meant placing them within the createUser() function, have you tried placing them before it's called, i.e. before the "return $this->createUser($form, $template, true);" line? Just to make sure whether we reach that point at all. Assuming that this is all server-side code, I don't see how the browser could be relevant. The first options I can think would be ... To make sure that however you're adding these new features to the render() method, it really gets done on each page load. To make sure that this issue isn't caused by an error in the form, i.e. a required field being blank or having invalid value. To make sure that caching isn't involved (seems unlikely, but it might be worthwhile turning all kinds of caching off and test if the issue still appears).
  8. Not sure at what point this was added, but if you click the name of the image in admin, you can edit it in context. Save, and the filename will change. Personally I prefer sorting items in the order they appear in the admin. This way you can simply drag the images to the correct order, no need to tweak filenames
  9. teppo

    Slightly off-topic, but ... Not a very good first impression in terms of reliability. There's another search provider as well, but that one was unable to find anything with the keywords I could think of. This probably isn't a major issue for the whole platform, but the downside of a completely free and open service is often that "it works if it works". Best make sure that the client is also aware of this – i.e. that there are no guarantees whatsoever On topic: so far I think that providing Google with proper credit card details and defining daily quotas where applicable is the most viable solution. This change will likely limit our enthusiasm to offer certain Google Maps based solutions to clients as well. One possibly interesting thing is that previously Google Maps terms of service stated that the implementation "must be generally accessible to users without charge". IANAL, but one (strict) interpretation of this was that using Google Maps on a non-public site, such as an intranet, would require the premium version – and I can assure you that it's not particularly cheap, so most organisations wouldn't want to pay for it unless it was a key part of their business model. It seems to me that this limitation has now been lifted, making the use of Google Maps API a bit more flexible. I am not a lawyer though, so don't take my word for it
  10. teppo

    As @OLSA explained above, that's not how Repeaters work. In order to connect more than one instance of a specific field, behind the scenes they create pages, and store field values on those new pages. The change you've suggested here wouldn't be a trivial one, at least. Calling field value ($page->field_name) when multiple fields have the same name is one issue, and selectors are another ($pages->find("field_name=value")). Probably a few other issues as well, but at least in those cases we'd need to do a lot more – that would ultimately add a ton of complexity for a use case that, in my humble opinion, is very rare. Now, getting back to your original issue: Although I think I get what you're trying to do here, you're approaching this in a really "non-ProcessWire" way. When using any given system, you'll eventually run into things that work in a certain, perhaps unique way – and that's where you can either try to work with the system, or work against it. The latter, obviously, is not particularly productive approach. In ProcessWire fields are most useful (considering data architecture, use in selectors, keeping your code readable, and so on) when each of them has a specific and semantic meaning: "this field stores phone number, so we'll call it phone_number – and this one stores a first name, so let's call it first_name". When you need to reuse multiple fields on a single page, we're often talking about some sort of a content block builder, even if in your case you need to predefine the number of items, the order of items, and so on. For such constructs ProcessWire provides two options right out of the box, Repeaters and PageTable. Both have their own benefits, but it essentially boils down to this: while Repeater UI is more embedded to the Page editing workflow, PageTable uses modal windows for editing content – and while PageTable supports multiple different content types, Repeaters only support one (although you can use showIf settings to define rules governing when a specific field is displayed). Commercial RepeaterMatrix field (part of the ProFields package) essentially provides the best of both worlds, at least in my opinion: in-context editing like Repeaters and proper support for multiple content types. That's what I usually use for my client sites when a content block builder is required. If you're looking for a free (as in beer) solution, PageTableExtended is definitely worth checking out as well. To summarise: it seems that your use case would greatly benefit from the use of a repeating field type (Repeater, PageTable, or RepeaterMatrix). If the number of items and the order of them is the main issue and things will fall apart if those two are wrong, I would try to find a programmatic solution to that: use hooks to force each new page to have specific items – and when a page is saved, make sure that those items are still there. You could also hide or disable features that sort items or remove/add them using some simple JS or CSS, which you can embed yourself (via hooks), or by using a module such as Admin Custom Files. Finally, if you're adamantly against the idea of using a repeating fieldtype, one more (commercial) solution you should check out would be the Table fieldtype, which is also included in the ProFields package. It's essentially a flexible fieldtype you can use to create new custom fieldtypes on the fly, so more or less what OLSA suggested above, but with a nice GUI. This way you can quite easily make each of your fieldsets a single field, and you'd have much fewer fields in total. --- Hope I didn't come out too smug, but while I do sympathise with your struggle with this particular use case, in my opinion it is something that ProcessWire already supports – it just doesn't do it exactly the way you'd like to. Also: while this is no doubt among the use cases that can be solved using ProcessWire, in some cases you have to face that ProcessWire might not be the best possible tool for the job. Given the wide variety of web based solutions, such situations are bound to pop up eventually
  11. teppo

    Nothing wrong with this approach. You can always build your own, site-specific modules for such features, and as long as the module has "autoload" set to "false" ProcessWire won't load it unless you really need it – i.e. unless you specifically request it via a template file, a bootstrap script, etc. A "bare-bones" alternative would be separating this logic into a regular PHP file, which you then include as needed. Which approach makes most sense tends to depend a lot on the complexity and your use case, and even then it's ultimately a matter of preference If you do go with a module approach, you'd probably want to use something like this: <?php namespace ProcessWire; class MyModule extends WireData implements Module { ... } You can use .module or .module.php as a file suffix. ProcessWire supports both, but as far as I can tell .module is still more commonly used
  12. There are various ways you can achieve this, including plain PHP and even plain HTML+CSS (depending on your use case you might be able to convert this to a list and add those delimiters as ::after pseudo-elements – it might even make more sense semantically), but probably the easiest way would be the implode() method of the WireArray class. Since $page->authors returns an instance of PageArray and PageArrays inherit the methods of the WireArray class, you can do something like this in your code: <!-- Query of the authors --> <?php if (count($page->authors)) { echo "<u>AUTOR/EN</u>:&nbsp"; echo $page->authors->implode("; ", function($item) { return "<a href='{$item->url}'>{$item->title}</a>"; }); echo "."; } ?> A plain PHP solution using a counter variable would look something like this – this is probably the easiest method to understand for a not-so-experienced developer: <!-- Query of the authors --> <?php $author_count = count($page->authors); if ($author_count) { $count = 0; echo "<u>AUTOR/EN</u>:&nbsp"; foreach ($page->authors as $author) { ++$count; echo "<a href='{$author->url}'>{$author->title}</a>"; echo $count < $author_count ? ";&nbsp" : "."; // note: this is a ternary operator, see http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.ternary for details } } ?>
  13. teppo

    @netcarver, re-opening issues depends on who closed them. Here's the key part, borrowed from this StackOverflow answer: you can re-open your own issues *if you closed them yourself. you cannot close or re-open issues opened by someone else. you cannot re-open your own issues if a repo collaborator closed them Also: thanks for your work there – the issues repository is looking much better already
  14. teppo

    Hey there, All in all this sounds like a editor issue, not a ProcessWire issue per se – i.e. for some reason your code editor crashed and emptied the main.inc file, and perhaps deleted / emptied other files as well. Do you have any backups of the site files? It's a bit late to say this, but you should make regular backups of your work. Using a version control system like Git or SVN is preferable, but manual or automatic backups will do as well. If you're using ProcessWire 3.0+ you could take a look at /site/assets/cache/FileCompiler/ – if you're really lucky, you might have a compiled version of your main.inc in there. Although since you're having issues with the site, this seems unlikely. Sorry for not being able to help more here. The thing is that sometimes editors and such mess up, and the best protection you can employ is a version control system, or at least those regular backups. Hope you get this sorted out!
  15. teppo

    What you probably want to do is hook after Pages::saveReady instead. Something like this, perhaps: public function init() { $this->pages->addHookAfter('saveReady', $this, 'checkStateAndHide'); } public function checkStateAndHide($event) { $page = $event->arguments[0]; if(!$page->active){ $this->message("{$page->title} now hidden"); $page->addStatus(Page::statusUnpublished); } } Written in browser and not tested, but that's the general idea anyway. Note also the $this->page->addStatus() -> $page->addStatus() change: here you're trying to change the status of $page, not a class property $this->page. This should also work if you hook before Pages::save and just set the value there, but in my opinion saveReady is usually what you should use. If you hook after Pages::save, the page has already been saved, so you'd need to do another $page->save() or $page->save('field') in order to save any changes – but f you hook before Pages::save or to Pages::saveReady, the page has not yet been saved, so you can just set the value and it will be stored soon enough (By the way, you might want to check that the template of this page actually has "active" field – otherwise you could end up in a situation where pages without this field will be unpublished each and every time they're saved.)