Jump to content

FireWire

Members
  • Posts

    629
  • Joined

  • Last visited

  • Days Won

    43

Everything posted by FireWire

  1. @ryan Fantastic work. I was just doing some heavy development around FormBuilder earlier this year and this is all awesome stuff. Thanks!
  2. @Mike-it I'm going to have to guess that this is a server issue that is unique to your environment. There's nothing that Fluency could do to change how the server delivers the JS file. The second error mentions the header which means that the way that your server is delivering the file to the browser is causing a problem because the browser is expecting a "text/html" document and the MIME type for a JavaScript file should be "text/javascript". Here's a stackoverflow thread discussing this same issue for JS. This is difficult for me to help diagnose since this is a one off issue that seems to be related to the server you're using rather than an issue with the module. If it's not happening in your development environment but it is happening in production then that also points to a server configuration issue.
  3. This is dedication to the PW craft 😎
  4. @poljpocket "It's not in the app so it shouldn't be in the app" isn't really a good argument against anything in software. Because it's a feature that would be beneficial to module developers and future utility. I think that's the point here- is the case being made for utility. I can see situations where this would be useful in the future and I don't have a reliable way to create dependencies that would make building on top of this functionality easy for me or users. Let's call my argument entirely separate from @bernhard as a developer who would love to see this supported without a complex module requirement process that doesn't exist and would require a lot more work to implement. If/when the time comes that something would benefit from adding hooks to the module, then it would be a good time to do it. There is no need to go and edit all of the JS for each module just to make it immediately available. It is perfectly fine to say that "many existing modules do not yet support JS hooks, but they may in the future". But the InputfieldDatetime.js example is probably a good example of where one may be easier to convert, at some point down the line (if it ever needed it), since it is a relatively simple JS file with few methods and not many lines of code at all. An alternative way of looking at this is that should the next version of a Datetime picker be chosen to replace this one in the core, for any number of reasons, then that would be a good time to write it for the first time. If a third party module for an alternate Datetime picker was to be written, it could make use of JS hooks if it's useful or valuable. All that aside, here's something that may resonate with the wider PW developer community. The server side API for ProcessWire is wildly powerful and flexible, however the client side is an area that has a lot of opportunities for growth. It doesn't have the dynamic nature of more modern front-ends. ProcessWire is built on jQuery and one of the things that @bernhard mentions were events. jQuery event listeners do respond to vanilla JS dispatched events and vanilla JS events can't be heard by jQuery. This can create interoperability issues for modules that primarily use vanilla JS and modules/core that strictly use jQuery. This bit me in the last couple of months. Hooks are an opportunity to bridge that gap, in the future. I need to stress this point- nobody expects the entire core to support this immediately or asking for it to. ProcessWire does not use event-driven architecture, it uses hooks to provide similar functionality. JS hooks are an opportunity to provide some sort of parity and additional powers on the front end that could translate somewhat into "if you know server-side ProcessWire hooks, you'll be comfortable using client-side hooks". One of the things that is really difficult for me to work around is not having a more dynamic UI in the admin. Having core and third party modules JS call hooks on specific events would make this much, much easier without having to write a lot of code or build an entirely new select input module. This is the first step towards an overarching client side admin API, which doesn't currently exist. Here's my hot take- jQuery is popular and easy to use but it will become a legacy library and in many ways it already is. I haven't used jQuery in projects in many, many years and the most recent lines I had to write were adding duplicate events fired in jQuery that I was already dispatching in vanilla JS in a module to make the rest of the UI see changes to fields. There are a lot of devs who really don't want to write jQuery. In 2025 it isn't necessary for jQuery to exist other than existing dependency or personal syntactical preference. There are going to be an increasing amount of people who want to use ProcessWire that have never written one line of jQuery. Does anyone expect the core to fully support hooks in all modules now? Tomorrow? Next week? Not at all. But having a framework in place that allows the core to continue using jQuery without overhauling it to bring a lot of extended functionality is really valuable. Nobody is asking that ProcessWire be rewritten in Alpine or htmx or something, hooks are a consideration for introducing more powerful features in the style of ProcessWire as part of a roadmap. Here are my questions @poljpocket: What is the best way to introduce new client side powers without completely overhauling the core JavaScript? Why is introducing powerful utilities that developers can use as part of ProcessWire being a framework, with parity in approach between server/client apis, that it may not prioritize using itself bad? If hooks can be introduced incrementally as needed, "as convenient", or by contributions and PRs- is that really completely overhauling the core JS? It seems like you are shooting down the simple examples, which are simple to show how easy using them can be, but haven't made the case for a true net negative other than saying "it will require work". This isn't how frameworks work, but it also doesn't preclude the value of having it available for use by the core in the future.
  5. Quick shoutout and thanks to @bernhard for both RockCalendar and RockJavaScriptHooks. Modifying the module UI to fit client preferences was one line in some JS added to the admin. It really opens up a lot of opportunities for making module JS as flexible and powerful as ProcessWire. Nice work 🙌 I came to post this randomly and didn't know about the ongoing conversation. Might have been good timing. @ErikMH Here is an example on site I'm working on. By default, RockCalendar times are 24hr, this hooks into the JavaScript method that creates the timepicker and changes it to 12hr time. JS hooks are supported in RockCalendar. // Set calendar time input to 12 hour ProcessWire.addHookAfter('RockCalendarPicker::settings', e => e.return.timePicker24Hour = false); Without this ability my alternative is to modify the module where it would break later or request a feature. "Can you add a config option for 12hr time" is a feature request I didn't have to write and @bernhard didn't have to read/implement and his module has even more utility right off the shelf. In cases where you're working on an open source/free module that can be a really big deal as well. Just to contribute a little more to the greater conversation- there is a lot of value in this. I would go as far to say "it will become clear how useful it is when you really need it." Hypotheticals for hooks are difficult. Most of the hooks in PW core are just "neat" until the time comes when they solve an issue or let you do something really cool. This would be more true if there were true dependency support in the core the way that it exists in Composer. Until then the requirement of dependencies is difficult to put on the user unless they come from the same author or are somehow packaged together in a way that handles that more easily. This is especially true since there is segmentation by module type (Inputfield, Fieldtype, Process, Markup, etc) and manually installing these one b one becomes exponentially tedious. If dependency installation existed then there could be fewer feature requests for Ryan or core contributors and that development can remain focused on the "framework" part of ProcessWire rather than individual unrelated feature requests. Perhaps this would be a good feature request for the core. In this case, JS hooks are a natural application of a fundamental feature on the client side implemented in a syntactically consistent way which encourages adoption and potential utility in the same. That would be my argument for core over module. Core support for the ability to hook into JS scripts can be established beforehand so that modules can take advantage of it and the core can implement gradually. It is an enhancement, not a breaking change, and doesn't modify the core API. A rollout where updates are prioritized by the greatest utility when feasible is an acceptable path forward IMHO. If hooks were part of the core I would write them into modules I build. The value of doing that is future creativity and problem solving by developers who use them.
  6. @DV-JF It's already merged with main but will be noted in the next release with credit for your contribution. Thanks again!
  7. @DV-JF I swear I thought I fixed that in a previous version... Thanks for the PR. I'm tidying up some updates and will include in the next forthcoming release.
  8. @Tiberium I have another way to attack this so I'll put together another commit on that branch and let you know. Unfortunately adding an ability to manually assign languages like the TranslatePage module would be a heavier lift than you might think since there are more features that Fluency uses. It would require rewriting the module config page for DeepL. The true solution is to make sure that the module performs correctly for everyone and preserve the UI that people are familiar with. It wouldn't be a good move to require some people who are having difficulty with API calls to forego features that are available to others who aren't. So I want to get this right for everyone 👍 Hold tight, I'll come back with another test. Please expect that via private message so we can more easily converse without adding too many more posts to this thread. When the issue is solved I'll come back and post a new release.
  9. @Tiberium This seems like a new issue that has happened to you and one other person over the past couple of weeks. There haven't been any changes to how Fluency interacts with the API for years. The API use to rate limit translations but now it looks like it rate limits all endpoints(?) What is odd is that only you and one other person have experienced this, or at least reported it here on the thread. I had to repeatedly hit the API endpoint 3-5 times to replicate the issue. I've updated the code to account for this but it is difficult for me to check since I have to create artificial conditions to replicate the problem. Can you test the code from this branch? Many thanks!
  10. New dev version of Fluency with fixes to address RockPageBuilder compatibility issues. Translating content within blocks should now save correctly. @bernhard @snck @Tiberium If you are able to test it would be a big help so I can merge this into a new release. I've tested this on text, textarea, TinyMCE (normal/inline), CKEditor (normal/inline), as well as image description fields. This should cover all multi-language fields. Download the .zip from dev and replace the entire folder (not copy/merge) in your modules directory. https://github.com/SkyLundy/Fluency/tree/development
  11. Here is what I'm currently doing: <?php class MyBlock extends Block { // ...rest of block /** * Determines if this block should render on the page * @return bool */ public function shouldRender(): bool { // For a field that displays featured activities. This is actually much more complex in real life // and keeping this in a shouldRender() method makes the template much cleaner return $this->featured_activities->where('date>=now&is_sold_out=false')->count(); // Sometimes blocks are saved in an incomplete state // Because ProcessWire doesn't have live field dependencies, an event has to be selected, page saved, // then activies in that event can be selected. This block shouldn't render until all of the information is complete. return !!$this->title && !!$this->event?->id && $this->featured_activities->count(); } // ...rest of block } View file: <?php namespace ProcessWire; /** @var Page $page */ /** @var MyBlock $block */ // This could be eliminated by making shouldRender() a method in Block.php if (!$block->shouldRender()) { return; } ?> <section class="rpb-myblock <?=$block->classes()?>" <?=alfred($block)?>> <!-- Block markup --> </section> If shouldRender() is defined in Block.php then it would be available everywhere. Otherwise to maintain consistency I have to do this in every block: <?php class AnotherBlock extends Block { // ...rest of block /** * This could be eliminated by making shouldRender() a method in Block.php */ public function shouldRender(): bool { return true; } // ...rest of block }
  12. @bernhard Forgot to mention that the first block of code is added to Block.php and is a method provided just for child blocks to override if they need. This way RPB will not render a block if that method returns false independently of the Inputfield UI for hide/unpublished state, which I think is what your for loop checks for. If I'm misunderstanding your for loop example then that could be my problem. A block can be published and unhidden, but the block can determine if it will render with its own logic.
  13. @bernhard My approach was very basic. <?php /** * Whether this block should be rendered. May be optionally implemented by blocks to control front-end visibility * @return bool */ public function shouldRender() { return true; } /** * Render this block * @return string */ public function renderBlock() { if (!$this->shouldRender()) { return ''; } // rest of method... } It works in practice as a function that does not modify RPB's existing behavior and the Inputfield UI takes precedence. Since this visibility is controlled by the blocks and not the user, the developer can work with this state. These may serve some edge cases, but it illustrates the philosophy of separating what is declared in the UI vs. in the block. <?php namespace ProcessWire; /** @var Page $page */ /** @var FeaturedActivities $block */ ?> <section class="rpb-foo <?=$block->classes()?>" <?=alfred($block)?>> <!-- You can create "grouped" behavior --> <?php if ($block->nextBlock()->type === 'Bar' && $block->nextBlock()->shouldRender()): ?> <p>Here's a little something extra</p> <?php endif ?> <!-- ...rest of block code --> <!-- Conditional design still possible --> <?php if ($block->isLastBlock() || !$block->nextBlock()->shouldRender()): ?> <span class="rounded-bottom-corners"></span> <?php endif ?> </section> The un-rendered will exist with an ID because the UI and RPB's core behavior dictates that the block exists and is available, but blocks maintain control of rendering separately.
  14. One of the things that I have to work around in a current site is lots of dynamic content. Content in blocks may change depending on values from other pages, dates/times, or updates from external sources such as APIs. Many of these are automated via hooks. My example is events and activities. Events can become active, tickets go on sale, be cancelled, end, etc. This is a block for "Featured Activities" Activities are selected by a person editing a page. They can choose as many activities as desired but only 3 are shown on the page If the date of an activity passes, or tickets are sold out, it is removed from the featured activities (automatically via hook) When one is removed another is rotated in (automatically via hook) If there are no more featured activities (all of the dates have past, or tickets are sold out) the block should no longer be output to the page. These are featured on many pages across the site with a lot of automation and updating them manually would be a very terrible thing 🤣 I have a handful of blocks that do stuff like this. The idea is a shouldRender() method for Block classes. By default it returns true but may be overridden to control whether a block will show up on the page. <?php /** * Whether this block should be rendered. Called before a block is output to the page. * @return bool */ public function shouldRender() { return true; } I have something like this cobbled together already in my code but I have to add an if statement to all of the block views that need this. I also use it for things like image galleries that shouldn't render if the image field is empty. It would be really nice native feature 😎
  15. @bernhard Awesome as always 😎 I don't know if you have a use case for trying the filesystem cache, but I recommend it. As it's a drop-in replacement it's a default for my projects. Sometimes just knowing it's the caching method is nice (I sleep better at night?) haha If you see any issues that pop up during testing it would be great if you could share them ahead of the release. Maybe there's a fix, maybe I need to reconsider it in project.
  16. @bernhard I made the following change to the code and it appears to work correctly. <?php public function __construct() { parent::__construct(); $this->path = $this->wire->config->paths($this); $this->wire->classLoader->addNamespace("RockMigrations", __DIR__ . "/classes"); $this->lastRunLogfile = wire()->config->paths->logs . 'rockmigrations-lastrun.txt'; // load all constant-traits in /site/modules/*/ $file = wire()->config->paths->site . "RockMigrationsConstants.php"; if (is_file($file)) require_once $file; $dir = wire()->config->paths->siteModules; foreach (glob($dir . '*/RockMigrationsConstants.php') as $file) { require_once $file; } $this->watchlist = $this->wire(new WireArray()); // $this->lastrun = (int)$this->wire->cache->get(self::cachename); <- Move this from here } public function init() { $this->lastrun = (int)$this->wire->cache->get(self::cachename); // <- To here $this->wire->classLoader->addNamespace("RockMigrations", __DIR__ . "/classes"); $this->wire->classLoader->addNamespace("ProcessWire", wire()->config->paths->assets . 'RockMigrations'); $config = $this->wire->config; $this->wire('rockmigrations', $this); if (!wire()->modules->isInstalled('MagicPages')) $this->installModule('MagicPages'); if ($config->debug) $this->setOutputLevel(self::outputLevelVerbose); // ...etc I'm not sure if there is a need to have the last run timestamp checked in __construct() that you know of and I am not familiar with but this change seems to work for migrations and resolves the issue.
  17. New thread from this original comment in the main RM thread. So I have WireCache Filesystem installed and it's a critical part of the back end of the ProcessWire application. This is a drop-in replacement by Ryan for the core database cache system. @bernhard from your original response: So the benefits of a filesystem cache are that it's lightning fast. It's really preferable in a lot of situations to database caches which require DB queries. It would be difficult to quantify in hard numbers but the simple fact is that filesystem reads are much faster that MySQL queries. This is negligible on local environments but in production is has a significant impact. The compatibility issue is that RM is getting the lastrun value in the __construct() before the filesystem cache has a chance to boot. Is it possible to move that to init or ready?
  18. That would be a great feature, however I will make a case for an implementation for your module. Since the module adds the lqip property and lqip() method to the image field object it would be important to selectively disable some features of the module and not others. It's important that they're always available so that there aren't any errors or unexpected behaviors. A full module disable might cause some of those. I'll send over the PR 👍
  19. Hey @d'Hinnisdaël. I recently tracked down a behavior that isn't a fault of your module, but where an additional feature in ImagePlaceholders would be a really big help. Since this module can affect so many fields and because it hooks into very common actions (savedField, savePageField) it would be really helpful if there was a module setting to globally disable placeholder generation. The issue I reported above ended up being with another module that was triggering placeholder regeneration for a very large group of fields due to a bug. This caused major slowdowns on the server as regeneration happened for all images in dozens of fields, many with multiple images. Up to hundreds of images in total. Regardless of the cause, having the ability to temporarily disable image generation for troubleshooting or whatever need may arise would be a very great feature. If you're open to a PR on Github, I've already written this into a local copy of ImagePlaceholders where the module is configurable and a checkbox is provided on the module config page to globally disable placeholder generation. Would be happy to contribute if you're interested. Thanks again for the great module!
  20. Thanks for sharing, good to know. I'll keep an eye out to see if this happens more.
  21. I am sporadically seeing this issue and it's difficult to detect why/when. When I get a chance I will take another look at how Fluency can help. @bernhard I'm still convinced that this isn't a problem with RPB and the measures that you/we have worked to to address this have been very robust. RPB is at no fault if changes to Inputfields are not properly being signaled by a class change or event. So the fixes in RPB seem to work partially but there are edge cases- why though I am not 100% sure of. The following is my best guess (we shall see for sure). I (pretty recently) found out that jQuery events are completely isolated from vanilla JS events. Events dispatched from vanilla JS do not trigger listeners in jQuery and vice versa. jQuery hasn't been part of my workflow for many years and dispatching jQuery events is an extra step that modules that do not use jQuery must take when necessary. Another native behavior of vanilla JS is that programmatically setting the value of a field does not trigger a change event, which is the reason all of this matters to begin with, so RPB and PW Inputfield listeners will not be triggered. For the record, Fluency has only ever dispatched vanilla JS events. Rather than try and track down why some changes are caught by ProcessWire/RPB, I'm going to take another crack at a solution. @Tiberium to bypass this you'll need to translate a field then manually click through the language tabs and add something like a trailing space to the content in each. ProcessWire trims leading/trailing spaces on save so this won't affect your content. This is annoying but it ensures that the changes to the field content are registered by both ProcessWire and RPB via a UI interaction. Thanks to all for your patience! Improving software one bug at a time...
  22. @bernhard Sounds good! To add to the greater conversation, here's how a .env file approach would work. A .env file is created for your local development. A .env file is created on a staging server if one is used. A .env file is created for the production server. Each file exists where they will be used and the values match the requirements for the application to run in that location. Since the .env file for a project is not committed to the repository, a commonly adopted way to document what is needed in it is to create a .env.example file that contains all of the variables used by the application without values. This is unrelated to @bernhard's reply but I didn't share some ProcessWire specific information in my original post that readers- whether choosing to use .env or not- may want to keep in mind. .env files are part of a secrets management strategy. Sensitive values should be stored in a separate location, like a password manager. The config.php file is a sensitive document. ProcessWire provides direction on securing the file on your server, however this doesn't account for workflows like Git or sharing config.php in collaborative situations. Sensitive values committed to a repository (even if it's private) must be considered compromised. It's not just about DB credentials. Here's an example: /** * Installer: User Authentication Salt * * This value was randomly generated for your system on 2023/02/22. * This should be kept as private as a password and never stored in the database. * Must be retained if you migrate your site from one server to another. * Do not change this value, or user passwords will no longer work. * */ $config->userAuthSalt = "c187bd9fx935ca861f43da592475fe6afa20a63"; Ryan's note says "private as a password", and that's real. Your auth salt must remain the same regardless of where your code is being run so it is a universally sensitive secret whether local, staging, or production. This unique value is part of how ProcessWire hashes passwords in the database. Having a config.php file committed in a repo with this value means that your site/app is now insecure. Removing it from your repo and pushing the change will not make it secure since it's in the commit history. So now you're faced with the situation of storing that value in addition to your database credentials which change depending on where your site/app is running. That's makes a case for a .env file or a secure solution like @bernhard is developing for his workflow implementation.
  23. @bernhard Glad you found it useful! Yes. The logic behind .env files is that they are tied to the environment/server, not the application, so 1 environment = 1 .env file. Think of it as the store of values necessary for your application to run in a given environment. Your application doesn't have to care where it's being run, it just knows that the necessary values will be provided and everything works. It would overwrite the cached file since the Env utility follows the general single-file usage of .env files Out of curiosity, how would multiple .env files be useful?
  24. @BillH Good thinking. I've used this before but didn't think to try that in this case. Thanks!
  25. Had a client attempt to upload a large (large) image file that ended up causing issues. These are 7-9mb files that caused memory issues. I deleted the images but this error is persistent when there are no images visible in the image field when editing the page: I've since re-uploaded the images after resizing them to a reasonable file size but this error still persists. I'm sure I could dig into the database/file system to remedy this but it would be really nice to have a ProcessWire way to deal with this. It would help with this instance and automate future issues. Any ideas on how to clear a stubborn problematic image/file?
×
×
  • Create New...