Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


schwarzdesign last won the day on July 27 2020

schwarzdesign had the most liked content!

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

schwarzdesign's Achievements

Sr. Member

Sr. Member (5/6)



  1. @benbyf We ran into an issue with image resizing not working correctly on PHP 8, in particular when using focus points: https://github.com/processwire/processwire-issues/issues/1351 I'd consider this a showstopper since image resizing is absolutely necessary for responsive images, and when we tested a site on PHP 8, focus points either didn't work at all or result in fatal exceptions altogether.
  2. Herzzentrum Bonn The Herzzentrum Bonn (Heart Center Bonn) is part of the University Hospital Bonn (UKB) and consists of the cardiology and heart chirurgy clinics. Goals for the website were a clear content structure, friendly and personal communication tailored to the different visitor groups and easier maintenance and content updates. Concept, design and implementation by schwarzdesign. www.herzzentrum-bonn.de You can read more about the challenges, concept and implementation of this project in the case study on our website (German only). Notable modules used ProFields (especially RepeaterMatrix) FormBuilder ProCache UniqueImageVariations WireMailSmtp ProcessCacheControl ProcessRedirects TracyDebugger Development insights One thing to note is the central management of staff members. To represent staff members as well as the hiarchies and different departments, we created a layered template structure: person – Represents a single person and has fields for name, title, position, portrait, contact info etc. hierarchy – Represents a hiarchy level or department in the organisational structure. Has person pages as children. people – This is a singleton template which displays all team members sorted by hierarchy level. Has hierarchy pages as children. The central staff database is also used to display people throughout the site – for example, the experts on angiology on the angiology page. Most of the editorial content is created through a RepeaterMatrix field with different section types. The section type for people contains a simple page reference field, allowing the editor to select the people to display in a given context while still being able to edit their contact info in a central place. Another interesting content type are the track records on the homepage. Those are implemented using CountUp.js and a custom IntersectionObserver script to trigger the animation as soon as the section comes into view. Finally, we built a very flexible grid section which uses CSS grid to display grids with variable contents and row/column spans (see an example here). Screenshots
  3. @Robin S Good idea, thanks! The only problem I have with that solution is that it's hardcoded and there's no indication on the backend about the modification. This makes it harder to change fields, dependencies etc later on and it might cause problems if someone works on the site who doesn't know about that hook. So while it will solve this problem well, I'm worried it will cause others down the line. Of course, the same thing can be said about my hook above which just disables the field 😅 Another thing is that I would like the fields to be visible, just not editable, like a readonly field. So removing them entirely is not an option in this case. Though I will consider this approach for similiar problems, so thanks!
  4. We're currently working on a few sites that have some users with very limited access; most importantly, some users can only edit their own profile and nothing else in the backend. We're using AdminThemeUiKit, so the CMS navbar only contains the site logo and the username for those users. The problem is that the crucial "View site" link that gets you back to the frontend is hidden in the dropdown behind the username. This isn't immediately obvious (and TBH it does feel out of place there, even when you know it's there). I'm looking for ways to make the "back to site" link more visible – and I also think this is worth a discussion for AdminThemeUiKit in general. Here's what I have considered: Ideally, clicking the logo would take you back to the frontend (currently, you just get a blank page with nothing but an 'edit profile' button). I checked the settings, but the Uikit theme only has options to open the site tree or open a side navigation. Maybe a new option to go back to the frontend could be added? Or maybe the method that gets the logo link should be made hookable, so I could retain the default behaviour for editors, but change the link for users with limited access. An additional link in the menu would also work. But the only way I can think of to add this would be a Process module that just redirects to the homepage. But that's a bit overcomplicated, and I would like to do this without the additional redirect. Of course, copying the theme and modifying it manually or inserting a prominent link with JavaScript would work, but both options are sort of hacky and require some upkeep. Is there a better way? Have you come across this problem yet, and how did you solve it? I'm looking forward to suggestions!
  5. I'm trying to disable a specific field only when it is displayed on a user's profile edit page. I have worked out the following solution, but it's shaky and I'm looking for a better approach: // disable the member type field when members edit their own profile wire()->addHookBefore('InputfieldPage::render', function (HookEvent $e) { $inputfield = $e->object; $field = $inputfield->hasField; $user = $inputfield->hasPage; $process = wire('process'); // only handle the u_type field if ($field->name !== 'u_type') return; // only for profile edits if (!($process instanceof ProcessProfile)) return; // only for regular members without additional access if ($user->isSuperuser() || $user->hasRole('editor')) return; // get the inputfield the InputfieldPage is delegated to (InputfieldRadios) $delegatedInputfield = $inputfield->getInputfield(); // get all available options $optionKeys = array_keys($inputfield->getInputfield()->getOptions()); // build an array with option id => attributes maps (this is the format expected by InputfieldRadios) $optionAttributes = array_combine( $optionKeys, array_map(fn($o) => ['disabled' => 'disabled'], $optionKeys) ); // add the attributes to the delegated inputfield to disable all options $delegatedInputfield->addOptionAttributes($optionAttributes); }); What bugs me about this: Seems overly complicated, isn't there a better way than going through the delegated inputfield and then setting the attribute manually for all options? Like a global disabled switch on InputfieldPage? The hook is dependent on the type of delegated inputfield and might break if it's switched to something else. This only sets the HTML disabled attribute, so it's easy to bypass. Of course I could add backend validation separately, but I would prefer a "unified" solution. Though for my use-case the backend validation is not that important, it's more about UX. By the way, just setting the field to hidden does not work in this case, because a couple of other fields have show_if dependencies on the field I'm trying to disable, and those don't seem to work when the field is not rendered at all. Any of you know a better approach? Thanks!
  6. @d'Hinnisdaël Thanks for the reply! I've opened issue #1322 regarding the context-dependence of $user->editable. Hopefully something will come of it. I also found issue #538, which seems to be related to this? Not sure. Regardless, the fact that $user->editable returns different results based on context is troublesome in any case, so I think you're right that this should be fixed in the core.
  7. @d'Hinnisdaël I'm having some trouble with a Collection panel that lists user accounts. Specifically, with the "edit" action, which appears disabled for everyone but superusers. I checked the source code, apparently the edit action is disabled on DashboardPanelCollection.module#L327. $page->editable apparently returns false if the $page is a user, even for users with the user-admin permission. Probably because editing users is a special case? Anyway, changing this to a hardcoded false fixes the problem in my case. Of course this isn't a general solution. Maybe the module could check for this special case and only disable the edit action if the current user doesn't have the user-admin permission? Not sure what the best solution is, does anybody know why $user->editable returns false even if the current user has the user-admin permission? Thanks!
  8. @bernhard Can you use $modules->getModule() with the noPermissionCheck option? I haven't tried it yet, but according to the documentation it should bypass permission checks. We had a similar problem with a script that updates the database dump included in the site profile for our base installation. I solved it in the same way as you, by manually setting the current user to the superuser: use Composer\Script\Event; use ProcessWire\ProcessExportProfile; use function \ProcessWire\wire; use function \ProcessWire\fuel; class SchwarzdesignDevTools { /** @var string The path of the webroot. */ public const PUBLIC_WEBROOT_DIR = __DIR__ . '/../../../public/'; /** @var string The name of the site profile. */ public const SITE_PROFILE_NAME = 'site-schwarzdesign'; /** * Script to update the database dump included in the schwarzdesign site profile. * * @param Event|null $event * @return void */ public static function createDatabaseDump(?Event $event = null): void { // bootstrap processwire require_once self::PUBLIC_WEBROOT_DIR . 'index.php'; // set the "current user" to the superuser to enable access to the site profile export module $users = wire('users'); $superuser = $users->get(wire('config')->superUserPageID); $users->setCurrentUser($superuser); // initialize the profile exporter $processExportProfile = wire('modules')->get('ProcessExportProfile'); // dump the database into the site profile $path = self::PUBLIC_WEBROOT_DIR . self::SITE_PROFILE_NAME . '/install/'; $processExportProfile->mysqldump($path); $realpath = \realpath($path); echo "Database successfully dumped to {$realpath}/install.sql!" . \PHP_EOL; } }
  9. Just an update in case anyone is looking for this, setting arbitrary 3XX response codes is now possible! As of ProcessWire 3.0.166, $session->redirect now accepts an integer as the second argument, which may be any HTTP response code in the 3XX-range. The blog post above doesn't really mention this, but you can see the change in this commit. Thanks @ryan!
  10. Time for another small update! The Architekturführer Köln is now available in the Google Play Store. One of the major problems with the Progressive Web App approach was that people don't really know about it, and they're disappointed when they don't find it in the App Store / Play Store. The new Trusted Web Activities help solve this problem. We used bubblewrap to generate an app package based on the PWA that can be distributed through the Play Store. As a result, you can now find the Architekturführer in the Play Store! Takeaways: The app is really nothing more than a tiny website launcher that opens a Chrome instance without any UI. For the end user, it's barely distinguishable from the PWA when added to the home screen. But being available in the Play Store does help with visibility (and talking to clients). The Play Store requires a lot of info, screenshots in specific formats and buttons to be clicked before publishing an app there. Also, every change needs to be manually approved, so it takes a while. Don't start the process the evening before. I used appstorescreenshot.com to generate nice looking annotated screenshots for the Play Store page. Trusted Web Activities don't exist on iOS, so for now this only works for Android, not in the App Store.
  11. @ryan In the spirit of closing up Github issues, could you take a look at issue #1133? Changing passwords on the profile page does not work if the old password is pasted instead of typed in manually. Edge-case, admittedly, but when a client stumbles upon this it's pretty disruptive. As far as I can tell it's just a jQuery event that needs to listen to paste events as well as input events, so it should be a one-line fix. Though of course I don't know the code base so well, so I might be mistaken 🙂 Same for issue #1111 about titles getting cut off in the page tree. Thanks!
  12. @Sergio Thanks! We suggested ProcessWire to the client, they were very happy with it 🙂 Though they mostly interact with custom interfaces. Thanks for the report! I checked on a Windows 10 device but can't replicate the rendering issue. The site uses Rubik, though locally installed versions of the font take precedence. Maybe you have an older version of the font installed on your Computer? I know there were a couple of issues with older versions of Rubik ...
  13. We relaunched the website of German health insurance broker KLforExpats, who provide a service that is specifically tailored for expatriates in Germany. The website includes very extensive, completely custom-built forms for data entry and multiple custom interfaces for management and handling of requests. Concept, design, branding and development by schwarzdesign. If you are moving to Germany and need health insurance, KLforExpats is the contact for you! Read on below for some technical insights. Features A beautful, streamlined website including an extensive knowledge area (Expert Corner) Custom-built forms for initial contact and data collection A central database of clients / leads An analytics dashboard that displays key performance indicators based on the lead database A client / lead template with multiple workflow-related actions Automatic generation of Trello cards for new leads using the Trello API Notable modules Dashboard TrelloWire ProFields Hanna Code ListerPro Cacheable Placeholders Cache Control Automatically link page titles Unique Image Variations Regular shoutout to Tracy Debugger Building custom forms based on ProcessWire fields The forms on the site are built from scratch, which is a lot of work but opens up a lot of fine-tuning that isn't possible with form builder modules or services. There are a couple of interesting features of the form system we built. In particular, using built-in HTML5 features for form input and constraint validation makes developing simple, cross-browser and mobile-friendly forms a breeze. The forms make heavy use of modern input types and attributes. In particular, all date fields use the date input type, which is supported in all major browsers except Safari. This way, the forms come with good accessibility out of the box. A cleaner solution than using some rickety jQuery UI datepicker. Client-side validation is pure HTML5 as well. Since each form consists of multiple steps, the validation is triggered when the user tries to go to the next step. This is easily done by iterating through the inputs in the current step and calling reportValidity on them. The browser takes care of reporting errors – no need for a popup library. We use ProcessWire's field settings to generate field labels and validation attributes (like the required flag, minimum and maximum length settings etc.). This way, changes to the fields are always kept in sync between the frontend and the backend. For server-side validation, we used an open source library (rakit/validation). We added some custom rules to integrate it with ProcessWire's CSRF protection, a honeypot spam protection, and file uploads using WireUpload. This way, validation and error reporting can be done through a uniform interface. Using custom page classes as data models New leads are represented by ProcessWire pages. We ended up writing a lot of custom functionality for those pages – for example, automatically generating a vCard based on the contact information entered in the form. We used a custom page class as a nice way to group those methods and be able to call them from anywhere. <?php namespace schwarzdesign\Page; use Processwire\Page; class ClientPage extends Page { /*** methods here */ } Since each lead is a regular page, we used the regular page template to display all the data collected for this lead as well as to provide an interface to perform lead-related actions, like create form access keys, generate PDF protocols, etc. Since we use Twig as a templating layer, we ended up with a MVC-like approach, where the PHP-template is only used to call the appropriate methods of the ClientPage based on URL parameters. You can read more on the process and the client-facing functionality on the KLforExpats project showcase on our website (in German).
  14. @Robin S Oh I see, sorry I misread your reply the first time 🙂 Enabling the textformatter is not an option for me because of the interferance with Twig. By the way I did consider turning Twig's autoescaping off and using textformatters instead, but in the end it's much easier to have Twig handle it instead of having to add the textformatter to every single field. So I'd say the issue is still valid, since there are use-cases for not wanting to use the formatter, even if they are not that common. Thanks for the workaround! I'll give that a try as well, either that or just use the proper smaller-than sign as suggested above 🙂
  15. @Jan Romero Thanks for the suggestion, I'll probably do that ^^ @Robin S Hm, curious. I have the HTML Entity Encoder turned off (because that is handled by Twig in our setup), but I'm still getting the cut-off title. I'm surprised you're getting different results. Not sure if this can be related to the textformatter, as the encoding is hard-coded inside ProcessPageListRender::___getPageLabel ...
  • Create New...