Jump to content


Popular Content

Showing content with the highest reputation since 02/14/2019 in all areas

  1. 30 points
    We recently rebuilt the Architekturführer Köln (architectural guide Cologne) as a mobile-first JavaScript web app, powered by VueJS in the frontend and ProcessWire in the backend. Concept, design and implementation by schwarzdesign! The Architekturführer Köln is a guidebook and now a web application about architectural highlights in Cologne, Germany. It contains detailled information about around 100 objects (architectural landmarks) in Cologne. The web app offers multiple ways to search through all available objects, including: An interactive live map A list of object near the user's location Filtering based on architect, district and category Favourites saved by the user The frontend is written entirely in JavaScript, with the data coming from a ProcessWire-powered API-first backend. Frontend The app is built with the Vue framework and compiled with Webpack 4. As a learning exercise and for greater customizability we opted to not use Vue CLI, and instead wrote our own Webpack config with individually defined dependencies. The site is a SPA (Single Page Application), which means all internal links are intercepted by the Vue app and the corresponding routes (pages) are generated by the framework directly in the browser, using data retrieved from the API. It's also a PWA (Progressive Web App), the main feature of which is that you can install it to your home screen on your phone and launch it from there like a regular app. It also includes a service worker which catches requests to the API and returns cached responses when the network is not available. The Architekturführer is supposed to be taken with you on a walk through the city, and will keep working even if you are completely offline. Notable mentions from the tech stack: Vue Vue Router for the SPA functionality VueX for state management and storage / caching of the data returned through the API Leaflet (with Mapbox tiles) for the interactive maps Webpack 4 for compilation of the app into a single distributable Babel for transpilation of ES6+ SASS & PostCSS with Autoprefixer as a convenience for SASS in SFCs Google Workbox to generate the service worker instead of writing lots of boilerplate code Bootstrap 4 is barely used here, but we still included it's reboot and grid system Backend The ProcessWire backend is API-only, there are no server-side rendered templates, which means the only PHP template is the one used for the API. For this API, we used a single content type (template) with a couple of pre-defined endpoints (url segments); most importantly we built entdpoints to get a list of all objects (either including the full data, or only the data necessary to show teaser tiles), as well as individual objects and taxonomies. The API template which acts as a controller contains all the necessary switches and selectors to serve the correct response in <100 lines of code. Since we wanted some flexibility regarding the format in which different fields were transmitted over the api, we wrote a function to extract arbitrary page fields from ProcessWire pages and return them as serializable standard objects. There's also a function that takes a Pageimage object, creates multiple variants in different sizes and returns an object containing their base path and an array of variants (identified by their basename and width). We use that one to generate responsive images in the frontend. Check out the code for both functions in this gist. We used native ProcessWire data wherever possible, so as to not duplicate that work in the frontend app. For example: Page names from the backend translate to URLs in the frontend in the form of route parameters for the Vue Router Page IDs from ProcessWire are included in the API responses, we use those to identify objects across the app, for example to store the user's favourites, and as render keys for object lists Taxonomies have their own API endpoints, and objects contain their taxonomies only as IDs (in the same way ProcessWire uses Page References) Finally, the raw JSON data is cached using the cache API and this handy trick by @LostKobrakai to store raw JSON strings over the cache API. Screenshots
  2. 23 points
    This latest version of ProcessWire on the dev branch adds a new Inputfield module called “Toggle” that is an alternative to the existing Checkbox Inputfield. It also adds a nicer way to make column width adjustments to your fields when editing a template. This post covers all the details with screenshots and a short video: https://processwire.com/blog/posts/pw-3.0.139/
  3. 20 points
    In this tutorial I want to write about handling special cases and change requests by clients gracefully without introducing code bloat or degrading code quality and maintainability. I'll use a site's navigation menu as an example, as it's relatable and pretty much every site has one. I'll give some examples of real situations and change requests I encountered during projects, and describe multiple approaches to handling them. However, this post is also about the general mindset I find useful for ProcessWire development, which is more about how to handle special cases and still keep your code clean by making the special case a normal one. The problem: Special cases everywhere Since ProcessWire has a hierarchical page tree by default, as a developer you'll usually write a function or loop that iterates over all children of the homepage and displays a list of titles with links. If the site is a bit more complex, maybe you additionally loop over all grandchildren and display those in drop-down menus as well, or you even use a recursive function to iterate over an arbitrary amount of nested child pages. Something like this: function buildRecursiveMenu(Page $root): string { $markup = ['<ul class="navigation">']; foreach ($root->children() as $child) { $link = '<a class="navigation__link" href="' . $child->url() . '">' . $child->title . '</a>'; $children = $child->hasChildren() ? buildRecursiveMenu($child) : ''; $markup[] = "<li class="navigation__item">{$link}{$children}</li>"; } $markup[] = '</ul>'; return implode(PHP_EOL, $markup); } But then the requests for special cases come rolling in. For example, those are some of the requests I've gotten from clients on my projects (by the way, I'm not saying the clients were wrong or unreasonable in any of those cases - it's simply something I needed to handle in a sensible way): The homepage has the company's name as it's title, but the menu link in the navigation should just say "Home". The first page in a drop-down menu should be the top-level page containing the drop-down menu. This was requested because the first click on the top-level item opens the sub-navigation instead of navigating to that page (espcially on touch devices, such as iPads, where you don't have a hover state!), so some visitors might not realize it's a page itself. Some top-level pages should be displayed in a drop-down menu of another top-level page, but the position in the page tree can't change because of the template family settings. The menu needs to contain some special links to external URLs. For one especially long drop-down menu, the items should be sorted into categories with subheadings based on a taxonomy field. In general, my solutions to those requests fall into three categories, which I'll try to elaborate on, including their respective benefits and downsides: Checking for the special case / condition in the code and changing the output accordingly (usually with hard-coded values). Separating the navigation menu from the page tree completely and building a custom solution. Utilizing the Content Management Framework by adding fields, templates and pages that represent special states or settings. Handling it in the code This is the simplest solution, and often the first thing that comes to mind. For example, the first request (listing the homepage as "Home" instead of it's title in the navigation) can be solved by simply checking the template or ID of the current page inside the menu builder function, and changing the output accordingly: // ... $title = $child->template->name === 'home' ? 'Home' : $child->title; $link = '<a class="navigation__link" href="' . $child->url() . '">' . $title . '</a>'; // ... This is definitely the fastest solution. However, there are multiple downsides. Most notably, it's harder to maintain, as each of those special cases increases the complexity of the menu builder function, and makes it harder to change. As you add more special conditions, it becomes exponentially harder to keep changing it. This is the breeding ground for bugs. And it's much harder to read, so it takes longer for another developer to pick up where you left (or, as is often cited, for yourself in six months). Also, now we have a hard-coded value inside the template, that only someone with access to and knowledge of the template files can change. If the client want's the link to say "Homepage" instead of "Home" at some point, they won't be able to change it without the developer. Also, each special case that is hidden in the code makes it harder for the client to understand what's going on in terms of template logic - thus increasing your workload in editorial support. That said, there are definitely some times where I would go with this approach. Specifically: For smaller projects that you know won't need to scale or be maintained long-term. If you are the only developer, and/or only developers will edit the site, with no "non-technical" folk involved. For rapid prototyping ("We'll change it later") Building a custom solution My initial assumption was that the main navigation is generated based on the page tree inside ProcessWire. But of course this isn't set in stone. You can just as easily forgo using the page tree hierarchy at all, and instead build a custom menu system. For example, you could add a nested repeater where you can add pages or links on a general settings page, and generate the menu based on that. There are also modules for this approach, such as the Menu Builder by @kongondo. This approach is not the quickest, but gives the most power to the editors of your site. They have full control over which pages to show and where. However, with great power comes great responsibility, as now each change to the menu must be performed manually. For example, when a new page is added, it won't be visible in the menu automatically. This is very likely to create a disconnect between the page tree and the menu (which may be what you want, after all). You may get ghost pages that are not accessible from the homepage at all, or the client may forgot to unpublish pages they don't want to have any more after they've removed them from the menu. I would only go with this approach if there are so many special cases that there hardly is a "normal case". However, even then it might not be the best solution. The direct relationship between the page tree, the menu structure and page paths are one of the strongest features of ProcessWire in my opinion. If many pages need to be placed in special locations without much structure in regards to what templates go where, maybe you only need to loosen up the template family settings. I have built one site without any template family restrictions at all - any page of any template can go anywhere. It's definitely a different mindset, but in this case it worked well, because it allowed the client to build custom sections with different page types grouped together. It's a trade-off, as it is so often, between flexibility and workload. Weigh those options carefully before you choose this solution! Utilizing the CMF This is the middle ground between the two options above. Instead of building a completely custom solution, you keep with the basic idea of generating a hierarchical menu based on the page tree, but add fields and templates that allow the editor to adjust how and where individual pages are displayed, or to add custom content to the menu. of course, you will still write some additional code, but instead of having hard-coded values or conditions in the template, you expose those to the client, thereby making the special case one of the normal cases. The resulting code is often more resilient to changing requirements, as it can not one handle that specific case that the client requested, but also every future change request of the same type. The key is to add fields that enable the client to overwrite the default behaviour, while still having sensible defaults that don't require special attention from the editor in most cases. I'll give some more examples for this one, as I think it's usually the best option. Example 1: Menu display options This is probably the first thing you thought of for the very first change request I mentioned (displaying the homepage with a different title). Instead of hard-coding the title "Home" in the template, you add a field menu_title that will overwrite the normal title, if set. This is definitely cleaner than the hard-coded value, since it allows the client to overwrite the title of any page in the menu. I'll only say this much in terms of downsides: Maybe the menu title isn't really what the client wanted - instead, perhaps they feel limited because the title is also displayed as the headline (h1) of the page. In this case, the sensible solution would be an additional headline field that will overwrite the h1, instead of the menu_title field. Which fields are really needed is an important consideration, because you don't want to end up with too many. If each page has fields for the title, a headline, a menu title and an SEO-title, it's much more complicated than it needs to be, and you will have a hard time explaining to the client what each field is used for. Another example in this category would be an option to "Hide this page in the menu". This could be accomplished by hiding the page using the inbuilt "hidden" status as well, but if it's hidden it won't show up in other listings as well, so separating the menu display from the hidden status might be a good idea if your site has lots of page listings. Example 2: "Menu link" template One solution that is quite flexible in allowing for custom links to pages or external URLs is creating a menu-link template that can be placed anywhere in the page tree. This templates can have fields for the menu title, target page and/or external target URL. This way, you can link to another top-level page or an external service inside a drop-down menu, by placing a Menu Link page at the appropriate position. This is also a clean solution, because the navigation menu will still reflect the page tree, making the custom links visible and easily editable by the editors. A minor downside is that those templates are non-semantical in the sense that they aren't pages with content of their own. You'll need to make sure not to display them in listings or in other places, as they aren't viewable. It may also require loosening up strict family rules - for example, allowing for Menu Link pages to be placed below the news index page, which normally can only hold news pages. Example 3: Drop-down menu override This one is a more radical solution to override drop-down menus. You add a repeater field to top-level pages, similar to the one mentioned as a custom solution, where you can add multiple links to internal pages or URLs. If the repeater is empty, the drop-down menu is generated normally, based on the sub-pages in the page tree. But if the repeater contains some links, it completely overrides the drop-down menu. It's similar to the fully custom solution in that as soon as you override a sub-menu for a top-level page, you have to manually manage it in case the page structure changes. But you can make that decision for each top-level page individually, so you can leave some of them as is and only have to worry about the ones that you have overwritten. Again, this offers sensible defaults with good customizability. A downside is that the mixed approach may confuse the client, if some changes to the page tree are reflected in the drop-down menu directly, while others don't seem to have any effect (especially if you have multiple editors working on a site). Finding the right solution So how do you choose between the approaches? It depends on the client, the requirements, and on what special cases you expect and want to handle. Sometimes, a special request can be turned down by explaining how it would complicate editorial workflows or have a negative impact on SEO (for example, if you risk having some pages not accessible from the homepage at all). Also, make sure you understand the actual reason behind a change request, instead of just blindly implementing the suggestion by the client. Often, clients will suggest solutions without telling you what the actual problem is they're trying to solve. For example: In one case, I implemented the drop-down override mentioned in example three. However, what the client really wanted was to have the top-level page as the first item in the drop-down menu (see the example requests mentioned above). So they ended up overwriting every single drop-down menu, making the menu harder to maintain. In this case, it would have been better to go with a more specialized solution, such as adding a checkbox option, or even handling it in the code, since it would have been consistent throughout the menu. Another example was mentioned above: If the client requests an additional "Menu title" field, maybe what they really need is a "Headline" field. I recommend reading Articulating Design Decisions by Tom Greever; it includes some chapters on listening to the client, finding out the real reason behind a change request, and responding appropriately. It's written from a design perspective, but is applicable to development as well, and since UX becomes more important by the day, the lines between the disciplines are blurred anyway. Conclusion I realize now this reads more like a podcast (or worse, a rant) than an actual tutorial, but hopefully I got my point across. ProcessWire is at is greatest if you utilize it as a Content Management Framework, creating options and interfaces that allow for customizability while retaining usability for the client / editor. I usually try to hit a sweet spot where the editors have maximum control over the relevant aspects of their site, while requiring minimal work on their part by providing sensible defaults. Above, I listed some examples of requests I've gotten and different solutions I came up with to handle those with custom fields or templates. Though in some cases the requirements call for a custom solution or a quick hack in the template code as well! What are some of the special requests you got? How did you solve them? I'd love to get some insights and examples from you. Thanks for reading!
  4. 20 points
    I've been in Minnesota all week for a family reunion and only a few minutes at the computer every day, so I don't have a core update or anything worthwhile to write about this week. But now I'm headed back home so will be back to a regular schedule next week. Hope that you have a great weekend!
  5. 17 points
    Version 3.0.135 of ProcessWire on the dev branch focuses on adding additional layers of security via .htaccess updates, adds clarity to debug mode, and improves upon the installer— https://processwire.com/blog/posts/pw-3.0.135/
  6. 15 points
    This module is (or will be) the successor of RockGrid. It uses http://tabulator.info/ as grid library that is completely open sourced (MIT, no commercial extensions) and as far as I've seen so far at least as powerful as ag-grid, which RockGrid is using. GOALS: Support various data sources (RockFinder, JS, PHP, SQL) Supported only in PW Backend + Uikit Easy setup of new fields INSTALLATION: Just install the main module. RockMarkup is a required dependency. Please also have a look at the RockMarkup examples before jumping into RockTabulator! DEMO: STATUS: The module is early alpha and can be downloaded from github: https://github.com/BernhardBaumrock/RockTabulator It took me two weeks of rewriting RockMarkup/RockTabulator to get where I am now and I think I'm quite happy with the setup. There might be some breaking changes though in the near future. At the moment the main features that should be working properly are: Data sources: SQL, PHP, JS Sandbox for easy setup Multilang This means basically everything that is possible with Tabulator is also possible with RockTabulator. Though, there are no custom helpers/plugins yet. That's the next step and whoever is willing to help, please give me a shout 🙂 If you have any questions or ideas please let me know 🙂
  7. 14 points
    Thanks to @Macrura for the idea behind this module. Page Field Info Adds information about options in Page Reference fields. Supports InputfieldSelect and inputfields that extend InputfieldSelect: InputfieldSelect InputfieldRadios InputfieldSelectMultiple InputfieldCheckboxes InputfieldAsmSelect Requires ProcessWire >= 3.0.61 and AdminThemeUikit. Screenshots Field config Example of changes to inputfield Example of info field filled out in Page Edit Installation Install the Page Field Info module. Configuration In the Input tab of the settings for a Page Reference field... Tick the "Add info tooltips to options" checkbox to enable tooltips for the options in the field. Tooltips are not possible for Select or AsmSelect inputfield types so for those types you would want to tick the next option. Tick the "Append info about selected options" checkbox to append information about the selected options to the bottom of the inputfield. If the Page Reference field is a "multiple pages" field then the info for each selected option will be prefixed with the option label (so the user will know what option each line of info relates to). In the "Info field" dropdown select a text field that will contain information about the page, to be used in the tooltips and appended info. Of course this field should be in the template(s) of the selectable pages for the Page Reference field. Hook In most cases the "Info field" will supply the text for the tooltips and appended info, but for advanced usages you can hookPageFieldInfo::getPageInfo() to return the text. For example: $wire->addHookAfter('PageFieldInfo::getPageInfo', function(HookEvent $event) { $page = $event->arguments(0); // The page $inputfield = $event->arguments(1); // InputfieldPage $field = $event->arguments(2); // The Page Reference field $info = $event->return; // Text from the info field, if any // Set some custom text as the $event->return... }); https://github.com/Toutouwai/PageFieldInfo https://modules.processwire.com/modules/page-field-info/
  8. 13 points
    This week I was catching up with client work after traveling last week, but some of that work overlapped with a focus on WireMail modules. As a result, this week I’ve released two new WireMail modules, and also have information in this blog post on how you can configure two existing WireMail modules (WireMailSmtp and WireMailPHPMailer) to use Gmail as the SMTP sender— https://processwire.com/blog/posts/wiremail-modules-and-gmail/
  9. 10 points
    I am back again with another crazy module that might help someone. This time I am using the native Tfa class to add FIDO/U2F support. this includes Yubikeys 🙂 Sadly I cant seem to find a way to do multiple keys at once. and it seems you can only have one Tfa method at a time so not ideal but it was a fun challenge to code and maybe someone will a use for it Github: https://github.com/adamxp12/Processwire-TfaU2F ProcessWire Modules: https://modules.processwire.com/modules/tfa-u2-f/ The code is not the neatest and has limited comments but if you understand the Tfa class it should be quite easy to break apart. And here is a demo of signing in using the Yubikey as the 2nd factor
  10. 10 points
    When I installed Processwire for the first time, I noticed that Admin sessions were not lasting for a long time and it was very common to be logged out. Reading this forum I found useful information, but I could not solve this issue. I tried to modify site/config.php adding $config->sessionExpireSeconds with different values, but without success (for your awareness sessionExpireSeconds default value is 86400 seconds, ie 1 day .. so quite enough!). OK, I had no time to go deeper, so I kept doing what I had to do ... being happily logged out … time to time. Few weeks later while studying Session.php in wire/core/ I got the hint (please read the commented text) which helped me to understand how to solve it: if(ini_get('session.save_handler') == 'files') { if(ini_get('session.gc_probability') == 0) { // Some debian distros replace PHP's gc without fully implementing it, // which results in broken garbage collection if the save_path is set. // As a result, we avoid setting the save_path when this is detected. } else { ini_set("session.save_path", rtrim($this->config->paths->sessions, '/')); } } Uh! Yes, my VPS uses Debian 9 ! So I quickly did a test: echo ini_get('session.gc_probability'); echo ini_get('session.gc_divisor'); echo ini_get('session.gc_maxlifetime'); The session.gc_maxlifetime was rightly set to 86400, but session.gc_probability was 0 ! As you can easily get from Session.php routine, if probability is 0 bye bye PHP's session garbage collection and of course PW will not set the save_path. But why probability is set to 0 ?? This is due to the fact Debian/Ubuntu Linux overrides standard PHP’s session garbage collection by setting session.gc_probability to 0. As a consequence PHP’s standard session garbage collection will never run. Instead Debian/Ubuntu sets a specific Cron job for garbage collection with a duration of 1440 seconds, ie 24 minutes. This determines the max session duration. If you try to change session.gc_maxlifetime through $config->sessionExpireSeconds=86400 or ini_set('session.gc_maxlifetime', 86400) it will have no effect and sessions will be deleted at intervals of 24 minutes (or within 54 minutes). The Cron job garbage collection duration is defined at php.ini level, and runtime changes to session.gc_maxlifetime will not affect the Cron job timeout. Uh! Of course the simplest solution would be to change session.gc_maxlifetime in php.ini. However sometimes this is not possible (shared hosting). Another point to consider is that this change may affect multiple applications running on your server. Instead of modifying php.ini, personally I preferred to enable PHP's session garbage collection locally for Processwire only. Majority of the code is already written in PW Session.php, we have just to take benefit of it. Let's go step by step. Let's open site/config.php and do the following modifications (I choose to implement 14400 seconds session time, ie 4 hours): /** * Reduce inactivity timeout (original 86400 = 1 day) * How many seconds of inactivity before session expires */ $config->sessionExpireSeconds = 14400; /** * Enable Session Garbage Collection * Garbage Collection is disabled in Debian as default (probability set to zero) * Enable session garbage collection with a 1% chance of running on each session_start(); * Chance calculated as gc_probability/gc_divisor * Session path is defined inside wire/core/Session.php and points to site/assets/sessions * Thanks to this modification session now takes into account gc_maxlifetime set in config */ ini_set('session.gc_probability', 1); ini_set('session.gc_divisor', 100); Do not forget to lock site/config.php after modifying it. Here it is! We are done! After we have set gc_maxlifetime (through sessionExpireSeconds), enabled the garbage collection (gc_probability=1), and set its intervention probability (gc_divisor=100 ie 1% chance), we can rely on Session.php where the a session path (session_save_path()) is defined, and session is started (session_start()). In the development session of our browser let's look for our session cookie: if you go to site/assets/sessions you will find your corresponding session: Please note that during development phase, likely having little traffic, the number of sessions may grow and they will not be deleted. This depends from the 1% chance of deletion. If you want to test garbage collection is properly working or just to make sure sessions files are regularly cleaned during development, you can decrease gc_divisor to a lower rate(10=>10% ... 2=>50%). Do not forget to reestablish gc_divisor = 100 when moving to production. I hope some can find that tutorial useful in the future ... and may save several log outs!
  11. 10 points
    Here I'm introducing FlipFall Magazine, our multi-topic blog. It used to run on Wordpress but we recently switched it to ProcessWire. This was done the usual way we do it when converting our sites: install ProcessWire in a subfolder of the original Wordpress site under a hard-to-guess name, set up the new site there, then move content over manually, inspecting and updating each article as needed. After the ProcessWire site was ready, when we un-installed the Wordpress one and moved the ProcessWire site up one level to the document root, and... done. We used the W3CSS framework because it handles the responsive breakpoints so well (no extra work for us 😉), and it tends to default to a clean modern look. We wanted full control over the back end of the site and do customized things without having to hire a developer. As FlipFall has grown, the ability to have in-house back-end control has become even more important. Case example: Ad partners - we now can quite easily, if we wish, place different ads on different topics on this blog at a moment's notice - no need to hire a developer. Changes like this can be implemented in-house right away. The fact that we can easily incorporate this sort of thing is really nice when we're talking with potential ad partners. Helpful features of ProcessWire during this experience: The ability to export and import fields in PW was key here. We had a few other article-style sites I had done in PW recently, so having the same types of templates was very helpful. We were able to export fields and templates from our existing sites and import into FlipFall as a starting base point. No need to re-invent the wheel here! Another helpful ability of PW was when we were dealing with the categories. We built the site without category templates (but with the category page field), then added the templates in later as needed - no disruption. In other words, a template-less page field worked perfectly for the categories until we needed the template, then we just created the template. Not every feature of the site needs to be thought out in absolute full beforehand, some can be added in later as needed. Very extensible and convenient. Internal links within blog posts worked well using the page select option in the link button on the editor. When moving out of staging folder and into document root, the links auto-updated, which was nice. Creating new articles is a breeze, because under PW our fields are now customized for our needs: we created all of the fields we need and none of the ones we don't. Again, this is unlike most blogging CMS's, where they try to guess what you want (and usually get it wrong). Even for people who are solely doing blogs/article sites, I feel that ProcessWire is a much better option than most blog-specific platforms, because of PW's flexibility. The only thing I miss about Wordpress is the ability to auto-schedule post publication, which for the serious blogger is important. For example, there were some occasions on some of our other blogs where we needed to schedule posts to auto-publish at 3:01am Eastern Time to allow a time-sensitive post to come out as early in time of day as possible on publication date (3:01 am US Eastern time ensures it's that same day 12:01 am on Pacific time). We were delighted to see that ProcessWire is much, much lighter on resources of the hosting environment than the same site on Wordpress - we could see this empirically on our web hosting stats before and after the switch.
  12. 9 points
    Also, there is a counter option built into PW for all textarea fields:
  13. 8 points
    I also use different ways for implementing menus, depending on what I find appropriate. Here is a repeater based, one level customizable menu, where hiding fields on conditions makes it possible to switch between "custom" and page picker options:
  14. 8 points
    Here is another snippet that I use to get rid of unwanted table properties: // Remove unwanted attributes from tables CKEDITOR.on('dialogDefinition', function(ev) { var dialogName = ev.data.name; var dialogDefinition = ev.data.definition; if (dialogName == 'table') { var info = dialogDefinition.getContents('info'); info.remove('txtWidth'); info.remove('txtHeight'); info.remove('txtBorder'); info.remove('txtCellPad'); info.remove('txtSummary'); info.remove('txtCellSpace'); info.remove('cmbAlign'); var advanced = dialogDefinition.getContents('advanced'); advanced.remove('advStyles'); advanced.remove('advId'); //Id attribute advanced.remove('advLangDir'); // writing direction advanced.get('advCSSClasses')['default'] = 'uk-table'; //set default class for table } Put this code inside your custom config.js Best regards
  15. 7 points
    @pwired — there was a time when I'd agree with you, but there are quite a bit of options for I ❤️ PW devs out there - for flat file CMS at least. So in the end I'd say that ProcessWire and its community are better served by focusing at its one thing.
  16. 7 points
    I have no experience with this Tribe events thing, so can't speak for that, but for the bulk of the content I'd recommend skipping the database export idea and going with the built-in REST API. While the REST API has its quirks, going directly to database for exports is going to be a major pain in the a*s in comparison. Not entirely unlike exporting ProcessWire content with raw SQL... 🙂 It would be best to have a separate copy of the site at hand first, but after that it's basically as simple as installing the ACF to REST API plugin (which adds ACF field data to the REST API results) – and of course making sure that the REST API is enabled in the first place. You should be able to query and export all your pages, articles, and any custom post types with this method. Once you have the data, importing it to ProcessWire is going to be a breeze. (Note: based on some quick googling the Tribe events plugin also provides REST API support. I haven't used this, but it looks promising.) Also, in case that idea won't pan out, you can always rely on existing solutions, such as WP All Export (which provides a GUI for exporting content, including ACF data). Admittedly I haven't worked with this plugin before, but it's the companion plugin for WP All Import, the de facto standard plugin solution for complex imports. WP All Import is a bit of a monster and can feel clunky (hence devs often prefer custom imports for long-running, often-used, scheduled stuff), but for one-off cases it's a really handy tool. -- Edit: in case anyone is wondering, the WP REST API was first announced on June 17th 2013, which would be a week or so after Ryan started this thread. It didn't make it's way into the core until 2015, and even then it was for a very long time considered "a work in progress". It's been more than five years since this thread was started, so it shouldn't come as a big surprise that some things have changed 😅
  17. 7 points
    Hi all, I thought that you'd be interested to know we've now launched our third ProcessWire site, called Home of the Blizzard - The Australasian Antarctic Expedition. It's about Douglas Mawson's famous expedition of 1911-1914. As a part of the move to ProcessWire from our previous CMS it has undergone a redesign as well. It has been done completely in-house. https://mawsonshuts.antarctica.gov.au/ It uses Fancybox for the image galleries and modal menu, Plyr for video, and Modernizr (primarily to check for CSS Grid compatibility). It was actually the first PW site we started working on, but then the SCAR COMNAP and Antarctic Jobs sites became priorities so it got pushed back. It's great to have it live at last. The next PW site we launch should be our main site (http://www.antarctica.gov.au)! That's still a work in progress. 🙂
  18. 7 points
    @szabesz has to be the most generous here on the forums. Look at the given count, and that is since the end of 2015!
  19. 7 points
    Thought I'd share this quickly as it helps me get to grips with whether I'm looking at the dev site or live site when working on any client project. Dev site only has AdminOnSteroids module. I add the below to sites/templates/admin/admin.css and add that url the admin css field in the module. Currently only works with default adminTheme. #masthead{ background: rgb(153, 12, 94) !important; } #logo:before{ content: 'DEV '; color: white; margin-right: 1em; vertical-align: middle; display: inline-block; font-size: 1em; letter-spacing: 0.05em; margin: -15px 0.6em 0em 0; } Simply adds a DEV string and changes the header color so I can see I'm on Dev not live. I guess you could do the opposite if you wanted adding content: "LIVE" instead in the CSS.
  20. 6 points
    Fixed! Not completely sure why, but switching: $mail = new WireMail(); to this: $mail = $this->wire('mail')->new(); in the LoginRegister module did the trick — line 684. Now Gmail's sending my registration emails too 🙂 Gotta say, I am hugely grateful for Processwire. Ryan, and all you fantastic moderators and commenters—this is such a great place to learn, and goddamn if the sky doesn't seem to be the limit.
  21. 6 points
    One last update for the day: master branch of the module is now at 0.5.0. This includes both the rendering features mentioned above, and a slightly more polished theming feature, where each theme can declare custom markup, styles, scripts, strings, etc. More details in the README file.
  22. 6 points
    Use wire('all') Example from our production code: $factory = $modules->get('TemplateEngineFactory'); echo $factory->render('chunks/bodyCta.tpl', array_merge( (array) wire('all'), (array) [ "title" => $title, "text" => $text, "href" => $href ] ));
  23. 6 points
    With ProcessWire you don't generally want to perform your own SQL queries. It's possible, but generally I'd consider that a bad practice. If your content is stored as ProcessWire objects (basically Pages), you should always use the Selector engine for that sort of stuff. Not only does this provide the benefits of a great API (such as $pages->find('template=mailbox, owner=[some_user_field=whatever_value]') or $pages->get('parent=some-parent, name=page-name')->setAndSave('field', 'value')), there's also zero chance of accidentally running into nasty SQL injection vulnerabilities. Of course you can always create custom database tables and perform queries on them using the $database API variable (which is essentially a wrapper for PHP's own PDO class), but in such cases the content won't be editable within ProcessWire's admin, so you're missing a pretty important benefit there. Another alternative would be using RockFinder, which kind of provides the best of both worlds: easy to use syntax for queries combined with the performance of raw SQL and lightweight PHP arrays/objects. So, long story short: if you want a nice GUI and an easy-to-use API for managing your content, ProcessWire is a great choice. If you ultimately just want to use your custom database tables, write a few SQL clauses to update a few rows here and there, and there's no need for a web based interface for managing said items – then perhaps you should just build it from scratch (or use something like Laravel instead).
  24. 6 points
    Most of my clients already have some sort of webhosting and only in very few cases it needs an update in terms of more features like SSL and similar things. If they don't have webhosting I recommend a middle-sized shared hosting from trusted providers. An all-in-one package works in almost every situation. Domain + Hosting + E-Mail management = ~15 EUR/month that's it and all they need. In the past I have had root servers and VPS to host client projects. It was a nice option, additional money, and a good way to keep clients close. But as regulations and laws changed over the past years I decided to stop offering hosting services. Hosting isn't that expensive anymore and you find really good options out there. Hosting providers are there for a reason. They take the hassle away from me. If your client already has a website, take a look at their web analytics to see how much traffic there is. You can then decide which way to go and what package might be a good deal if there are performance issues. As far as I can say... a good ProcessWire site doesn't need that much of a high performance hosting. Unless you can't use ProCache even a super cheap $3 shared hosting might work well enough. ProcessWire sites with ProCache, almost no real-time-database interactions, and only a few forms have a nice small footprint.
  25. 6 points
    You don't need to migrate to a new hosting server just because the domain name for a site changes. Point the domain to your host and update $config->httpHosts in /site/config.php. Depending on the type of hosting you might need to adjust a setting there too, e.g. update the primary domain if it's a cPanel host.
  26. 6 points
    Thanks for noticing it. I usually place those overrides in /site/wire/ (for example /site/wire/JqueryMagnific) so I know which module is an override from the directories structure.
  27. 6 points
    This is all @tpr's hard work - he has just added a search/filter implementation using his awesome filterbox.js - be sure to check it out and Star it! Note that in addition to filtering, if you hit "Enter" it will load the first matched file. Thanks again Roland - this is very cool!
  28. 6 points
    @kongondo and everyone else 🙂 I have just added caching for both the Tracy and PW logs panels so now they only read a log file if it has changed since it was last cached. This should make a dramatic difference to most page loads. Do note that if you have a large log file and a new entry is added, then the load time will still be slow for that first page load when the entry is logged, so you still may want to delete log files (or use the PW log prune function) if you notice a slow load. Hope that helps everyone.
  29. 6 points
    Tiny explanation: The new directive only creates a fresh instance of a PHP class in memory, in this case a DateTime and a DateTimeZone object. The latter is initialized to 'Europe/Berlin' and used as the timezone parameter for initializing the DateTime object, which, in turn, is stored in variable $ct. Nothing affects the system.
  30. 5 points
    @wbmnfktr thanks for the tips 👍 Version so old, cache had only one folder LOL Tested in a staging environment. Upgrade of PW core - almost 150 versions from 2.3.0 to 3.0.141 - worked first time. Gotta love it! Couple of modules needed upgrading and most went smoothly. Solved issues with ProcessCustomAdminPages. Couldn't upgrade so recreated the admin pages and assigned the necessary templates Now resolving a few hiccoughs with custom template code and confident I'll get through
  31. 5 points
    Actually I came to a pretty handy solution with my co-dev! Images have information about their modification time saved within them, so using that I came up with following code: $img = $page->image; // check if image exists if($img) { // fetch cropped images' modification timestamps $tsNormal = filemtime($img->getCrop('normaali')->filename); $tsHigh = filemtime($img->getCrop('korkeampi')->filename); $tsLow = filemtime($img->getCrop('matalampi')->filename); // check if they have the same modification time => user hasn't cropped the image, so use the original if(!($tsNormal == $tsHigh && $tsNormal == $tsLow)) { // stamps are not equal => check which is highest aka last modified switch(max($tsNormal, $tsHigh, $tsLow)) { case $tsNormal: $img = $img->getCrop('normaali'); break; case $tsHigh: $img = $img->getCrop('korkeampi'); break; case $tsLow: $img = $img->getCrop('matalampi'); break; } } } Seems to work quite nicely for my purpose 🙂Thought it would be nice to share, if anybody else wants to achieve similar effect!
  32. 5 points
    You probably have "dev" in your hosts file pointing to localhost.
  33. 5 points
    The notes on the Settings tab of Page Edit are a good summary of what the statuses mean: Hidden and unpublished pages are both excluded from selectors (unless you override this) - the difference is that a hidden page is viewable if the URL is known, whereas an unpublished page cannot be viewed unless the user is logged in and has edit access for the page.
  34. 5 points
    Thanks for sharing this, EyeDentify – nice and simple 🙂 Just a little note before folks go implementing IP logging: IP addresses are considered personal data, and as such you should keep GDPR (and similar legislations) in mind. Here's SE question that covers the details related to logging IP addresses: https://law.stackexchange.com/questions/28603/how-to-satisfy-gdprs-consent-requirement-for-ip-logging. (The general consensus seems to be that you don't need to ask for permission before logging IP addresses, but there are other requirements you do need to keep in mind.)
  35. 5 points
    I wrote a script a while back to search for this kind of thing, though it doesn't spider Gitlab, PW gists or forum code yet. I've made a start at putting it online at pwgeeks.com. Currently only has about 60 items of over 1300 it has found to date - but as I massage it back to life, the directory will fill up.
  36. 5 points
    RepeaterMatrix is going to be the best choice for any type of page builder in ProcessWire (at least at this time). The recent updates to the module improve its flexibility further, such as being able to change the matrix-type of an item that's already been added to a page (this is similar to Gutenberg functionality of being able to change block-types... nice). After using RepeaterMatrix and its equivalents in other CMSes over the years (such as WordPress ACF Flexible Content field), my suggestion is you're better off NOT providing fully customizable layout functionality within your builder (that is, avoid the capability of allowing users to add things like containers, rows, columns). I've personally found that even other CMSes that do this well and are built around that concept are just too clunky. It's the nature of the beast. The better approach in my opinion is to provide a good set (5-10) of matrix-types/blocks that can instead achieve this. Once again, the recent feature addition whereby matrix types can be changed is going to help here since switching a matrix-type retains its content as long as the matrix-type you are switching to uses the same fields.
  37. 5 points
    ProFields (especially Matrix Field) and ProCache.
  38. 5 points
    @tthom_pw - thanks for the updates. Looks like this is going to be an ongoing problem, so I have separated it out into its own module: http://modules.processwire.com/modules/process-terminal/ It can be run standalone, or via the Terminal panel in Tracy. Hopefully this will help to make it available if you run your own server / VPS, but not cause problems for those Tracy users on shared hosting.
  39. 5 points
    $wire->addHookAfter('ProcessPageEdit::buildForm', function($event) { $page = $event->object->getPage(); if($page->template != 'home') return; // example if($page->isUnpublished()) return; $form = $event->arguments(0); $field = $form->getChildByName('title'); // example $field->collapsed = Inputfield::collapsedNoLocked; }); 🙂
  40. 5 points
  41. 5 points
    I'm not sure if I can blame the PHP library alone. It definitely could be one of the things that contribute to poor performance. But there are many more things going on. For example permissions is a big one. The schema needs to check the permissions for each field and subfields. So if you have lots of page-refs and fetching their subfields, it will check if the user has permission to view those fields. When you make a query inside your templates, the script already got access and don't do permission checks manually. It needs to be improved. Performance is very important. But right now I'm dealing with PHP library deprecation, because it's not maintained anymore.
  42. 5 points
    A sad day for the internet, the EU, the democracy, and so much more. I don't know anything about any #article13 discussions, protests or media coverage in Spain or anywhere else but at least here in Germany - especially in the last weeks and days - the way of communication from politicians towards protestors, their statements against protests, and media coverage that supports that copyright directive were kind of shocking. They said some really weird things like... Online-protesters were bots. Mailings were from Google (as most of those mails came from gmail.com addresses). Those on the streets were paid [from big US companies]. ... and so on Yet another bad aftertaste especially for Germany and our politicians: https://edition.faz.net/faz-edition/wirtschaft/2019-03-26/f30a5870c08cc1e1b4524c1be19d1faf/?GEPC=s3 Maybe I never fully realized that degree of misleasing information from politicians and media but now I'm not only upset but actually really p*ssed. There seems to be a last option left but I really don't know if this will ever happen but... maybe. Back to your topic: those already big platforms will do fine with that. YouTube already has its Content ID system in place and therefore can offer APIs to those who will need it in the future. At least for video material. But the main issue I have with this copyright directive is this argument "Copyright-holders and creators should earn money with their work!" which is totally fine by all means. But that directive will not help any content creator on any plattform. How could it? Independent writers, musicians, DJs, fotographers, even programmers will still have the problem to find all those pirated copies of their work. They won't earn more money. They still have to prove their copyright claims. But on the other hand publishers got some more power to bypass money from the real creators. And they got their link tax foundation they always asked for. But... there is a positive side-effect. I learned to look closer. I learned to trust less. I learned to think more than twice. I learned who might not be on my side. And I learned who to vote for the next election. Regarding Alex Jones and de-platforming: That was never a real topic here in Germany at all. At least I saw only very few articles or side-notes somewhere or at the bottom of a newsfeed. That's it. And if you find anything about it, they applaud about it because he is some kind of a bad person. This narrative or bias at Twitter, Facebook, YouTube, [name more here] and the banning of people from their platform wasn't invented by those platforms. They would be doing totally fine even with all of those now banned people. Maybe even better. It was cultivated over the last few years.
  43. 5 points
    Nobody's talking about bringing content builder stuff to the core. I guess only Ryan could)) But the request for content building is high. Content is king. And RepeaterMatrix + Hanna codes are not as user friendly as Gutenberg seem to be. SPA editing is way more pleasant than opening and saving things one after another and adding images only after 1st save. PageTable Extended showed a way true block editing could be done in PW. Frontend editing is another step that could revolutionize content editing, but I never read about any good implementation. RepeaterMatrix is cool and could be even better if it would be PageTableMatrix with a similar Inputfield))) I think we can and should find a way to solve this need in true ProcessWire way. And we have to look at competition. Gutenberg might be hard and messy for developers, but it is desirable for end users. Let's make good for both using our strong points. P.S. js page api was on the roadmap. Might be a good fit here once it's done.
  44. 5 points
    We are off to the races.. Alpha version for testing and comments now available at repo. Please note (see what I did there? 😉😎) This thing is in lazy development. Don't expect any more non-critical changes soon. Main issues for me CSS: When note sizes are small, the note titles are still large and look horrible. I'm not sure whether to truncate or reduce font size, or? Truncating long titles + long text in dashboard Note visibility can be limited by permissions, users and roles: Should we filter out system permissions? Continuing from #3, should we NOT display superuser names (in the dropdown of lists of users who can view the note, if one wants to set that) Continuing from #4, what about frontend users only; should we remove their names from the list since they can't view the backend anyway? I'm not sure how code this Continuing from #3, currently we check if a user title exists and use that value rather than name. Maybe make the field to check configurable? Notes layout? Currently, one can reply to several responses in the same note simultaneously. Is this OK? I think that's it. If I think of anything else I'll add it here. Thanks!
  45. 5 points
    There are so many ways in ProcessWire to do or save things. Depending on your background and history with ProcessWire you will find other ways or solutions. I know recipe-collectors that would only need two fields. A title and a textarea. I personally would go a more abstract way to be able to much more and other things. Template: Recipe Fields: title (text) summary/introduction (textarea) preparation (textarea) ingredients (repeater) Fields: ingredient (page reference - pages with template ingredient) amount (int or text) unit (select options - grams, cups, liters, hint) images (image) Template: Ingredient Fields: title With that setup I can easily collect all my recipes, create a list of all ingredients I need for all of my recipes. Can look for recipes with a special ingredient and so on.
  46. 5 points
    Hello, We've been using Mailgun for several years now on ProcessWire developments, using a cURL implementation within a custom site development module/template site. I'm currently rewriting that and trying to use much more of the PW API as there's been a lot of handy things added in the past while. Part of that process is to use WireMailMailgun, so I installed @Macrura's fork and then began to see what could be improved/finished off from the todos. What I've ended up doing is a partial rewrite of the module: to use more ProcessWire conventions and the coding style guide implemented a few extra features removed what I though was unnecessary code. It requires 3.0.123 and above, as it uses the htmlToText() method from WireMail, which in turn uses WireTextTools. The module is here: https://github.com/chriswthomson/WireMailMailgun Please let me know your thoughts! Cheers, Chris
  47. 4 points
    AdminBar 2.4.0 is out and adds support for the "data-adminbar-adjust" attribute. The idea here is to automatically modify (or adjust) certain CSS properties whenever the height of the Admin Bar is recalculated. Note: AdminBar already automatically adds "padding-top: [Admin Bar height in px]" to the <html> element, so this feature mainly applies to elements with "position: fixed". Assuming that Admin Bar is displayed and is 100px tall at the moment, the following markup... <div data-adminbar-adjust="top max-height"></div> ... would result in this: <div style="top: 100px; max-height: calc(100% - 100px);" data-adminbar-adjust="top max-height"></div> Thanks to @Fokke for the idea 🙂
  48. 4 points
    It was not that much necessary for sure, I put it there because the actual external link points to a partner institution and they might change their mind regrading "to be blank, or not to be blank, that is the question :)". Sure, I could change it for them should they ever change their mind, but I also wanted PW look professional as this is the first time they see/use it and the editor of the site is a former programmer... Motivations vary too, not just requirements 😄
  49. 4 points
    I told you Vivaldi a is good browser 😉 I wonder how you picked it, did you spot it on this nice tree? 😄
  50. 4 points
    Yes, I can't move it to ready as I need to change the output depending on an incoming request. Basically, I have to return {'code': 0} if I have a valid incoming request and on ready stage, I already have rendered 404 page. Maybe there is a better place for a hook? I have changed ProcessPageView::execute to ProcessPageView::ready and now everything works. Thank for the help, TracyDebugger and Logger panel!
  • Create New...