-
Posts
158 -
Joined
-
Last visited
-
Days Won
6
Everything posted by poljpocket
-
Just to understand better: For your use case, is there any specific reason not to use: fetch() to load the config from an API, or $config->js() or $config->jsConfig() to hydrate your JS from the backend, or inline JS as config in the <head>?
-
Emptying / resetting all fields for a recently cloned page?
poljpocket replied to theoretic's topic in General Support
Reading this, I am asking myself: A clone followed by a data wipe is nothing more than creating an empty new page with the same template, right? Why don't you disallow clone for these templates (possibly for your client's role only) and instruct your users to use "new" instead? -
As @da² said, you shouldn't rely on page names like that in your code since names can change and also, you shouldn't prevent that (for SEO, localization and other reasons). The next best thing is to use different templates for each of your companies. With that, you get custom page classes for each of them and your challenge solves itself. Doubling down on your code though, why not use a new method in your custom page class, e.g. <?php namespace ProcessWire; class CompanyPage extends Page { // [...] public function tools() { $companyClassName = "ProcessWire\\" . ucfirst(str_replace('-', '', $this->name))."CompanyTools"; if(!class_exists($companyClassName)) return false; $event->return = new $companyClassName(); } // [...] } instead of the hook? You can also go all in on the PW style using hooks: <?php namespace ProcessWire; wire()->addHookProperty('CompanyPage(name=microsoft)::tools', function($event) { $event->return = new MicrosoftCompanyTools(); }); wire()->addHookProperty('CompanyPage(name=google)::tools', function($event) { $event->return = new GoogleCompanyTools(); }); wire()->addHookProperty('CompanyPage(name=apple)::tools', function($event) { $event->return = new AppleCompanyTools(); }); // [...] .. but this removes some of the flexibility of the class_exists call above.
-
Update to my last post. The fix sadly isn't easy enough. At least for the whole function "collapse" it is not. The line itself is fixed but, this code here does unexpected stuff when $r = ''. https://github.com/processwire/processwire/blob/3cc76cc886a49313b4bfb9a1a904bd88d11b7cb7/wire/core/WireTextTools.php#L454-L456 foreach($this->getPunctuationChars() as $c) { if(strpos($str, "$c$r")) $str = str_replace("$c$r", "$c ", $str); } Here, the strpos check actually will match any punctuation character no matter the position because the real issue is that we are losing any reference to the replacement positions when the replacement is nothing.
-
A quick code read gives me this problem. I think you are right, this is a bug! Line 443 of WireTextTools must be the culprit: https://github.com/processwire/processwire/blob/3cc76cc886a49313b4bfb9a1a904bd88d11b7cb7/wire/core/WireTextTools.php#L443 while(strpos($str, "$r$r") !== false) { ... } PHP 8 strpos will always return 0 (zero) for an empty string as needle (which is the case for $r = ''). And thus we get an endless loop. PHP 7 strpos will trigger a warning because the needle is an empty string. Nevertheless, the result is false and the loop breaks. I think your code was generating these on PHP7 but didn't fail and thus, you didn't care about it. This behaviour matches the updated strpos function in PHP 8, see Changelog here: https://www.php.net/manual/en/function.strpos.php @Ferdi Derksen this is your finding. Would you like to post the issue? I can produce a PR for it afterwards if @ryan would like me to. The fix is easy enough.. while($r && strpos($str, "$r$r") !== false) { ... }
-
Sorry for OT, but this isn't true. Maybe it is because the documentation lacks any mention of it, but years ago, @ryan fixed that problem in this commit: Add support for retaining abandoned translations in `__('text')` call… · processwire/processwire@34cc4e9 (github.com) You can pass an array with all alternates (as he calls them) to retain the old translations, e.g.: <?php namespace ProcessWire; $stillWorkingForOldTranslation = __(['new_translation_value', 'old_translation_value']); Like this, you can update your strings and still carry over the old translations to apply to both the old and new versions of the strings. I have to be honest, I believe this isn't generally known. I only know this because I stumbled upon this whilst reading the source code of the ProcessWire Core. This strategy also works for _x() and _n() functions, and also in modules with $this->__(), ->_x() and ->_n().
- 14 replies
-
- 1
-
- language
- languagesupport
-
(and 1 more)
Tagged with:
-
Unable to add a language pack to site Modules.
poljpocket replied to zilli's topic in Module/Plugin Development
My *.info.php file was @ryan's suggestion when I contacted him about the exact same problem. Even then, it didn't work. I guess I just never removed the file. Ryan ultimatively added the language pack manually to the directory for me. You should ask him to do the same. -
ProcessWire decides the language displayed based on the URL. I am assuming you didn't configure different root URLs for your languages and thus, ProcessWire doesn't know which language to display and will revert to the default language. A quick test shows this exact behaviour. If you configure your homepage URLs into something like this, your languages will work:
- 14 replies
-
- 1
-
- language
- languagesupport
-
(and 1 more)
Tagged with:
-
I made some progress. With debug mode enabled, I tried to just go with what the error messages were saying. Seemingly, headers are being sent before the last ini_set calls were made. So I restructured the install.php a bit and moved the PW initialization in step 5 of the installer in front of the install-head.php include: No more warnings even with debug mode on. @ryan I think this might be worty of a PR? Would you like one?
-
As I mentioned, this happens to me every time. Well, I thought about how I'm installing PW usually: To start a new project and what do always enable for in-development projects? I enable debug mode. So, I am still testing around a bit, but using my docker image (https://hub.docker.com/r/poljpocket/processwire) the errors only are output if I enable debug mode, leaving debug mode disabled I get no warnings.
-
How can i limit the form request according to ip of the user?
poljpocket replied to kkalgidim's topic in Getting Started
Here's a good stack overflow article discussing exactly what I am trying to say: Is it reliable to use the IP address to identify a user on your website? - Stack Overflow -
How can i limit the form request according to ip of the user?
poljpocket replied to kkalgidim's topic in Getting Started
Good approach. Didn't know if you actually used PW pages for the submissions, so I stuck to a direct SQL query. But of course that works this way. May I ask why you are limiting this by IP address? First of all, like that you are locking out all users behind one IP address. Means, that if a large number of your visitors is working from a private network with NAT, they will all have the same public IP and thus combined, they all can only post five trades per day. Second, if you want to really limit the trades one single user can do, the IP doesn't help you. I can simply spin up my VPN and have 5000+ IP addresses a click away. All of a sudden, I can post 25000 trades per day and you wouldn't even know! And then, if another user using the same VPN provider tries to post his own legitimate trade, they can't because the IP has been used up already. That's why I added the bracket with bad idea in my last post. You should use user accounts with logins and email verification to really get closer to managing maximum trades per user per day. Luckily, ProcessWire has you covered with that. -
How can i limit the form request according to ip of the user?
poljpocket replied to kkalgidim's topic in Getting Started
Hi, if you really just want to limit by the IP address (off-topic but this is a bad idea!) of your visitors, I guess a simple approach would be to add the IP address alongside a timestamp of the form submission to your database table. Before you're adding submissions, you can then do something like this: SELECT COUNT(*) FROM form_submissions WHERE date_created >= DATE_SUB(NOW(), INTERVAL 1 DAY) AND remote_ip = ':ip'; Whenever that result is 2 or higher, block the submission. Does that help? -
Me too. You can solve this (from a technical point of view at least) by using language-alternate fields. Combine that with @bernhard's great suggestion to sync settings between your language fields and you should be all set. The only thing you're not getting from that is the cool tabs system LanguageTabs provides. I am always extensively tagging both templates and fields. With the tags, you can even have some of them be collapsed by default. This retains all the overview I need.
-
Thanks @Tiberium. Good to know I'm on the right track. Seemingly, crawlers mostly don't send the header in question and thus won't be affected by my implementation anyway. Also, I'm always sending hreflinks for all languages available and thus, crawlers shouldn't be blocked. @HMCB you have to decide your strategy based on what your site will do. If language is location-agnostic, just use two-letter language codes and just respect the language headers sent (e.g. with my snippet). If you are more region-oriented, go with your suggestion. Also, ProcessWire allows you to serve the default language on a path other than / (e.g. /en-us/). For this, just change the name of the homepage. Here is an example of a German page's settings tab for the homepage. The German version gets served at / and the French version at /fr/: Here is the same page with settings changed. German is at /de/ and French is at /fr/. With this, ProcessWire will issue an automatic 301-redirect to /de/ when the root (/) is requested: Remember these settings aren't set in stone once you started your project. You can change them at any point if you want.
-
@Tiberium how are you detecting the languages exactly? I am using the Accept-Language header because it's simple and works almost every time. Here is the snippet I am using which is in readySite.php because this should only run on the frontend. Note that this requires the Language template to have the custom field 'iso_code' which I am always creating no matter if the site is multilingual or not. <?php namespace ProcessWire; /** * @var ProcessWire $wire * @var Session $session * @var User $user * @var Page $page * @var Sanitizer $sanitizer * @var Languages $languages */ // language detection, also make sure language detection only runs once if ($languageHeader = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? false) { // see if we have run detection before if (!($session->get('http_language_detection_done'))) { // in any case, we got a header and can indicate we did run detection (even if it's not successful) $session->set('http_language_detection_done', 1); if ($languageInHeader = Locale::acceptFromHttp($languageHeader)) { // map the value to available codes $isoCodes = $languages->getAll()->each('iso_code'); $preferredLanguageCode = $sanitizer->selectorValue(Locale::lookup($isoCodes, $languageInHeader, false, $languages->default->iso_code)); if ($preferredLanguageCode && $user->language->iso_code !== $preferredLanguageCode) { $requestedLanguage = $languages->get("iso_code=$preferredLanguageCode"); $session->redirect($page->localUrl($requestedLanguage), false); } } } } Do you have a better approach? Without JavaScript that is. I don't like that at all.
-
Remember that if you have all your country sites in one installation (without my inputs below), you are stuck with one set of Templates, one set of Fields and one set Languages (PW's term for localizations). From experience I can tell you that the more sites you have and the more different markets have to be reached, the more you will run into problems. Mostly, these will manifest in content only to be available in select regions and not others. I am from Switzerland and you could think, a site here should be in German and then offer a carbon-copy for French and Italian. Sometimes this is fine. For sites with multiple regional target audiences, I was immediately proven wrong though: The french want a banner for their super discount only the store in some location gets and the italians want a blog post which must only be available in their region. Remember, that a ProcessWire instance has one and exactly one default language/localization and all content must be available in this one language in order for the others to work. Now this is one country. You have multiple! Simply because of that, I would most likely use completely indepentent installations for every country. But PW has you covered! Here are some ideas: Building on @wbmnfktr's answer, there is also multi-site support in ProcessWire. This is where you have separate site folders with separate databases but all under one roof. More info here: Multiple site support in ProcessWire CMS. There is also multi-instance support which would allow you to e.g. fetch data from other installations (e.g. other countries for you). More info about this is here: How to use multi-instance in PW 3.x (processwire.com). You can use the multiple-site approach for your country pages. With this, every country has it's own set of Templates, Fields and Languages. They can mostly be the same but don't have to be the same at all. This allows for flexibility and sites to diverge from the "standard" as needed. On top of that, multi-instance would allow you to for example have a central newsroom section which gets displayed on all your sites somewhere.
-
Very interesting and reading through it, I was also instantly reminded of Mystique. And also, why I am almost never using fields like it. That is because of it's almost complete lack of support for selectors. Looking at your example, I am immediately thinking of problems like this one (people which have an email set, e.g. to filter contacts for a mail send operation): <?php $emailContacts = $pages->find('template=person,contact.email!='); Does your implementation support this? Mystique doesn't and you are stuck with loading everything and then filtering manually once the JSON is decoded.
-
I think ProcessWire has a well-estabilshed versioning plan: Ryan is increasing the version every few commits whenever some notable new feature was introduced. And the master version then just follows suit. I think a set release schedule with fixed time intervals is a very bad idea. I have been working with WordPress in the past and they have been notoriously bad at using their fixed minor release schedule. Sometimes a version introduced very important and big features and other times, there was barely anything new but both were minor releases just because the schedule said so. I have only been in the ProcessWire game for almost three years and thus have started out around where version 200 was released. At that time, I didn't look at GitHub too much though. I didn't notice the "slow releases" at all and was mostly influcenced by the forum and the website. For me, they did a good job. As many before me have mentioned, community activity is very important especially for new potential users (and even more to the target audience: fellow developers). This could also be reflected in more activity on the master branch. Finding a good solution might not be the easiest endeavour though. Has there ever been a situation where old versions needed to be patched for some bugs or security vulnerabilities? I haven't seen one yet. I think this mostly stems from the slow master releases which only ever get done when high stability has been reached. So for me, every master release is a "LTS" version, which is a big strength of ProcessWire: I have no reason to ever update a PW website I did years ago. As long as it doesn't get outdated because of external influences (PHP EOL comes to mind). I think using time-based releases like Ubuntu or Windows don't make much sense for ProcessWire. Years give a feeling of outdatedness. This directly contradicts ProcessWire's strengths: It does away with the stability and ease of upkeep arguments. How do you explain to a client that PW 2016.3 is still completely fine in 2024 and doesn't need any updates whatsoever? With operating systems, you want a sense of outdatedness simply because there is much more incentive to update to never versions, e.g. for hardware compatibility or platform support. Why not stick with semver with a few adjustments? One idea is to keep the patch part of the current versions as sort of like a build number which would primarily be used on the dev branch to indicate new features and fixes. And then every master version gets a minor version bump which corresponds to a dev version (indirectly that is). This would then allow for security fix updates down the road. Not that this would be needed much :).
- 127 replies
-
- 11
-
@wbmnfktr was just a minute faster, but I feel exactly the same way: I have to say I am using ProcessWire exactly because it doesn't force me into a direction and/or into a form of "best practice". But nevertheless I think there is already a lot of controller in the ProcessWire core. What you @szabesz want I think is a way to create your own controller manifested as a class and tightly integrated in the request lifecycle. But can't you already do that? That is the beauty of ProcessWire. You can alter anything I can think of with hooks. They will allow you to create a fully-fledged controller system if you want to. But again, I feel like ProcessWire handles most of the controller stuff one would ever need.
-
Hi all. Reading through the discussion about page classes, I have to add my two cents. I feel like we are mixing concepts here. We are talking about OOP concepts where the request arises to extend page classes' capabilities to better allow for separation of concerns. Many OOP concepts stem from or are just a fancy form of the MVC pattern. I strongly believe ProcessWire follows such a form too. Whereas the core handles MC and it's API provides endpoints for the V in Model-View-Controller and hooks for extending and altering the C part. So to really allow for separation of concerns, page classes aren't the right place to start off. A page is just the representation of an entity, a line in the database. Instances of said class that is. And thus Page and page classes belong to the Model part of ProcessWire. And this is exactly where my motivation to side with @ryan and his general scepticism of page class init and ready methods comes from. So it makes sense to add virtual properties or basic relationships to the page class. But the model should never contain business logic which acts outside of the lifecycle of the entity. Having made my point so far, I think Ryan's second to add a new class file to act as a controller (by using the ProcessWire's hooks) makes a lot of sense. And exactly that is why I believe, ProcessWire already offers a very good way to enforce MVC patterns and true separation of concerns. It offers a good API without forcing everyone to use the same architectural patterns so many other systems do.