-
Posts
3,226 -
Joined
-
Last visited
-
Days Won
109
teppo last won the day on June 4
teppo had the most liked content!
About teppo
- Birthday 08/21/1984
Contact Methods
-
Website URL
https://weekly.pw
Profile Information
-
Gender
Male
-
Location
Finland
Recent Profile Visitors
97,130 profile views
teppo's Achievements
-
I hate to break it to you, but... you are now 😉 Seriously though, thanks for sharing this module!
- 1 reply
-
- 3
-
First of all, you’ve got some solid suggestions here. Thanks for sharing. Just a couple of notes: Agreed, IP based blocking should be enabled by default. I did notice that you said this was tested with the default settings, but it should be noted that IP blocking is an option that can be easily enabled. I do not agree with your second suggestion, though. In fact the system should preferably try to make blocked requests look exactly the same (and take exactly the same time) as those that were not blocked. Strictly from security point of view, that is; compromises often have to be made to meet user expectations. Though I definitely appreciate the sentiment, this is not really realistic requirement, in my opinion. HTTPS is always a good idea and available in most cases, but this could become an issue e.g. considering development environments. As such, I feel that current default makes a lot of sense, all things considered. And again, thanks for sharing your findings!
-
What is the logic behind the static resources folders?
teppo replied to Ivan Gretsky's topic in Wireframe
Hey Ivan, Sorry, looks like I've completely managed to miss this topic. Also, this could probably use a bit of an overhaul in Wireframe, and a docs page as well of course. This is indeed the default setup, and your guess is correct: "static" was initially borrowed from somewhere else (possibly some version of Zend Framework, or perhaps our old in-house CMS, but not sure anymore) and eventually replaced by "resources", which seemed to be more common term. assets/dist was added with the idea that this would be the location for built/generated versions. My current workflow actually places dist under resources as well — so there could be e.g. resources/scss/, resources/images/, resources/fonts/, and finally resources/dist/. Additionally I often have a resources/lib/ directory that contains "libraries", which may be third party dependencies that are not installed via yarn or npm, or site-/app-specific JavaScript classes etc. In my opinion this doesn't matter all that much, as long as there is a convention for placing said files, so that it doesn't change from project to project. Personally I would keep "resources", and place generated files in either resources/dist or assets/dist — latter part doesn't matter a whole lot, and as such I am now wondering if the whole assets/dist thing should just be discarded from Wireframe. Hope this helps explain things a bit at least 🙂 Technically I would like to have a "public" directory, but I'm not sure if that is really meaningful here: in the context of ProcessWire files are often accessed from other directories as well, so it is almost impossible to split the project into public and non-public parts in such a way. In something like the Sage theme for WordPress (at least slightly older versions, not sure of the current state) there were "resources" for source files and "public" that contained identical structure with built files — or copies in case of files that were not modified during the build process. -
This (GUI for querying results by field name) is now available. The "field" filter is disabled by default, but can be enabled via module config screen. Stored data may contain removed fields, so free form input is required, but a simple datalist HTML element seemed to work nicely for providing suggestions based on currently existing fields:
-
Finally got around to implementing this (open/collapse all toggle). Other suggestion, querying by changed field via GUI, is still waiting — though I think I might as well add that one too, just behind an "advanced" toggle in the module config ? Have you configured max age for data storage in Process Changelog Hooks module config? If yes, it should "just work". There is also a "prune data now" toggle that you can use to clean data based on the configured max age setting, but the module should also trigger this check once a day via LazyCron. If that doesn't work, it sounds like there could be some sort of issue on the site, though it's a little difficult to say what; anyway, I'd probably start by making sure that Lazy Cron works for something (e.g. via custom hook).
-
Please no ? To elaborate, there are a couple of issues with this: Depending on how this is implemented, it could be a major turn-off for users like me, who have never (and likely will never) click that "download" link on the website, let alone use a configuration tool to get a download package. Most of the time I'm installing ProcessWire via Composer or by cloning it via Git, and obviously my wish would be that this process isn't made more complicated. On the other hand I've seen some users (beginners) kind of trip on things like "you'll have to install a module to get Repeaters working" or "you need to get a separate site profile". As such, I don't think this would necessarily be a good idea considering new users either. A configuration tool would likely be interesting mostly for advanced users, who know exactly what they want... and prefer to use a download link on a website to get it, which (I would assume) somewhat limits its usefulness. That being said, as long as I can still get a "viable" version of ProcessWire (most of what's currently in the core, and future additions as well, assuming that they are meaningful ones — which they undoubtedly will be!) without having to use a configuration tool, I of course don't mind if it is added as an additional option. If someone likes that kind of thing, then great, why not! Also if this would mean that non-essential core modules could be also installed one by one via Composer, that would be nice ? What I'm missing here is the context: is this about getting a smaller downloadable package? Is that still a thing, e.g. is it really a problem for many users? Serious question, because I really don't know. I care a lot about performance on websites, but have never considered the download size of a CMS I'm using; unless it's in gigabyte range or something crazy like that. Or is it about dropping support for some core features? I'm not getting that vibe from here either, but that would make more sense to me, though in that case it might be better to just drop them from the core and perhaps find new maintainers for the packages if possible ? Or is there some other benefit I'm missing?
-
I'd love to suggest other things as well, but for now I'll just say that this is also my experience. Sorry in advance if this turns into a rant, but I feel that this is an important topic ? Past few years we've shifted our focus so that now we mainly use ProcessWire for sites with heavy focus on application like features and structured content, while "regular websites" are more often built with WordPress. There are cases where ProcessWire is stronger, and it can be used to build flexible, content block based sites using something like Repeater Matrix, but to be fair Gutenberg (which I/we use solely, no other page builders) is on another level when it comes to built-in flexibility and WYSIWYG. With one exception: you can't have multiple "Gutenberg fields" on single page, which can, in fact, be a pretty big bummer in some cases; and that could also be a potential benefit if we did have some sort of block builder in the core. (... and if ProcessWire, on a core level, wants to focus more on directory / application type sites, there's nothing wrong in that either. It just means that we, as a group of ProcessWire developers and enthusiasts, will be "losing" a large — and likely increasing — amount of potential clients and projects for other systems.) The work done by Bernhard and jploch is fantastic, but for me the biggest question mark is probably that these are not core features, meaning that they are not something that is "officially supported" by the core / core team. They are also not free / open source software, which means that the community directly participating in their development is not really an option, in my opinion. I'm not sure what the best solution, especially since this is clearly not a common need/requirement for Ryan, but I do hope that we could eventually have some level of support for this at the core — even if it's not "full-featured", but rather a framework that can be expanded / built on top of. Using Gutenberg as an example: I don't have a real figure, but I can tell that a team has worked on it for many years now, and continues to do it on a daily basis. It's not realistic to assume that a single developer could truly compete with that. And one thing I've learned about page/block builders is that there's a lot of nuance and the architecture is a major question that could make or break it, so doing it without solid understanding of what the results of each choice is way down the pipeline would be a huge gamble. (In case of Gutenberg the architecture is a hot mess: there are no dedicated data structures, and they keep changing and breaking internal code all the time. But, again, they have enough resources to handle that, and the project has so much momentum that while developers may complain, eventually they'll have to go with the flow.) As for Ryan's point about preferring to "avoid features that blur the line between content and style or front-end and admin", which I assume was related to this request (to some extent at least), I'm sure there are ways to handle content block GUI in the admin without putting too much focus on how they look like on the front-end. E.g. tje editing interface could be more like a wireframe with some similar structure than "the final product". Front-end editing is an option, but... I must admit that I like the "middle ground" that Gutenberg has, where you're still editing content in the admin. Obviously introducing front-end styles for the content in admin is not a nobrainer, which is why many sites — in my experience — won't even aim for fully stylized (custom) blocks in the admin. WYSIWYG is a big topic in itself ?
-
And here I was thinking that this is so useful that it should be a core feature ? Anyway, just wanted to say that I absolutely love the concept of this module. In fact both Custom Logs and Logs JSON Viewer are brilliant additions!
-
I’ve not touched this module in years. I’m not surprised that the GUI is a little wonky. It was never tested on the UIKit admin theme, let alone recent jQuery versions ? That being said, thanks for testing and identifying the issue, looks like an easy fix. As for alternatives, there are of course third party tools (at least for public content), and there’s also Verify Links from Robin: I can’t say for sure how much time and effort I’ll be able to put into this module, so I’d suggest checking Robin’s module out ?
-
Whether or not the system is built on top of a framework is, in my opinion, largely irrelevant. Or perhaps it would be better to say that "it is impossible to guess if and how it would've mattered in the big picture". Call me cynical, but dependencies are never free. Each adds weight to the codebase, requires upkeep and maintenance (sometimes including major updates or rewrites), and increases potential attack surface. Also many dependencies — and especially frameworks — bring in their own way of doing things, and since ProcessWire's architecture (hooks, data structure, etc.) is really a major selling point for the system, using a framework could've had a massive impact on that. Part of the reason why ProcessWire is such a brilliant system could very well be due to it not being powered by a framework itself. This means that every decision could be made without considering how that would fit the framework. What is also interesting, in my openiin, is the framework landscape itself. Back when ProcessWire 2.0 was launched, Laravel — now considered the latest state of the art PHP framework — wasn't even around yet. Zend Framework was probably the biggest name back then, or at least the one that most serious developers considered "most likely to thrive and stay around"... yet it was discontinued. Had ProcessWire gone with the "safe bet", that would've meant a big rewrite later, or alternatively staying on a platform that is merely a shadow of its former glory. Long story short, I think Ryan made a good choice ? Don't get me wrong, though: I'm a big fan of the Composer ecosystem — almost all of my modules are available as Composer dependencies, etc. And, in my opinion, ProcessWire actually integrates quite nicely with external dependencies. Since HTTP clients were mentioned, I'll use that as an example as well: in some recent projects I've used Guzzle together with ProcessWire. I may not be able to (easily) swap the client used by the core itself, but I've yet to come across such a need anyway. Of course this comes with a cost: I recently had to migrate one project to a new server simply because a third party dependency decided to drop PHP 7.4 support. In a minor version, because why the heck not. Not that it's a bad thing necessarily to bump up the PHP version, but having to do that sort of thing in a hurry just because I prefer to use a recent and patched version of a dependency is just bollocks. This is starting to get a bit rambly, so I'll just leave it here.
- 18 replies
-
- 11
-
There's no such thing as an ignorant question, but in this case I would probably lean towards "unnecessary headache" ? If ithe goal is to use some data from Strapi and combine that with some content produced in ProcessWire, this might make sense. E.g. the data from Strapi would only cover part of the project. But if the client wants to continue to manage all their content in Strapi and you'd just be using ProcessWire for the front-end, this would mean that you'd be mitigating much of what ProcessWire has to offer. Not to mention that it might be a bit of work to make the systems run smoothly together, and when things inevitably change in the future, you'd be doing every update to the content structure twice: once in Strapi, and again in ProcessWire. I'm not familiar with Strapi, but I'm pretty sure they have a decent API already (considering that it's a headless CMS that's kind of their bread and butter) so personally I'd consider building the front-end using something else. Laravel might be a decent PHP choice, but there are many other solutions as well. Most commonly folks seem to combine Strapi and similar headless systems with some JS framework, e.g. https://strapi.io/integrations/vuejs-cms. Anyway, that's just my opinion ?♂️
- 1 reply
-
- 3
-
Reactions is a module that collects reactions for pages from site users/visitors based on a click of a reaction button. It's basically the same thing as those "did you find the information you were looking for" thingies you see on some sites. An example of what the buttons might look like: There is also a very simple process module that displays pages along with their reaction counts for each enabled reaction type. GitHub repository: https://github.com/teppokoivula/reactions Modules directory: https://processwire.com/modules/reactions/ Needed this for a project and was kind of in a hurry, so it's not super polished, but seems to work well for basic use cases. One thing that's kind of fun (or scary) about this module is that it modifies the structure of the reactions database table automatically based on active buttons; this is done using ProcessWire's built-in features ? Getting started You can install the module the usual way; clone or download the code, or install via admin. Or via Composer: composer require teppokoivula/reactions The easiest way to define available buttons is via site config: $config->reactions = [ 'reaction_types' => [ 'like' => [ 'title' => 'Like it', 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M720-120H280v-520l280-280 50 50q7 7 11.5 19t4.5 23v14l-44 174h258q32 0 56 24t24 56v80q0 7-2 15t-4 15L794-168q-9 20-30 34t-44 14Zm-360-80h360l120-280v-80H480l54-220-174 174v406Zm0-406v406-406Zm-80-34v80H160v360h120v80H80v-520h200Z"/></svg>', // optional attributes, either as an associative array or as a string, e.g.: // 'attrs' => [ // 'data-some-attr' => 'value', // ], // 'attrs' => 'data-attr="value"', ], 'love' => [ 'title' => 'Love it', 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m480-120-58-52q-101-91-167-157T150-447.5Q111-500 95.5-544T80-634q0-94 63-157t157-63q52 0 99 22t81 62q34-40 81-62t99-22q94 0 157 63t63 157q0 46-15.5 90T810-447.5Q771-395 705-329T538-172l-58 52Zm0-108q96-86 158-147.5t98-107q36-45.5 50-81t14-70.5q0-60-40-100t-100-40q-47 0-87 26.5T518-680h-76q-15-41-55-67.5T300-774q-60 0-100 40t-40 100q0 35 14 70.5t50 81q36 45.5 98 107T480-228Zm0-273Z"/></svg>', ], 'haha' => [ 'title' => 'Haha!', 'icon' => '<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-260q68 0 123.5-38.5T684-400H276q25 63 80.5 101.5T480-260ZM312-520l44-42 42 42 42-42-84-86-86 86 42 42Zm250 0 42-42 44 42 42-42-86-86-84 86 42 42ZM480-80q-83 0-156-31.5T197-197q-54-54-85.5-127T80-480q0-83 31.5-156T197-763q54-54 127-85.5T480-880q83 0 156 31.5T763-763q54 54 85.5 127T880-480q0 83-31.5 156T763-197q-54 54-127 85.5T480-80Zm0-400Zm0 320q134 0 227-93t93-227q0-134-93-227t-227-93q-134 0-227 93t-93 227q0 134 93 227t227 93Z"/></svg>', ], ], ]; ... though you could also add them programmatically, e.g. if you wanted to manage them via admin: $wire->addHookBefore('Reactions::setReactionTypes', function(HookEvent $event) { $reaction_buttons = $event->wire()->pages->get(1)->reaction_buttons; if ($reaction_buttons->count()) { $reaction_types = []; foreach ($reaction_buttons as $reaction_button) { if (!$reaction_button->title) continue; $reaction_types[$reaction_button->name] = [ 'title' => $reaction_button->title, 'icon' => $reaction_button->icon && $reaction_button->icon instanceof Pageimage ? $reaction_button->icon->filename : null, ]; } if (!empty($reaction_types)) { $event->arguments(0, $reaction_types); } } }); The module has basic styles and scripts bundled in, though you'll have to load them yourself: <link rel="stylesheet" href="<?= $config->urls->Reactions ?>styles/reaction-buttons.css"> <script src="<?= $config->urls->Reactions ?>scripts/reaction-buttons.js"></script> ... and then call the render method to render the buttons in your template file(s): <?= $modules->get('Reactions')->renderReactionButtons() ?> For those interested in doing stuff like displaying something based on the answer, bundled JS triggers an event that you can listen to: document.dispatchEvent(new CustomEvent('reactions-updated', { detail: { pageID: pageID, reaction: reaction, }, }, { bubbles: true }));
- 2 replies
-
- 12
-
Using int() and render() controller methods together
teppo replied to Ivan Gretsky's topic in Wireframe
Hey Ivan, Sorry for the delay. In all honesty: usually render() is the one you want. There are very few cases where init() is better, or necessary for that matter. Behind the scenes init() is triggered as soon as a Controller class instance is created; at the end of the __construct() method. Meanwhile render() is only called when a page is, indeed, rendered. This means that render() gets called one time for each rendered page (e.g. in case you're rendering multiple pages within single request), while init() is called for each item as soon as their controllers have been instantiated. Personally I've ended up using render() pretty much all the time ? There is no built-in solution for this, but if you want to stop rendering the page as soon as you detect (in init()) that you don't want to render it, you could e.g. trigger a redirect, or perhaps call wire404(). Now, if you do use this solution, you'll want to make sure that it's not a "page being rendered within another page" type of situation, as that would be pretty problematic. Alternatively you might be able to call $this->setView() to override the default view file to something specific to an error scenario. I'm not 100% sure of this though, as its not really something I've every done ?- 1 reply
-
- 2
-
Weekly update – 8 March 2024 – New invoices site profile
teppo replied to ryan's topic in News & Announcements
Awesome — thank you! I'll definitely put this into use ? Hard to say how common of a need this would be, but I wouldn't be against it (obviously). -
Weekly update – 8 March 2024 – New invoices site profile
teppo replied to ryan's topic in News & Announcements
Just this week had to deal with the same thing on a site with 100+ translatable strings, many views reusing same translations, and three languages. Ended up splitting translations into a (static utility) class that has a string() method that returns the translation. So basically the same thing that Ryan has done here. Biggest difference is that since many of those strings in my case also exist in the admin as field labels, I added a fallback that first checks if a translation for current language exists, and then falls back to the field label if possible. I guess this confirms that I'm not doing anything too silly ? ... but on a loosely related note, if anyone has a good idea how to check if a string has been translated, I'd be happy to hear. I'm currently just comparing the source value to the return value and if it has not been changed I'll assume that a translation wasn't found. That's obviously a bit crude. Would be nice to have some way to check if the returned value from the translation method in core is indeed a translated version ?