Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation since 04/02/2024 in all areas

  1. This week we have ProcessWire 3.0.238 on the dev branch. This version contains 17 commits containing new features (some via feature requests) as well as issue fixes. Recent updates have been nicely covered in ProcessWire weekly issues #517 and #518. Also added this week are the following: Improvements to ProcessPageClone, which now supports some new options such as the ability to configure it to always use the full clone form (a requested feature), and an option to specify whether cloned children should be unpublished or not. New $datetime->strtodate($date, $format) method that accepts any PHP recognized date string and reformats it using the given format. It also supports date strings that PHP doesn't recognize if you give it a 3rd argument ($options array) with an `inputFormat`. The existing $datetime->strtotime() method now supports an `inputFormat` option as well. The Inputfield class now has new methods: $inputfield->setLanguageValue($language, $value) and $inputfield->getLanguageValue($language), added by the LanguageSupport module. Previously there were no dedicated methods for this, so you had to manage them with custom keys containing language IDs if you wanted to programmatically use an Inputfield in multi-language mode. The ProcessWire.alert() JS method has been updated with an auto-close option (`expire` argument) that automatically closes the alert box after a specified number of seconds. InputfieldDatetime has been updated with 7 new interactively configurable settings for the jQuery UI date picker. See the screenshot below for an example of a few. Plus, its API has been updated with the ability for you to specify or override any jQuery UI datepicker option, either from PHP or JS, as requested by Toutouwai/Robin S. See the new datepickerOptions() method and phpdoc for details. Next week we've also got some more updates to InputfieldTable that take the newly added actions even further and make them easier to use. Thanks for reading and have a great weekend!
    19 points
  2. On the dev branch this week are a few issue fixes, but also some new features. The "Parent" field in the page editor (Settings tab) now is contextual to the page's template family settings. Now it will just show you the allowed parents, if you've configured them in the template. Previously it would show you a page tree to select from anywhere in the site. This saves you time, as well as the hassle of getting an error message after save, should you select a parent that isn't allowed by the page's template family settings. Next, the page tree "Move" actions (that you see when hovering a page in the tree) are now a little smarter. Previously, these Move actions would appear for any page that was either sortable or moveable. But now it also checks how many other allowed parents there are, per template family settings. If there aren't yet any other potential parent pages existing in the site, the page is no longer considered moveable, and thus won't show a Move action. This useful addition was added per Bernhard's request, as was the addition to a couple new classes used in the page tree to better differentiate between public vs non-public pages... something that I understand Bernhard's admin style may soon demonstrate. This week a question came up through email about how to make multi-language "required" fields require a value in all languages the page is active in. Currently multi-language required fields only require a value to be present in the default language. If you want to make them require all active languages, you can do so with a hook in /site/ready.php. I thought it was pretty useful so thought I'd share it here. Though maybe we'll have to add it as a feature. if($page->process == 'ProcessPageEdit') { $wire->addHookAfter('Inputfield(required=1,useLanguages=1)::processInput', function($event) { $inputfield = $event->object; $page = $inputfield->hasPage; if(!$page) return; foreach($event->wire()->languages as $language) { if($language->isDefault()) continue; if(!$page->get("status$language")) continue; // skip languages not active on page $value = $inputfield->get("value$language"); if(empty($value)) { $inputfield->error("Value required for language " . $language->get('title|name')); } } }); }
    18 points
  3. This week we have some updates for the ProFields table field (FieldtypeTable). These updates are primarily focused on adding new tools for the editor to facilitate input and management of content in a table field. All the details can be found in the new blog post with an accompanying screencast video— https://processwire.com/blog/posts/table-field-with-actions-support/
    17 points
  4. This week we have another update to the ProFields table field. A couple of weeks ago I wrote a blog post about Table v28 and the new actions features that it added. I've been working with Table a lot for my current client project, and have found these new features very useful. But I'm doing a lot of data entry in Table and found I still wanted more. Specifically, I wanted to be able to apply some of the actions directly on the row I was working in (rather than having to select it and then scroll down to the actions). Kind of like how one can click the Trash icon on any row to delete the row... I wanted to be able to apply other actions in the same way (Add, Clone, Copy, Paste). And Table v29 (released today) does exactly that. Another desire I had is for the for row-level actions to be just really simple, with not too much to look at... something folks could use rapidly without having a lot to read. This leaves several powerful and verbose features for the actions menu you saw earlier (the one that appears under the Table). Below is a video that outlines these new row-level actions. It's actually the same video from before, but I added to it for the version 29 features. So I'll try to post a link that starts at the timecode of the new stuff. But if you haven't seen this video before, you may want to rewind to the beginning. Below is the full CHANGELOG for this version: Expanded actions support so you can also execute actions directly on individual rows, which is often more convenient than selecting rows and then applying actions. Hold down the SHIFT key before clicking the row actions select and it will convert any actions that usually append rows to instead prepend rows. This works with the the Add, Clone and Paste actions when clicked at the individual row-level. It also works with the Select action for selecting multiple rows at once. The Select action is there in part for people that may not realize you can already click the sort arrows to select the row. Removed the Vex dialogs when copying or pasting and replaced them with other visual cues to indicate successful copy and/or paste. Added a new config option for disabling the DELETE (trash) icon on individual rows when individual row actions are enabled. This is because the row actions already include a delete action, so the trash icon can be redundant for some who might prefer the additional space. For all non-page selection column types, a new "Settings" option was added (named “formattedValueType”) to indicate how the value should be represented when accessed from a formatted page. Previously the API value was always the selection value. Now you can specify that it should include both the value and label (in your choice of array), or just the label rather than the value. Table v29 beta is available for download now in the ProFields download thread. More core updates are likely for next week. Thanks for reading and have a great weekend!
    13 points
  5. Following the advice of some PW-forum members @gebeer @dotnetic @bernhard @sebibu, I would like to share my first Processwire module with all members. QuickSave: My first attempt at developing a PW module to quickly save a page. What can the module QuickSave do: Quickly save a page edit in the admin and return to the last activity. Adds an extra save button AND shortcuts CMD+s and CTRL+s. QuickSave includes an additional plugin for TinyMCE. The plugin for TinyMCE must be assigned and activated specifically for these textarea fields. (Keyboard input shortcut does not yet work in an iFrame - RTE/iFrame, CKE, etc.) PW-QuickSave-1024-v16.mp4 Installation: To install the module, it simply needs to be copied into the Processwire module directory and then activated in the Processwire admin. Optional: Anyone who uses TinyMCE can activate the keyboard input shortcuts via the configuration as a plugin for TinyMCE. Afterwards it has to be activated for the field (e.g. body). This is the path for the configuration in TinyMCE: /site/modules/QuickSave/tinymce/quicksavetinymce.js QuickSave-TinyMCE-inst.mp4 I have been using the module only as a save button version for some time in a long Processwire page with a strong content and a four-fold nested repeater matrix and it works. The keyboard shortcuts were added because of a request. I was only able to test these on the Mac and hope they also work with Windows browsers. Due to another request, the short notification after saving was added. I hope you like the module and that it helps the moderators to keep a better eye on the areas they are currently working on. Especially with long pages and, for example, a table with many rows, it is very helpful for me not to lose the row when saving. (see the video) Note: The module does not intervene in the Processwire saving process, only the original saving button function is triggered. Please note that the keyborad shortcodes do not work in iframes or CKEditor. UPDATE: New version 0.1.7 added on April 13, 2024. A new combined version without jQuery has been created. Thanks to @dotnetic and all others 🤗. It is now more optimized and further optimizations are planned. Module 0.1.7 Download: QuickSave.zip Feedback on whether the keyboard shortcuts ctrl+s work under MS Windows would be great... 🤗 Thanks and Greetings Chris
    10 points
  6. It's been talked about elsewhere here in the forums, but an alternate idea would be utilizing .env files. It would satisfy both the installation process and long-term management of values. Some benefits: Widely used across applications, frameworks, and languages running in a web server environment and strongly recommended as a standard practice Secure by default. Web servers do not serve .env files Provides the ability to manage local and production configurations separately Frameworks like Laravel provide a .env file as well as a .env.example file containing all variables used in the application. This is kept up to date, used to document application requirements, and is committed into the repository Values that are not security-critical can be safely stored in the example file Provides a convenient location for additional non-ProcessWire site/app specific values such as API keys, or those required for modules Solves the issue of excluding site/config.php from a repository given that it's a required file containing specific syntax and $config object property assignments If .env was available in ProcessWire I would have my Fluency module look for translation API keys there rather than store them in the database. A benefit there is that different environments like local/ staging/production can mean an environment that is yours and an environment that is a client's. Pulling the latest copy of a database from production wouldn't require manually re-configuring modules that require API keys, or module registration keys. It would be good to eliminate storing security-critical values in PHP files entirely. The .env file could be generated and populated during the ProcessWire install process pre-excluded in the .gitignore file. Example: ENVIRONMENT="development" # ProcessWire PW_DB_HOST=localhost PW_DB_NAME="your_database PW_DB_USER=your_database_user PW_DB_PASS="LowuHeju7[BoI3" PW_DB_PORT=3306 PW_DB_ENGINE=InnoDB PW_DEBUG=true PW_CHMOD_DIR=0755 PW_CHMOD_FILE=0644 PW_USE_PAGE_CLASSES=true PW_USE_FUNCTIONS_API=true PW_PREPEND_TEMPLATE_FILE="_init.php" PW_USER_AUTH_SALT=d5e3ac4beda1e382255bbd8744d7e815 PW_LOCALE="en_US.UTF-8" PW_TIMEZONE="America/Los_Angeles" PW_DEFAULT_ADMIN_THEME=AdminThemeUikit PW_INSTALLED=1580675413 PW_HTTP_HOSTS = "domain.com,www.domain.com" # Some API that is used EXTERNAL_SERVICE_API_URL="https://api.someservice.loc/v2" # Development EXTERNAL_SERVICE_API_KEY=0d41fe1b68244f4ea51ae5e4abd24fab # Mailgun MG_KEY=key-192cde47ab73095e747ebe7556577b2d MG_DOMAIN="mg.somedomain.com" # Forecast.io FORECAST_IO_KEY=c28096383d66bcb1e2cb9ec37153f85c To take the idea further, it could be integrated with the ProcessWire API in a way that would prevent conflicts, keep .env variable naming organized, and make any value added by the developer available. Something like: <?php // An accessor method, this is probably the cleanest and resembles other frameworks $config->env('SOME_ENV_VARIABLE'); // Nested under a property acting as a namespace $config->env->SOME_ENV_VARIABLE; // On ProcessWire projects I implement some extras to easily interact with .env values without needing to access them directly. $config->envIs('production'); // boolean I haven't built a ProcessWire site without implementing this for many years and there's a great widely-used great package that provides .env values to PHP. There are also hosting providers that make environment variables/secrets manageable through their admin UI that eliminates the need for an actual file in production entirely. If ProcessWire were to implement environment variables it could look to values that may already exist and fall back to using a file. Implementation aside, if someone is able to access phpinfo() in production it's a critical issue beyond exposing config values given the totality of information dumped by that function.
    7 points
  7. Customized templates and fields Each and every content type only has the fields it really needs. Books, companies, recipes - it doesn't matter what kind of data my clients or I have to deal with. The templates and fields will reflect that. Therefore clients don't even have to learn anything in regards to creating or editing data. Super easy. It's typesafe (by my definition) We can discuss the meaning of 'typesafe' here but... I think ProcessWire is somewhat typesafe because I define each field, template, relationship, and almost everything else. I know where to expect what kind of data and know what data is allowed in which field. No guessing, no errors. (Sure this depends on your setup and your will to invest some time.) Works perfectly fine for non-developers I won't call myself a coder or programmer - I just tinker around with code and have fun. When I started using ProcessWire, getting around was super easy, and learning the fundamentals took only a day or two. From there on, it was easy-going. It's impressive what you can achieve with only some if/foreach/echo in PHP/ProcessWire. I said it a few years back and still stand behind it: ProcessWire seems to be the easiest way to learn and work with PHP. Low maintenance There are ProcessWire projects of mine that haven't been updated in the last 5+ years and still work without any PHP or security issues. The moment a project is finished and works without flaws it will do so for a very long time. There is no real need to update a project. Small footprint, high performance A ProcessWire website doesn't need that much of a big hosting package. The moment you start using Core cache functionalities or even ProCache most websites are fine and ready for an average amount of traffic. Maybe not ready for a slashdot/reddit/ProductHunt-peak but that's a totally different story. I can get so much out of ProcessWire compared to WordPress (and others I used/tested in the past). ZIP downloads and no real need for a package manager What I really love and enjoy is that you can get everything as a ZIP file, unpack those, move them around and do whatever you want or need with them. Not needing NPM or composer to get started - like in the good old days - is just perfect. In the last 1-2 years I did a lot with NPM due to 11ty and Astro, yet an old-school ZIP file has its very own charme. For comparison: Installing CraftCMS feels good and really nice, yet I absolute don't know what's happening, what is needed, and so on. It's like a blackbox. It works but I don't know why. I hate that.
    7 points
  8. Lots more Adminer updates in the last couple of weeks, but the key things are: 1) Shift-click on the DB icon links will now open Adminer in full mode rather than with the Tracy panel 2) Page, template, field, etc ID within Adminer table views are now linked - note the page title (and path) and the link to edit that page - this comes from hovering on any of the id, parent_id, templates_id, created_users_id, modified_users_id, etc. These sorts of links are present throughout including linking to modules from the "modules" table, hanna_code, pages_meta, etc. It also works for all Page Reference field's page IDs in Profields Table "field_table" tables, Profields Combo, repeater, RM fields, etc. Hopefully you'll all find this as useful as I am.
    6 points
  9. @Mustafa-Online I made nice update today on this module after not having touched it in several weeks. It's now basically complete but before I release it I still need to clean up some old code that's left over, make it work more nicely with SelectizeAll and provide similar overriding capabilities that the UIkit theme has. This module includes Bootstrap Icons and it substitutes Font Awesome icons accordingly (I went through each one and found the equivalents!). It also uses the Bootstrap navbar and dropdowns. A side-effect of this is ajax-loaded dropdown content won't work in the first release. I may backtrack on using Bootstrap dropdowns depending on if that becomes difficult. Anyway, it's looking good overall. If anyone is wondering why use this as opposed to UIkit, it may be beneficial if you are doing a lot of custom admin stuff and want to use pre-made Bootstrap styled components since the Bootstrap ecosystem is much much larger than UIkit. Also, it feels a little more fresh, although my actual reason for creating this was to for a way for me to get a deeper understanding of how admin themes work.
    6 points
  10. Just launched my first public Module 🎉 This module allows ProcessWire to send transactional emails via Brevo. Download the latest version: https://github.com/ttttim0709/WireMailBrevo Installation Copy the WireMailBrevo directory into your site/modules/ directory. In the ProcessWire admin, go to Modules > Refresh. Click "Install" next to the WireMailBrevo module. Usage Example usage: $email = $mail->new(); $email->to = 'recipient@somedomain.com'; $email->subject = 'Test #1'; $email->body = 'An example email'; $email->send(); Use of Versions: Check the Brevo dev section for more information about Message versions $email->versions([ [ 'to' => [ [ 'email' => 'bob@example.com', 'name' => 'Bob Anderson' ], [ 'email' => 'anne@example.com', 'name' => 'Anne Smith' ], ], 'subject' => 'This is my version subject line', ], [ 'to' => [ [ 'email' => 'jim@example.com', 'name' => 'Jim Stevens' ] ], 'htmlContent' => "<!DOCTYPE html><html><body><h1>Modified header!</h1><p>This is still a paragraph</p></body></html>", ], ]); Configuration After installing the module, you can configure it by going to the module settings page. You need to provide the following configuration options: Brevo API Key: Obtain this key from your Brevo account settings. Sender Email Address: The email address to be used as the sender. Sender Name: The name associated with the sender's email address.
    6 points
  11. If you're on PHP 8 and a new-ish version of Latte, you should be able to use the nullsafe operator to safely get the value: <body n:class="$page?->category?->value"> On PHP 7, you can still use the similar nullish coalesce operator, which in this case behaves identically: <body n:class="$page->category->value ?? ''">
    6 points
  12. I've been working on this site profile over the last month and we got several updates to the site profile exporter thx to @ryan that make maintaining site profiles a lot smoother. It's not 100% battle tested yet, but if anybody wants to help finding bugs and improving the docs (by asking questions, which indicates where docs are missing), here you go: https://github.com/baumrock/site-rockfrontend It's a quite interesting setup that I came up with on my latest project. I'll share more info another day, if there is interest, but for my latest RockMonthly newsletter I didn't want to hold that information back and also I wanted to have a place where people can discuss.
    5 points
  13. Thought this might be interesting for the UIkit/Tailwind users, maybe best of both worlds?? https://www.franken-ui.dev/docs/introduction
    5 points
  14. I've added a new sub-project to my PWGeeks site that turns the ephemeral activities shown in the PW forum's Online Users & All Activity pages into a live-updating, unified, timeline of events - both what users are replying to - and what they are viewing. Whilst it is not built with Processwire, it is related and was an interesting little project to build. I thought I'd post about it here in case it's of use to anyone else. You can find it here: https://activity.pwgeeks.com/ Clicking on a username drills down into their activity, but more on that later. Unlike the usual All Activity view on the forum, this integrates consumption activities (viewing stuff) with production activities (posting/replying.) Unfortunately, due to a limitation on what the forum lets non-logged in readers see, reactions to posts cannot be tracked at this time. I initially thought this might be useful just to make the ephemeral viewing activity more obvious, but I'm now hoping that it can be turned into a tool to more easily help forum moderators deal with spammers (new joiners who quickly start posting). But that's yet to be proven. If you don't wish your read/write activities to be traceable, you can login to the forum in anonymous mode. Architecture The architecture is split into a long-running ReactPHP Watcher Service, and the Index Generator code which creates the page you just viewed with the help of Caddy, PHP8.2 and PHP-FPM. It all runs on a cheap Contabo VPS. Both Caddy and the watcher process are defined as systemd services that are automatically restarted if they fail, or the box is rebooted. Pusher is used to provide a Pub-Sub channel for immediate communication of changes found by the watcher service to anyone who is viewing the index pages - allowing the index to be updated as forum activity is detected by the watcher. Pusher takes care of any fan-out needed between the Watcher Service publishing the events, and any browsers subscribed, via Pusher-JS. I used Pusher's free tier and created an "application" to get my channel and the needed credentials, which went in a .env file. I also turned on subscription counting on the channel within Pusher's dashboard to allow simple console logging of the number of clients connected to the channel at any one time. All detected activity is also stored in a local SQLite DB which allows the Index Generator to build the initial table of activity shown in your browser. Once the page is loaded, JS events take over and continue populating the table in (almost) real time as they come in from Pusher. The Watcher Service ReactPHP is used to create a long running server process, in PHP, that has run for more than 2 months at a time with rock-solid (no, that's not a bernhard module) memory use at 10MB once all the user data is loaded from the DB. I am sure this process would have run indefinitely, but I recently restarted the service to add detection of write-activities on the forum. The major Composer packages used are pusher/pusher-php-server (to publish to my app's event channel) vlucas/phpdotenv (to read the pusher credentials from an .env file) react/event-loop (to run the PHP app indefinitely) fabprot/goutte (for scraping the 2 forum pages) symfony/console (for CLI output formatting and logging) I would probably choose a different scraping library if I were to do this again, but goutte works just fine for now. The watcher only uses two public forum pages; the Online Users page, with the logged in filter applied, and the All Activity page. It is worth noting that the service has no log-in details, so sees these pages as a logged-out visitor to the forums would - which means significantly less information is available to it than to you if you view those pages when you are logged in to the forum. All Activities Page Differences When logged in, the All Activities page shows user reactions to posts (2 below). These are not available to guests, so cannot be tracked by the Watcher Service. If you have purchased Pro modules and have access to some of the VIP forums, then new posts or replies to posts in those forums are also shown (1) Guests have no access to either of these - so VIP forum activities are not tracked. The Watcher Service does not have any login credentials, so this is the view it sees... All activities listed on this page have a UTC timestamp in their HTML attributes that can be used to record the actual time of Joins, New topics and replies being posted. I don't bother recording any "user started following..." activities. Online Users (logged in) You might not be aware of this page on the forum, but it's how the Watcher Service can tell who's viewing forums & posts, creating new topics, or using the personal messaging service. If you have never visited this page on the forum, you want (1) browse, 2(Online Users) and then use the Filter-By dropdown to view logged-in users. The activities listed (3) do not have a timestamp in the HTML - so the watcher limits itself to anything that happened "Just Now" that has not yet been recorded for that user and uses the server's time() to record the event as having occurred. When users view a VIP forum or post, or visit the All Activity page, the user list page does not show what the user is viewing - it just shows their activity as a blank string (See netcarver's activity in the above screenshot.) Other Limitations The main loop of the service runs several times a minute and scrapes and de-duplicates activities from the forum. Any activity that happens on the forum between these samples are undetectable. So, if you visit a forum and then quickly click into a topic, and then back out, your activity will not be traceable. The Event Loop Using ReactPHP is conceptually quite simple, but there are a few things to keep note of. Here's the basics of the Watcher Service... <?php declare(strict_types=1); namespace Netcarver\ForumActivityMonitor; require_once 'vendor/autoload.php'; use React\EventLoop\Factory; ... use Pusher\Pusher; use Dotenv\Dotenv; require_once __DIR__ . '/.format.php'; // output formatting helpers require_once __DIR__ . '/.storage.php'; // storage class $dotenv = Dotenv::createImmutable(__DIR__); $dotenv->load(); // Create pusher publication connection $pusher = new Pusher( $_ENV['PUSHER_KEY'], ... ); $sample_period_seconds = 20; $started_ts = time(); $output = new ConsoleOutput(); $output->write("\n>>> ProcessWire Forum Activity Monitor (sampling every $sample_period_seconds seconds) <<<\n\n"); // Open the local SQLite DB for storage layer... $db = new \PDO('sqlite:path/to/database.sqlite'); $storage = new Storage($db); $loop = Factory::create(); $loop->addPeriodicTimer(1, function () use (&$storage, $started_ts, $sample_period_seconds, &$pusher, &$output) { $now = time(); $can_access_pw_forum = ($now % $sample_period_seconds === 0); $elapsed_time_seconds = $now - $started_ts; showStatusLine($output, $can_access_pw_forum, $storage->userCount(), $elapsed_time_seconds); if ($can_access_pw_forum) { $client = new Client(); try { // Scrape, dedupe & store events ... // publish events via pusher... if (!empty($event_timeline)) { ksort($event_timeline); $table = new Table($output); $table->setHeaders(['#', 'Time', 'UID', 'Username', 'Activity']); $mem_use = memory_get_usage(true); $runtime_str = formatElapsedTime($elapsed_time_seconds); $pusher_events = []; foreach ($event_timeline as $events_at_time) { foreach ($events_at_time as $event) { $uid = $event['uid']; $user_activity_count = $storage->getUserActivityCount($uid); $table->addRow([$user_activity_count, $event['time'], $uid, $event['user'], $event['activity']]); $pusher_events[$event['time']][] = [ 'uid' => $uid, 'url' => $event['url'], 'user' => $event['user'], 'act' => $event['activity'], 'mem' => $mem_use, 'uptime' => $runtime_str, 'type' => $event['type'], ]; } } $pusher->trigger('activities', 'update', $pusher_events); $table->render(); $output->write("\n"); } } catch (\Throwable $e) { $output->write("\nCaught Throwable: ".$e->getMessage()."\n\n"); } } }); $loop->run(); Note that Pusher, the storage instance, and the console are all passed into the loop closure by reference so state can be maintained between each scheduled call to the loop function. The loop closure uses a try {} catch (\Throwable) {} block to ensure it keeps running without systemd having to restart it in case of a PHP error. The catch block does occasionally run - so far if DNS resolution fails when scraping the forum. I've omitted the scraper and de-dupe code from the above as they are still a work in progress, but they populate an $event_timeline array if anything new is detected. The unified array of events (if any) is published via Pusher and each entry includes information about the Service uptime and memory usage. The Index page simply console logs this meta-data from the first event in the array of activities it receives, so you can use your browser's console to track these (along with the number of subscribers to the channel)... I made the event loop run every second, even if it's not time to sample the forum, so the CLI output can be updated regularly. This was especially useful when initially running the Watcher from the command line and I could probably drop the status updates now things are run via Systemd. Running from the CLI on the server, or tailing the log file, gives a nicely formatted table of events as they occur thanks to Symfony's console library and table helper. Systemd Integration To allow automatic restart of the watcher when the VPS is restarted, I added this service definition file to /etc/systemd/system/forumwatch.service that runs the watcher as an unprivilaged user... [Unit] Description=ReactPHP Processwire Forum Watcher [Service] ExecStart=/usr/bin/php8.2 /home/pwfw/activity.pwgeeks.com/watcher/react.php WorkingDirectory=/home/pwfw/activity.pwgeeks.com/watcher/ StandardOutput=file:/var/log/pwforumwatch.log StandardError=file:/var/log/pwforumwatch.log Restart=always User=pwfw Group=pwfw [Install] WantedBy=multi-user.target A quick sudo sytemctl enable forumwatch.service && sudo systemctl start forumwatch.service is then all that's needed to get things running. As the output is logged to /var/log/pwforumwatch.log, I also gave it a logrotate.conf file to keep things under control. The Index Generator This is a single index.php file that takes care of reading the most recent user activities from the SQLite DB and generating the table of events from it for that point in time. JS is included (pusher-js) that subscribes to the application's activity channel. Pusher's free tier allows up to 100 simultaneous connections to the event activity channel, and you can see how many users are connected via your browser's console. NB: The following feature is now behind a basic auth login. If you click on a user's name, you'll reload the page with a filter that lists only that user's activities. Here are Bernhard's as he has posted recently as I write this up. Click on the User's name or avatar (1) to be taken to their page on the forum, or click on the "Everyone" or PW logo (2) to be taken back to the all-inclusive index. Trying It Out I recommend opening the activity tracker in one browser on one side of your screen, then opening the Forum (and logging in) in another browser on the other side. As you (and anyone else) visits pages on the forum, you should see things update in the tracker. Also open up the console on the tracker page to see uptime/memory and viewing user count data as they come in. If you read this far, thank you for your time, and I hope this was of some interest or use to you.
    5 points
  15. It's long overdue for a refresh of a personal website. At least it was built on the fantastic ProcessWire! Pats website awkwardly. I gave this poor thing a makeover before it got mistaken for a museum exhibit. I hope for positive comments, but I would rather listen to what the critics say to improve. It is not yet tweaked to the details (I am on the heroin run for the proper images for service pages), but it is something I can brag about. Here is the link: Digital Marketing Montenegro
    4 points
  16. I had to do this just the other week. We had an old CMSMS site that we'd moved to PW. We had a db table with the old user names and passwords in which we stuck on the new site, and then just created our own login page which first checked to see if we had the user in PW already. If the user isn't already in PW then check the password against the old table; If it matches then use that information to add a new user to PW. The users don't really notice that anything has changed. Here's the code I used for that - you'll have to adapt to your circumstances of course but it worked well for our move. if ($input->post('ml_name')) { // when processing form (POST request), check to see if token is present // (we have a CSRF field on our login form) if ($session->CSRF->hasValidToken()) { // form submission is valid // okay to process } else { // form submission is NOT valid throw new WireException('CSRF check failed!'); } $ml_name = $sanitizer->name($input->post('ml_name')); $ml_pass = $input->post('ml_pass'); // dont allow the guest username if ($ml_name === 'guest') { throw new WireException('Invalid username'); }; // do we have this user in PW already? $u_exists = $users->get("$ml_name"); if ($u_exists->id) { // user exists // lets try and log them in try { if ($session->login($ml_name, $ml_pass)) { $session->redirect('/'); } else { $ml_feedback = 'Unknown details.'; } } catch (WireException $e) { // show some error messages: // $e->getMessage(); } } else { // ok - well do we have this user in the old CMS table? $query = $this->database->prepare("SELECT * FROM `cms_module_feusers_users` WHERE username = :login_name LIMIT 1;"); try { $query->execute(['login_name' => $ml_name]); } catch (PDOException $e) { die ('Error querying table : ' . $e->getMessage()); } // we've got a user from the old table if($query && $row=$query->fetch()) { $ml_feedback='Is in old table'; $hash=$row['password']; // handily the old auth just uses password_verify if(password_verify($ml_pass, $hash)){ // Add this user to the PW users $new_user=$users->add($ml_name); if($new_user){ $new_user->pass=$ml_pass; $new_user->addRole('members'); $new_user->save(); $log->save("new_members_site", $ml_name . " added as user"); $u = $session->login($ml_name, $ml_pass); if($u) { $session->redirect('/'); } else { die("Error in logging in. Please contact admin."); } $ml_feedback='new user added to PW'; }else{ $ml_feedback='Unable to add new user. Please let admin know'; } }else{ $ml_feedback='No matching records found.'; } }else{ $ml_feedback='No record found.'; } } } and this is the login form that the we had on our new login page - this and the above was all in a single template. <form id="ml_login_form" class="ml_login_form" method="POST"> <?php echo $session->CSRF->renderInput(); ?> <label for="ml_name">Username</label> <input id="ml_name" name="ml_name" type="text" value="<?= $ml_name ?>" required> <label for="ml_pass">Password</label> <input id="ml_pass" name="ml_pass" type="password" value="<?= $ml_pass ?>" required> <div style="display: none;"> <label for="ml_pass_bear">Password</label> <input id="ml_pass_bear" name="ml_pass_bear" type="text" value=""> </div> <button type="submit" name="ml_submit" class="butt">Submit</button> <div class="ml_feedback"><?= $ml_feedback ?></div> </form>
    4 points
  17. Hi @DrQuincy I think you can do this by hooking in to PW's login flow. Here's how I'd attempt to do this - untested - just to give you some inspiration... Create a new field on the User template for their hashed password from your old system. Write a script to populate this field where there's an email match between the old system and the new one. If the new system doesn't have users in it yet, then great, you'll be creating user records for everyone from the old system. Make sure you create a long, random, password for the initial processwire password on any new users you create and leave existing user passwords untouched. Store the hash from your system in the new field on the matching user and save any changes. You need a before hook on the session::login method. Use the name param (in $event->argument(0)) to match on emails if that's how you did it in the old system, if you have exactly one match, and this user has a non-empty value for your old password hash, use your existing pwd checking algorithm to authenticate them from the pass ($event->arguments(1)) parameter. If that works, the plaintext password they submitted to you is the correct password. Now set the PW password on that account using the plaintext password you just verified is correct AND delete the old password hash value. Now the correct password has been stored in the User's PW pass field, just exit the hook and PW should process the login as normal, or call the forceLogin method to log them in and do your own redirect. Basically, as people log in, they will auto-convert their accounts over to PWs way of doing things. Once they convert, the login process just reverts to using PWs method. Potential gotcha: more than one account in the PW system with the same email (if there are already accounts in there.) After a reasonable period has elapsed, you could then deal with seemingly dormant accounts by emailing non-converted users and asking them to login (or otherwise handle them as appropriate.) Hope that helps.
    4 points
  18. @Christophe Thanks to Christophe for suggestion the PHP Session save path, I set it to my writable folder and now it works, had to do in this in PHP Cpanel settings
    4 points
  19. Hi @HarryWilliam and welcome to the forum! E-Commerce is a huge topic and there are many ways how to do it - unfortunately or luckily ... Option 1: Payment Buttons or Links Very simple solutions are payment buttons that Platforms like Paypal offer. You can see an example here: https://www.boukal.at/work/catalogues/catalogue-do-you-also-have-pretty-motifs/ Another option would be payment links that payment providers like stripe or mollie offer: https://www.mollie.com/gb/products/payment-links Pro: Very easy to implement Con: You have to manage different buttons/links for different products on your own, place them in your markup (for example with a textformatter), keep them up do date and you have very limited possibilities for customisations (like different options etc). Option 2: SaaS Shop integration The next option would be to add one of the SaaS solutions to your PW site. One option would be to use Snipcart, which is very simple to add to your site, at least in theory: https://snipcart.com/blog/processwire-ecommerce-tutorial Pro: Easy setup, working shop out of the box, they maintain and develop the product continuously and long term (hopefully) Con: You usually pay for it per purchase and/or you have a monthly fee. Snipcart for example costs at least 20$ per month if your sales are < 1000$. That's 240$ each year. https://snipcart.com/pricing Con: You need to add products to your SaaS shop. That means you can either not manage products directly from within your ProcessWire backend or you need to develop a bridge that keeps products in sync. Con: Using a SaaS Shop means you are locked to the features that this shop provides. In PW we have this module, but I'm not sure whether it's still maintained or will see any updates in the near future. Option 3: A custom PW shop This is maybe the most advanced solution. The benefits are that you get a fully integrated solution. You can manage all your products, all your users, all your orders etc. directly from within your PW backend. You can add hooks wherever you want and you can customise everything to make it work 100% the way you or your client wants. Imagination and your skills are the limit. The con is that it will likely be a more complex setup, as you need to understand the basic workflows of E-Commerce and you need to setup everything the way you want. As far as I know we only have Padloper 2 by @kongondo at the moment. I don't know the price, though, because the shop is down at the moment. I'm developing RockCommerce at the moment and it will hopefully be released during this year. The basic version is already done and you can see it in action on my website baumrock.com where I use it to sell my commercial modules, for example RockForms. As you can see on my website it can already be used to sell single products. It comes with a checkout (live example) but it has no cart functionality at the moment. But it already has a nice Dashboard with filters and charts, at least 🙂 Also, it can already create fully automated and 100% customisable invoices directly from within PW/PHP (using RockPdf) - which is something that not all shopping carts do for you, keep that in mind when evaluating those products! Thanks to the integration into the PW system it can send 100% custom emails to your customers, where you can make sure that you comply to your local legislation (for example in Austria we need to attach terms of service to that email): In this example it's a nice looking mail because I use RockMails, which is another module in the pipeline 🙂 But as it is 100% ProcessWire you can simply send an email with some lines of code as well: $m = new WireMail(); $m->from('office@your-company.com'); $m->to('your@client.at'); $m->subject('Thank you for your oder!'); $m->body('Congrats, you are now a ProcessWire hero!'); $m->send(); So while it is not yet 100% it can already be already a great option! If you want to get notified about the release you can subscribe to my monthly developer newsletter: https://www.baumrock.com/en/rock-monthly/ I'm quite sure there are 100 more options, but I tried to give an overview 🙂
    4 points
  20. It now also works on Mac with Firefox. Some other changes are also included. The new optimized and vanilla-js QuickSave version 0.1.7 is available as a new download in the first post.
    4 points
  21. @Chris-PW Welcome to the plugin-author's club :) Would you be able to create a github account and create a repository for this? It's the next step to getting this published in the PW modules DB.
    4 points
  22. I don't know if this will help you in your case, but I will take your partner example here to demonstrate my way of doing similar things. Partners wouldn't be content on its own. I see them more like data I can re-use. Therefore I need two templates: partners (parent for all partner entries - just to group the partner pages) Fields: title Template file: none partner (single partner page with all the data, content, images) Fields: title, desc, image, www, phone, email, ... Template file: none With this setup I can create a RepeaterMatrix block called partners and would add a PageReference field there that allows multiple entries. Probably AsmSelect to be able to sort those entries. Or a selector field to look up (template=partner, sort=random, limit=5) Now whereever I want to display a set of partners I add that partners block, select my partners and it's done. There could be multiple blocks for partners in RepeaterMatrix - so the layout can change easily. partnersLogo - just the logo partnersLogoLink - the logo linked to the partners website partnersLogoDesc - partner name and the description partnersCard - full card with logo, name, description, link to website With this setup I create those partner pages somewhere in the backend and reference those. Would even work in case your partners would be pages on their own. In terms of images I stopped worrying too much. There are several ways to handle images. For example: Tags. Tag images with hero, gallery, avatar, or whatever and select images based on your needs. While this works I started using multiple image fields. It's easier (for me) and I can upload optimized images for each use case. AND I can check how many partners don't have a hero image, og:image or gallery images super easy.
    4 points
  23. Looks like the next level of Business Email Compromise just became unlocked (if it wasn't already.) Lutra Security have a nice write-up on the attack they are calling "Kobold Letters". Basically, email clients change the DOM of the email when they forward it, allowing different CSS to apply between the first recipient viewing an email, and subsequent recipients. Allows an innocent-looking "request to forward to the CFO" phishing email to the CEO to become a "request to send funds/data" when received by the CFO from the CEO. Explict verification of the request contents needed now, not just a "Did you send me a message?" question which only verifies that the message was forwarded. Something to be aware of if you work in a team or are responsible for any kind of staff training on phishing etc.
    4 points
  24. Ran into the exact same problem a few minutes ago. Verified the [home] of composer with this: composer config --list --global And finally added it to my $PATH in .bashrc export PATH="$PATH:~/.config/composer/vendor/bin"
    4 points
  25. You can probably find the executable file from /home/<username>/.config/composer/vendor/bin -folder so running /home/<username>/.config/composer/vendor/bin/wirecli should work. If you want to use it without the path you should add that path to your shell $PATH-variable.
    4 points
  26. @szabesz @AndZyk Drill down to per-user activity is now behind basic auth, and the main page table is shorter now.
    4 points
  27. Just officially released RockForms: https://www.baumrock.com/processwire/module/rockforms/ A project that has been in the making for quite some time, with its first git commit dating back to a year ago. However, the roots of RockForms stretch even deeper, originating from another repository, showcasing its rich history and evolution. RockForms has already been battle-tested in several production projects, proving its reliability and efficiency. It comes with extensive Docs with several interactive forms that you can try out yourself to see how it looks and feels: https://www.baumrock.com/en/processwire/modules/rockforms/docs/ Furthermore, Jens, known in the community as @dotnetic, has also implemented RockForms in his production environment, contributing significantly to the refinement of this release. Thank you Jens! 😎💪 We believe that RockForms will not only enhance your web development experience but also elevate the quality of your projects.
    4 points
  28. Hi guys. Check out my latest project Casa Douro Guesthouses. As the name implies, Casa Douro offers a few guesthouses in historic Porto and on the Douro Region. They came to us looking for a well built website that would fit their marketing efforts and grab direct reservations, instead of relying only on Booking.com and Airbnb. Since their channel manager (CM) software only offers a cookie-cutter website and no API, ours does all the presentation and jumps straight to the booking system when the user decides to make a reservation. As usual on my sites, pages are built using a blocks system (Profields Repeater Matrix), allowing the admin to change things up a little bit between the different units. Plus the usual WireMailSMTP, SEOMestro, and Rockfrontend because I love using Latte templates. The frontend is a mix of Tailwind + SCSS on more complicated components, and JS over Vite which allows me to keep it as vanilla as possible. We already have plans for new sections, and maybe upgrade the booking system in the future.
    4 points
  29. Just a note to say that I've added a new Page Meta section to the Request Info panel. This displays all meta entries for the page, along with links to open the entries for editing directly in Adminer. Speaking of Adminer - it was recently updated to AdminerEvo and I changed the way links from Tracy to open Adminer work - they now open the bar panel version which I believe is a much nicer experience than the standalone Adminer page. I also added links to edit the values of all fields within the Page Edit interface. If the field has multiple values, it will open Adminer showing all entries instead. This is of course optional, so you can visit the Adminer settings (now merged into Tracy's settings) to turn this off if you prefer. Please note that when you first upgrade, you will likely need to do a modules > refresh to get Adminer to load properly the first time.
    4 points
  30. Maybe I'm missing something but isn't your selector returning another page then? If you uncheck the checkbox then you have pj_kub_published='' for that page, but you are selecting =1, so your page does not match and it will find another page having =1 and that obviously has a modified date in the past?
    3 points
  31. You need to expand the parent select and navigate to the assigned parent. When you hover on that, you should see the "unselect" button.
    3 points
  32. @bernhard: Thanks to your forum thread, I finally did the switch from my previously used XAMPP development stack to WSL2/DDEV on my Windows 11 machine. Now I do all my Python, PHP and Node/Html projects within the Linux subsystem on Windows 11 using VS Code as my editor of choice. Only Windows Desktop C# projects (WinForms, WPF) are still done on the Windows side using Visual Studio 2022. Always wanted SSL certificates on my localhost. Installation was easy and my first project was set up within minutes by simply cloning and importing my MySQL dump into my ddev container. Thanks for the inspiration.
    3 points
  33. For handling datetime in Processwire, I've come to realize that the best way for me to avoid the most headache is leave EVERYTHING in UTC...the $config file, the ddev settings, etc. Then whenever I need to display times on the front end, I use a helper function I created that formats time in the Timezone of my choosing, at display time. With this method, the production server timezone or my dev environment timezone never matters. The added benefit is that you can have users save a timezone to their profile and then display times in their timezone. Any other way of dealing with timezone besides saving UTC to database has always created a mess for me later down the road. function UtcToCst($timestamp) { if(!$timestamp) return; return (new \DateTime("@" . $timestamp))->setTimezone(new \DateTimeZone("America/Chicago")); //Or use a timezone saved on your $user template. }
    3 points
  34. Checking all 3 of these will probably do what you want, but I actually never use the second two because I make use of the "Enable Guest Dumps" button from the panel selector. Enable that, do what you need to do as a guest in a private window and then reload the PW admin where you are logged in as a superuser and you'll get the dumps recorded by the guest. Another thing is to make sure you have the "Tracy Exceptions" panel enabled so that if a guest user interaction results in an exception, the bluescreen with full stack trace will be made available for easy viewing. I rely on this for all my sites with Tracy's production mode. Hope that helps.
    3 points
  35. Hey @Neue Rituale. Yes, Padloper is very much still being developed. Version 009 is due for a release this week (I have been dealing with a number of issues, including this one).
    3 points
  36. Hey, @Michael Lenaghan. The setting() function might be a fit.
    3 points
  37. Found the problem, and it was me, not ProcessWire, but... Here's why this issue might occur for anyone who encounters it: I have a module with a hook that triggers on page save (thanks to @wbmnfktr's for pointing it out). This module's function is to update its fields in the database whenever a post is liked on the page. Simple: someone likes the page, so it counts as one more like. The problem arises when both ProcessWire cache and silent page save are enabled. In this scenario, the changes aren't reflected on the front page. To ensure updates of the field are reflected on the frontpage, silent mode needs to be disabled. With silent mode off, the modified field updates whenever a post is saved from the hook. Here's the code snippet which is solving issue with modified BUT in my case making the problem when the cache is on: @$this->page->save($data['field'], array('quiet' => true)); @wbmnfktrI don't own you a beer, I own you at least a dinner man!
    3 points
  38. I haven't bothered with Github yet other than downloading a zip there. But as soon as I find time for it, I will gladly publish the module there.
    3 points
  39. Here's a copy of my blog with some reflections on building my first site with ProcessWire as someone coming from Drupal: peopleandplanet.org ProcessWire is an open source CMS Content Management System or Framework (CMS / CMF respectively) using PHP and MariaDB/MySQL. It's been around a while, humbly gathering users and sites. I spent a good while reviewing lots of open source CMSes recently as I have previously relied on Drupal 7 (excellent) and didn't like Drupal 8+ nor BackDrop (a fork of Drupal 7). WordPress? not with Gutenberg/React and all those plugin ads, thanks. Turns out I'm quite picky about CMSes! This is because my role is developer, trainer, implementer, themer, discusser of problems and solutions and dreams. I have personal relationships with my clients and am here to help. So I need a system that makes it simple for them to do as much as possible without me, while also being flexible enough for me to rapidly develop new features. So I was shopping for me and my clients, not just one of those parties. ProcessWire seemed a good balance, and once I started developing with it I was hooked. I've now launched my first site with it: peopleandplanet.org and my clients are pretty pleased with it, and I have another job in the pipeline. Templates and pages In ProcessWire, everything (even users!) is a Page, and every Page has a Template. So in Drupal-speak, it's kinda like Page = Content/Entity and Template = Content/Entity Type. A Template is configured with lots of options and describes what fields apply. Templates don't all need to be renderable, but typically are, so generally have an accompanying Template File. Key implementation decisions I made There are many ways to generate and theme page HTML in ProcessWire and I went through them all! Here's what I settled on: Use Page classes: these are PHP classes which add/bend functionality for a particular page/template. Doing pre-processing of data this way seemed the cleanest way to organise things, using inheritance to share code between similar templates. I used the excellent Latte templating engine instead of plain PHP or other options like Blade/Smarty/... Latte is context-aware which makes templates cleaner and clearer to look at and safer because it knows to escape content in one way as HTML text and another as an attribute, for example. The final clincher is that it uses the same syntax as PHP itself, so as a developer hopping between PHP and Latte, there's much less brain strain. Use PageTableNext. This is similar to Drupal's Paragraphs or Gutenberg's Blocks (ish). It allows a page to be built from slices/sections of various different templates, e.g. I have things like "text" and "text-over-image" and "animated stats" etc. These let authors make interesting pages, applying different preset styles to things, giving a good mix of creative control and theme adherence. What I liked Beyond the above features, I liked these things: Fairly unopinionated: the core is quite small and everything is a module, so when you write your own module, you have similar level of access. e.g. I was able to make a core module behave differently by using hooks rather than having to maintain a patch of a core code file. The selector API is a domain-specific query language for fetching page data that makes a lot of common things you need to do very easy and clear to read. I like readable code a lot. A lot of basic CMS features are implemented really nicely; thought has gone into them. e.g. Drupal has a redirect module that can add redirects from old URLs when you update the 'path alias' for a page - great - but ProcessWire's implementation (a) prevents you making circular redirects which is a quick way to kill a Drupal site by accident that's happened more than once, and (b) has some useful rules like let's only do this if the page has been in existence for a little while - because typically while first composing a page you may change the title quite a few times before you publish. e.g. when you save a page that has links to other pages in it, it stores the page IDs of those other pages too, and when the page is fetched it will check that the URLs exist and still match the ID, fixing them if needed. Images - have 'focus' built in as well as resizing etc. so if a crop is needed you can ensure the important content of the image is still present. Booting is flexible; it enabled me to boot ProcessWire from within Drupal7 and thereby write a migration script for a lot of content. There's a good community on the forum. A forum feels a bit old fashioned, but it's good because you can have long form discussions; it sort of doubles as a blog, and a lot of new features are announced in forum posts by Ryan and others. The Tracy debugger is mind-blowingly good, just wow. Modules - third party or core - are typically very focussed and often tiny. This is a testament to what can be achieved throught the flexible and well-designed APIs. Weekly updates on core development from both the lead developer on the blog and the community, both with RSS feeds so it's easy to keep updated. What I don't like Logging is weird and non-standard. I prefer one chronological log of well categorised events, but instead we have lots of separate files. This is a bit weird. One thing it is opinionated on is that there should be a strict hierarchy between pages and URLs. I like that level of order, but in real life, it's not what I needed. e.g. People & Planet has three main campaigns and it wanted those at /campaign-name not /campaigns/campaign-name. And we wanted news at /news/2024-03-25/title-of-news-article, but we don't want a page at /news/2024-03-25/ and we want the news index to be under an Info page in the menu. This meant I had to write a custom menu implementation to implement a different hierarchy to display what we wanted it to look (3 campaigns under a Campaigns menu, the news index under an Info menu). There was a page hook for having news articles describe their URLs with the publish date, but this took quite a bit of figuring out. Ryan Cramer leads/owns the project and other contributors are sparse. He seems like a lovely person, and I'm super grateful for his work, but there's only one of him, so this is a bit of a risk. Also, the code has no phpunit tests. Gulp. There have been various initiatives, but this sort of thing needs to come from a core team, and it's not a priority for Ryan. I love tests, they help avoid regressions, help document designed behaviour, etc. Likewise, there's a styleguide, but it's not adhered to, so... Right decision? I'm very happy with it, and it seems a great fit for my clients' needs, and they're very happy. All software has risks and I got burned twice with Drupal 8/9 - once backing out after months of development; another project that went to completion I regret and dislike administering/maintaining now. But so far, so good, and I intend to use ProcessWire for other projects (including replacing this website) very soon. Contributions I have two ProcessWire modules that are there for anyone who needs them. TagHerder provides a page at Setup » Tag Herder that lists every tag and every page tagged with that tag, and provides three options: Rename the tag; Trash the tag; Replace the tag with another. Useful for cleaning up tags that have gotten out of control! EditablePublishedDate lets you edit the published date of a page. Useful for entering historical page information or such.
    3 points
  40. Here's a small module I wrote a few years ago and was asked to share in the module repo. TextformatterImgDataUri This Textformatter checks all images in the field's markup for images under a certain size and converts those from links to data URLs, i.e. it embeds the image data itself. This can be handy when you cache whole pages and want to cut down on the number of requests. Original post with the module code:
    3 points
  41. If anyone sticks to using a version of PHP that old, I think they should also be okay with not upgrading modules.
    3 points
  42. @TomPich I wouldn't recommend caching a field value like that, as I don't think you'll get any performance benefit since the amount of work for PW to do is the same either way there. What I'd recommend doing instead is caching the resulting output, which also means only loading the repeaterConsultants when it will be used to generate that cached markup. Whatever markup you generate, use that as your cache value, for example: echo $cache->get('consultants', 'hourly', function() use($pages) { $out = ''; $consultants = $pages->get(1027)->repeaterConsultants; foreach ($consultants as $consultant) { $out .= "<li>$consultant->consultantName</li>"; } return "<ul>$out</ul>" ; });
    3 points
  43. @iank I had a look at this and it seems like it can happen if you omit homepage language segments, and are also using the PagePathHistory module. What happens is that PagePathHistory provides a shortcut for finding the page, leaving no language segments for PagePathHistory to detect the language. I don't think PagePathHistory supported multi-language URLs until 3.0.186, so maybe that's when the issue started. Though the entire URL-to-page mapping system has been rewritten since 3.0.165 via the new PagesPathFinder class, so who knows. I think maybe it's not been reported before because just about everyone is using language segments on the homepage, and I always recommend doing so, but didn't intend to require it. I've attempted a fix on the dev branch, it's just one line of code, so maybe it'll work just to modify your copy too. Do you find this fixes it there? https://github.com/processwire/processwire/commit/9e6b89cf9331fccb8f41ae0b1785e21c8c5d62f0
    3 points
  44. Just to add to this: the Move action is only removed if there is a "Children are sorted by" setting on the parent template or the parent page. Because even if there are no other allowed parents, the Move action is present to allow sorting within the existing parent so long as no fixed sorting is set.
    3 points
  45. Hello Flo, should it look like this: At the moment the icon will be displayed if a start and/or an end time has been set, but id does not take care if a change will happen in the future (publishing or unpublishing of the page)
    2 points
  46. Hi @poljpocket, sort (-iname ... ) does not work, because iname_* contain different criteria to sort the images. To have an impression of the site, here's the link: (The new sorting function is not yet implemented completely) http://www.malabu.de But ->reverse(); was the right way, it works! Thanks to you all Günter
    2 points
  47. @Jonathan Lahijani It's great you still working on this, can't wait to try it. I wish one day you make a tutorial on how to create an admin theme from scratch, as all forum's related content is outdated.
    2 points
  48. When using Cloudflare try this setting in Cloudflare's Page Rules: Does the trick for me all the time.
    2 points
  49. Great so see someone else working with ReactPHP as I'm also evaluating it for a new Project 🙂 Thx for sharing! Though I feel a little tracked now 🙈
    2 points
×
×
  • Create New...