-
Posts
474 -
Joined
-
Last visited
-
Days Won
31
Everything posted by FireWire
-
I'm glad you asked this! This should be pretty much a drop in replacement. The only thing you'd have to do to upgrade to the new version would be setting the language associations again and transfer any settings (like global excluded strings and API key) in the module config. Upgrading later will not cause any loss of website content and the work for developers should be minimal. The new features are implemented behind the scenes, so you just get more cool stuff ?. ProcessWire makes it possible to change editors between TinyMCE and CKEditor without re-creating the field, so using CKEditor editor now and then switching to TinyMCE later shouldn't cause any headaches. It really should be as easy of a transition as you can get with how well TinyMCE is concurrently being implemented (props to @ryan). As for the module, Fluency doesn't care what field/editor you use or if it's changed at any time because fieldtypes are detected and initialized by JS at runtime when the UI loads, not on the back end. So good news- I don't believe that there is anything that keeps you from using Fluency now and upgrading later. I've been working regularly on the module lately, my goal is this month or next. I think a wildcard will be testing but I'll be requesting help from the community here when it's time. I want this version to be the one that breaks out of alpha. Many thanks and I'll report back here when I have updates.
- 220 replies
-
- 2
-
- translation
- language
-
(and 1 more)
Tagged with:
-
Hello all! I've compiled a list of features that Fluency will have on it's next release and currently under development. There are a lot of new features and, as mentioned, it's being completely rewritten. I want to share some notable features that I think will be some great additions. IMHO, I believe that this puts Fluency in a first-rate position to make ProcessWire easier and more powerful for multi-language sites compared to other CMS/CMF platforms. If you've tried to use translation modules/plug-ins for other platforms I think you'll agree. As you can imagine, the feature expansion makes the module very powerful but it also means a lot of extra work. There will be an upgraded version available named (unsurprisingly) FluencyPro. Before I get into that, my commitment is to make the non-pro version the real-deal when it comes to quality and features. No features will be taken away from the core Fluency module and moved to the premium module. As you'll see below, the majority of new features will be available in the Fluency core version. Every feature in FluencyPro is new and complements the Fluency module that is and will always be free. I also want to make the Pro version very reasonably priced so it can remain within reach for as many people as possible and an easy sell to clients. The price will help offset the time and effort it takes and the support is greatly appreciated. More details to follow on that later. I chose the new features based on feedback from the community as well as my usage for sites I've built. Here is a list of new features that are coming in the next version: Fluency (core) Continuity - All existing features will still be available Localization - All Fluency admin UI elements can be translated to all languages present in ProcessWire. Includes the translation trigger buttons on each field, the global translation tool in the menu, etc. Error Handling - Will indicate things like the DeepL service not being available, usage limit reached. All errors will be translatable. Improved Module Config - Cleaner and more organized module config screen Inline Fields - Support for inline fields TinyMCE - Support for the new rich text editor CKEditor - Continued support for CKEditor to keep the module backwards compatible with ProcessWire sites that don't/can't use TinyMCE Per-language change indication - When content is changed in a field, the corresponding language tab will indicate that the content has been changed. This makes it easy to see where content should be updated in other languages. Translation Caching - Translations will be cached so that additional requests for the same content will not require additional DeepL API calls. This can help keep monthly DeepL API usage lower where possible and make repeated translations lighting fast. Cache can be manually cleared in the module config screen Logging - Improved Remains free - Free forever and will be open-sourced FluencyPro Multi-Language - Translate any content to any language for a field. Multi-Language - Translate any content from any language for a field. One Click Translate All - Any language to every other language for a field. This makes using a wider array of languages trivial when editing pages Markup Companion Module - Optional FluencyMarkup module provides individual easy-to-use methods for markup output to the front-end. This makes Fluency a complete translation solution out of the box. Features: Render all languages as prebuilt `<a>` links to navigate between page languages. Render a self-contained prebuilt `<select>` element with one click switching between languages on the front end while needing no additional JS required in your code. Inline JS is optional for those who prefer to implement their own. Render all alternate language `<link rel="alternate" hreflang="{ISO code}" href="{alt language URL}">` `<head>` tags to indicate that the page has additional versions in other languages. Great for SEO and adhering to HTML standards. Output the current language ISO code. Useful for turning `<html>` into `<html lang={ISO code}>` in keeping with HTML best practices. All render methods are hookable for additional customization by developers Notable overall code improvements: Written using PHP 8.0 (required for use) JavaScript rewritten in ES6 to make use of newer language features, is transpiled to ES5 to maintain browser compatibility. Transpiling is pre-configured and included with the module. Modular per-inputfield JavaScript so that adding new field types and updating existing ones in the future is faster and easier. Standardized composition so interfacing with fields within code is uniform and predictable. Server-side module code is being rewritten with the future potential to add additional "translation engines". While there won't be additional services available now, there will be a more standardized interface to make adding others easier. Both versions of Fluency will have this feature and can benefit from new translation services other than DeepL. This won't be 100% ready on release, but it is being kept in mind now. Future translation engines will have access to a uniform interface to use the Fluency caching feature with no additional overhead during development. Improved RESTful style API within the admin which lets other modules or PW customizations implement separate translation features using AJAX requests Leverages ProcessWire's built in JavaScript config object (as opposed to a separate API request on page admin page load) to speed up UI initialization .prettierrc and .editorconfig files to make contributing easier Thanks everyone for your patience, really excited for the new features! Cheers!
- 220 replies
-
- 11
-
- translation
- language
-
(and 1 more)
Tagged with:
-
Ryan has already responded to the Github issue and will merge the fix as soon as it can be confirmed. Passing along a PW API method call he shared that can fix this in case anyone that runs into this and wants to skip working in the DB directly.. $query->exec('RENAME TABLE tmp_field_body TO field_wvprofile_body'); Thanks @ryan!
-
Fantastic work! That table does exist in my DB. As for DB table names being lowercase by default, that seems to conflict with the admin UI. If the field lets you enter uppercase names, but table names default to lowercase, I think this issue is pretty much guaranteed to happen. I think that because the UI has shown that uppercase letters are accepted and it's been that way for a long time then the solution would be for $config->dbLowercaseTables to default to false. That would preserve the behavior shown in the admin and fix the issue going forward. But, I too, have started to dig deeper. I did a quick search because I was curious about case-handling in MySQL itself and if there might be additional scenarios to consider. Database case sensitivity is dependent on the filesystem of the underlying OS. Windows is not case sensitive, Unix-like systems such as Linux are case sensitive, macOS is almost always the exception to that rule where it's a Unix-like system but HFS+ is not case sensitive and APFS can optionally be (but only at the time of formatting the disk) and is not by default. Even Docker on Mac looks like it struggles with this. So I'm wondering if this is an environment issue and having $config->dbLowercaseTables is true to mitigate potential issues. Regardless though, the admin UI/name field validation should reflect the current DB casing configuration. The better option would just be to eliminate using uppercase letters for fields in the future if it would act as a sort of protection for all environments.
-
There was nothing special in the setup, it's a very similar setup to what I usually use on sites. Really appreciate you looking into it and running some tests! This is it. It was the uppercase B in Body that I accidentally put into Name instead of Label that conflicted with another field named body. Really appreciate @Robin S @wbmnfktr and @iank working to figure out what happened, I don't have the time to troubleshoot right now (deadlines!) and you really helped out. If I didn't find out what happened I would be kind of uneasy about the website. Ideally I think it would be best if field names were restricted to lowercase, but that would be a big breaking change at this point. Many situations could cause this: Text intended for the Label could mistakenly be put into Name and all data is lost for that field (my case) A developer may be familiar with this bug, but not know or have forgotten that a field already exists with a name that will conflict Accidentally mistyping with a capital letter where a lowercase letter would have shown the appropriate duplicate field name error I have opened a Github issue for this bug.
-
This was on a production server so debug is off, no warning. I am familiar with that data loss warning and didn't see it. I've only seen that when attempting to delete a field or change its type. v3.0.165, so stable and not the latest. I was able to restore the data by pulling a table from an SQL backup and running a query to create the table and insert all of the data. Was the main text field on ~120 pages so there was a chance for a lot of catastrophic data loss. ProCache kept the content live while I restored this but it was a real not-cool moment... ProCache and Cronjob Database Backup can go a long way to save a site with no downtime. Just still really not sure if this is something everyone needs to keep an eye out for or if it was a one time glitch.
-
Like the title says. Accidentally renamed "wvprofile_body" to "Body" where I actually meant to change the label. Didn't notice that I had entered that into the wrong field, hit Save. ProcessWire destroyed the wvprofile_body table then showed me an error saying that the field "body" already exists. I have no idea what happened. I've never had this happen before, but I've also never accidentally renamed a field to an existing field name. Has this happened to anyone else? Doesn't PW check for a unique name before deleting data? Looked in the database directly, the entire wvprofile_body table is gone. Keep backups.
-
I've been following the news on the new editor and I'll be adding that to the next version of the module. The module is already getting refactored so I'll be able to plan for this much more easily. I'll work on posting some updates here with some details on what's planned!
- 220 replies
-
- 5
-
- translation
- language
-
(and 1 more)
Tagged with:
-
@Robin S Brilliant! I don't know why I didn't think of that... Thanks!
-
Hello all, I am working on a module and wanted to know if there was a way to get deeper nesting in module admin URLs. Basic: /admin/coolmodule Renders with ___execute() in the module First child: /admin/coolmodule/info Renders with ___executeInfo() in the module Would like to create these: /admin/coolmodule/foo/bar /admin/coolmodule/foo/bar/baz Is there a way to do this virtually like __execute() and __executeInfo() or something similar? Can URL hooks be used within the custom module page? Thanks!
-
The logs show that this error has been happening for this version and the last version. I checked that the version of PW was compatible before upgrading the PHP version to 8 on the server. I inspected the network requests and it looks like this is a ProDrafts issue. It's attempting to save a field's changes. I was able to trigger this by creating a new page where it immediately detects a change to that field and shows the alert error. I attempted to fix this issue by adding a RegEx in the module's config but no dice. Using ProDrafts version 0.8.0 Tough to figure out what could be causing the conflict since it looks like like it's isolated to ProDrafts, but also tough to figure out since it doesn't seem to be happening more widely to other ProcessWire devs.
-
We are seeing consistent errors for a few fields. They pop up as browser alerts when editing pages and I'm not sure what's causing it. This error is thrown from a PW core file so not sure where to start with this. Seeing errors such as: "Field '_pw_page_name' is not applicable to this page" "Field 'status' is not applicable to this page" "Field 'wrap_delete_page' is not applicable to this page" This is happening for all users regardless of permissions and when editing any page. ProcessWire 3.0.2 PHP 8.0.16 From the looks of it I'm only seeing this happen with core fields, not fields I've created.
-
The files you work with will always be on your local machine. And I see no foolishness here :) Working inside the container itself (using the shell script in the Devilbox directory) shouldn't be needed so no worries there. Some recommendations (and me thinking out loud)- If you're getting a 500 error with a page title before failure then PHP is booting properly. I would start with ProcessWire's logs first in case it's able to catch that error when it executes. Could be more info there. Double check that $config->debug is set to true in config.php to see if you can squeeze out any more information from your 500. Check your .env config to make sure you're running either PHP 7.4 or 8.0 (depending on your PW version) just in case Devilbox's defaults to PHP 8.1 which PW isn't fully compatible with yet AFAIK. I think it might do that IIRC. Knock out those items and we can troubleshoot from there if it doesn't fix the problem.
-
Nice! Very awesome seeing the concept worked on and a great contribution to the ecosystem. Working with time bends my brain, you have my respect and admiration haha. Looking forward to seeing your work. Haven't used Alpine yet personally but it looks fantastic.
-
A couple months ago I reached out to the original author of Recurme and asked about the possibility of open sourcing the module and taking a role as maintainer. I've used this module previously and think a good calendar module is critical for the PW ecosystem. Had a great exchange with him and he was open and willing to turn over any assets needed and allow the code to be open sourced with no restrictions. As far as I know the module is still largely usable with the tweaks people have mentioned in this thread but I can't speak to more than that. I started working on refactoring the code and have a few ideas on how to improve/revamp it. I'm still enthusiastic about the idea of keeping development alive but unfortunately I just don't have the time right now to take it on with how busy I am with non-programming stuff as well as my commitment to getting the next version of my Fluency module released. I'd love to see this open sourced and would count myself as a contributor or help out where I can, but being a maintainer/lead is outside of my abilities right now. Hope there is some interest or capacity out there to make this happen.
-
What the hell are "outdoors" and "offline time"? I've never heard of this.
-
Back with more! Prepare for incoming wall of text... I mentioned adding custom directives to our .htaccess file and wanted to share some more detail on that as well as some other tips. I was reviewing our 404s as a matter of maintenance so to speak to ensure that we had redirects in place as necessary. While reviewing that I found a lot (a lot) of hits that were bogus, clearly bots and even web crawlers for engines we have no interest in being listed for. What I found was in just 48 hours we had 700 total 404s and I imagine on some websites that number could be higher. By analyzing that log and writing custom directives I was able to take 700 404s logged by ProcessWire down to 200 which are "legitimate" in that it's traffic that to be redirected to a proper destination page. I'm sharing my additional directives here as an example. Again, ANY bot/security directives should be at the very top of your .htaccess file. As always, test test test, and modify for your use case. # Declare this at the top of your .htaccess file and remove or comment out all other instances of this directive elsewhere RewriteEngine On # Block known bad URLs # Directories including sub-directories RedirectMatch 404 "\/(wp-includes|wp-admin|wp-content|wordpress|wp|xxxss|cms|ALFA_DATA|functionRouter|rss|feed|feeds|TKVNP|QXXLZ|data\/admin)" # Top level directories only - There are no assets served from these directories in root, only from /site/assets & /site/templates RedirectMatch 404 "^/(js|scripts|css|styles|img|images|e|video|media|shwtv|assets|files|123|tvshowbiz)\/" # Explicit file matching RedirectMatch 404 "(1index|s_e|s_ne|media-admin|xmlrpc|trafficbot|FileZilla|app-ads|beence|defau1t|legion|system_log|olux|doc)\.(php|xml|life|txt)$" # Additional filetypes & extensions RedirectMatch 404 "(\.bak|inc\.)" # Additional User Agent blocking not present in 7G Firewall <IfModule mod_rewrite.c> # Chinese crawlers that cause significant traffic to bad URLs RewriteCond %{HTTP_USER_AGENT} Mb2345Browser|LieBaoFast|zh-CN|MicroMessenger|zh_CN|Kinza|Datanyze|serpstatbot|spaziodati|OPPO\sA33|AspiegelBot|aspiegel|PetalBot [NC] RewriteRule .* - [F,L] </IfModule> Details on this additional config: It blocks some WP requests that get past 7G My added directives redirect to a 404 which tells the bot that it flat out doesn't exist rather than 403 forbidden which could indicate it may exist. I read somewhere that this is more likely to get cached as a URL not to be revisited (wish I could remember the source, it's not a major issue). Blocks a lot of very specific URLs/files we were seeing Blocks Chinese search engine bots, because we don't operate in China. These amounted to a lot of traffic. Blocks common dev files like .bak and .inc.* which aren't protected by default. Obvs you want to eliminate .bak altogether in production, but added safety fallback. I have not seen this cause any issues in the Admin. Also consider if directives could cause problems in another language. Customize by reviewing your logs Additional measures 7G and the directives I created are a healthy amount of prevention of malicious traffic. Another resource I use is a Bad Bot gist that blocks numerous crawlers that add traffic to your site but may or may not generate 400s-500s HTTP statuses. This expands on 7G's basic list. Bad Bot recommendations: Comment out: SetEnvIfNoCase User-Agent "^AdsBot-Google.*" bad_bot There's not really a good reason to block a specific Google bot If you make Curl requests to your server then comment this line out: SetEnvIfNoCase User-Agent "^Curl.*" bad_bot Reason: this will block all Curl requests to your server, including those by your own code. Be sure that you don't need Curl available if leaving this active. This is included in the list to prevent some types of website scrapers. If you want to leave this active and still need to use Curl, then consider changing your User Agent. Comment out: SetEnvIfNoCase User-Agent "^Mediapartners-Google.*" bad_bot Again, not necessary to block Google's bots, might even be a bad idea for SEO or exposure (only they know, right?). Testing There's no such thing as too much testing. These directives are powerful and while written well, may have edge cases (like 'null' mentioned previously). There's no replacement for manual testing, specifically it would be a good idea to test any marketing UTMs or URLs with GET strings you may have out there just in case. For automated testing I use broken-link-checker which can be called from the terminal or as a JS module. I prefer this method to using some random site scanning service. This will detect both 404s and 403s by scanning every link on your page and getting a response which is useful for ensuring that your existing URLs have not been affected by your .htaccess directives. broken-link-checker recommendations: Consider rate limiting your requests using the --requests flag to set the number of concurrent requests. If you don't you could run into rate limits that your managed hosting company, CDN, or you (if you're like me) have built into your own server. This terminal app runs fast so if you have a lot of links or pages those requests can stack up quickly. Consider using the -e flag, at least initially while testing your directives. This excludes external URLs which will help your test complete faster and prevent any false positives if you have broken external links (which you can handle separately). Consider using the -g flag which switches the request to GET which is what browsers do. Shortcut, just copy and paste my command: blc https://www.yoursite.com -roegv --requests 5 If you have access to your Apache access log via a bash/terminal instance then you may consider watching that file for new 404/403 entries for a little bit. You can do this by navigating to the directory with your access log and executing the following command (switch out the name of your log as needed): tail apache.access.log -f | grep "404 " You may consider also checking for 403s by changing out the HTTP status in that command. "This seems excessive" I think this is good for every site and once you get it dialed in to your needs can be replicated to others. There's no downside to increasing the security and performance of your hosting server. Consider that any undesirable traffic you block frees up resources for good traffic, and of course reduces your attack surface. If you need to think about scalability then this becomes even more important. The company I work for is looking to expand into 2 additional regions and I'd prefer my server was ready for it! If you get into high traffic circumstances then blocking this traffic may prevent you from needing to "throw money at the problem" by upgrading server specs if your server is running slower. Outside of that, it's just cool knowing that you have a deeper understanding of how this works and knowing you've expanded your developer expertise further. This isn't meant to be an exhaustive guide but I hope I've helped some people get some extra knowledge and save everyone a few hours on Google looking this up. If I've missed anything or presented inaccurate/incomplete information please let me know and I will update this comment to make it better.
- 8 replies
-
- 11
-
So @horst is correct about ProCache. ProCache renders HTML files to disk and uses some pretty clever directives in .htaccess file to detect a URL that has a corresponding page on-disk. If one exists then that HTML file is returned and the PHP interpreter never boots. We're currently running 7G and ProCache on the current site at our company. Unless you are configuring specific caching directives for HTML files in your .htaccess then you shouldn't see any problems. If you plan to use 7G or any bot blocking, it should be at the very top of your .htaccess so that it's directives are parsed before the rest that are there to serve legitimate traffic. The sooner the bots/malicious requests are deflected, the less impact on your server. While I've used 7G on many websites in production with no problems, it's important to test as noted by @nbcommunication in the comment above. He mentioned URLs with "null", while I've never seen any issues pop up with that since "null" isn't too common in English, I still keep the directive unchanged because that is there to detect malicious GET strings and similar undesirable things. 7G blocks a good deal of WP related requests however I wrote some additional directives that addressed requests that weren't caught. I'll share some of the additional customizations I've made that further filtered out traffic based on our 404s and web crawlers that we don't care for. If you're willing to get your hands dirty and write some custom htaccess directives you can dial it in even more.
-
Dangit. Sorry to hear that. The inline CKEditor thing is on my list but won't be added until the next version which I'm working on right now. The way that field renders is much different from other fields. I'll be sure to add that to the priority list to see what can be done.
- 220 replies
-
- translation
- language
-
(and 1 more)
Tagged with:
-
I haven't experienced that. I don't often use tables and can't remember if I've seen that. Fluency wouldn't be able to change how a field is rendered.
- 220 replies
-
- 1
-
- translation
- language
-
(and 1 more)
Tagged with:
-
Translating only for missing content should be good for performance. I do think that there are some items to consider. If this is used in a template when the page loads and caching is used then this function isn't guaranteed to execute since a pre-rendered HTML document would be returned to the browser. Caching is a good idea for performance so this would create a situation where you can't use caching and that would be a performance hit. If the content has been changed but you're only checking for the existence of translated text then it wouldn't re-translate. I have a solution for this but it would take a little extra code (detailed below) There is a possibility that using the function you wrote could mean additional calls to the database. Someone with a little more knowledge of the ProcessWire core could correct me if I'm wrong. If that's the case then there could be a performance hit that is dependent on how performant your database setup is. Performance difference would depend on how performant your DB and DB connection is. If you are running this loop on page load then the performance hit would really come from the delay in response from DeepL. Translation can take a couple of seconds in some cases and that will slow your page load time down a lot. This would only happen as long as something needs to be translated. If not then it will skip over the field and the page will load. As for the translation return value- the module returns a passthrough payload directly from the DeepL API (I didn't develop the return data structure). This is good because it is predictable and unchanged from DeepL documentation, and it makes sense when you consider the ability to translate multiple separate texts at once. Take some time to review the README.md file in the Fluency module directory, it has documentation of the return data structure and details on using the module directly. I'll make a note to let module users know that information is there for review. Solution for tracking changed content: One way to verify content is to use hashing and WireCache. I am developing the next version of Fluency that will have a solution for this but in the meantime here is a modified solution that may fit your use case: <?php /** * Analyzes the content in a field determines if it has changed since the last time it was checked * @param Page $thisPage Page containing field to check * @param string $fieldName Field object to check content for * @param string $lang Name of language to check content for default is PW's default language * @return bool|null Bool for content change, null if field doesn't exist on page */ function fieldChangedSinceCheck(Page $thisPage, string $fieldName, string $lang = 'default'): ?bool { if (!$thisPage->hasField($fieldName)) { return null; } $thisPage->of(false); $pageField = $thisPage->fields($fieldName); $isMultilanguageField = $pageField->type instanceof FieldtypeLanguageInterface; // Handle multi-language field if ($isMultilanguageField) { // Get the language, content in that language, and create a unique tracking ID $language = wire('languages')->get($lang); $current_field_content = $thisPage->$pageField->getLanguageValue($language); $key = "{$thisPage->id}|{$pageField->id}|{$language->id}"; } // Handle non multi-language data if (!$isMultilanguageField) { $current_field_content = $thisPage->$fieldName; $key = "{$thisPage->id}|{$pageField->id}"; } // Create a unique hash for the current content in this field in this language on this page $current_field_content_hash = hash_hmac('sha256', $current_field_content, $key); // Search WireCache for a previously stored content hash under this key if it exists, otherwise null $cached_field_content_hash = wire('cache')->getFor('field_content_tracking', $key); $contentHasChanged = false; // Compare the hash we created for the current content and compare it with the hash previously stored // If they do not match either it does not exist, or the content has been changed since it was last // analyzed if ($current_field_content_hash !== $cached_field_content_hash) { // Store the current content hash which will be used later to compare if content has changed wire('cache')->saveFor('field_content_tracking', $key, $current_field_content_hash); $contentHasChanged = true; } return $contentHasChanged; } There is a caveat, this solution will only tell you if it has updated since the last time it checked. So if a field was changed and you check the function will return true. If you check it again it will return false because it only tracks if it has changed since the last time it checked. I think this will still work for your use case as long as you act on it when it returns true. It works with multilanguage fields, regular fields, any language, and returns null if you try to check a value for a field that isn't on the page. Hope it helps!
- 220 replies
-
- translation
- language
-
(and 1 more)
Tagged with:
-
So I'm working on a new release and I just found this the other day myself. To fix this right away, change the following on line 172: <?php // From: wire('log')->save(self::ERROR_LOG, $message); // To: wire('log')->save(self::ERROR_LOG, $output['message']); This line means that there was a problem with DeepL. Either it had trouble connecting or DeepL returned an error when you tried to translate. In the ProcessWire admin take a look at the Fluency log, I think it may be named "deeplwire-api". It should contain the error to help you troubleshoot.
- 220 replies
-
- 1
-
- translation
- language
-
(and 1 more)
Tagged with:
-
PM me if I can share any info that would help get you up to speed. Can share some configs, code, or answer some questions if you need. I spent a lot (a lot) of time on tuning our setup and would be happy to share. Also, snapshot your "perfect setup" on DO before you host anything on it. I have one that is a template for our servers and I can spin one up in minutes. Also gives you some extra confidence with experimenting when you know you can nuke a server and start over with a machine built how you like it.
- 66 replies
-
- 3
-
- developing
- working with pw
-
(and 1 more)
Tagged with:
-
I don't know why I wasn't thinking about NPM security issues... that was a dumb on my part haha.
- 66 replies
-
- developing
- working with pw
-
(and 1 more)
Tagged with: