Jump to content


Popular Content

Showing content with the highest reputation since 04/19/2019 in all areas

  1. 19 points
    Quietly and without interruption this week, our whole website (and all subdomains) moved from a single static server to a load-balanced multi-server environment, giving us even more horsepower and redundancy than before— https://processwire.com/blog/posts/processwire-hosting-upgrades/
  2. 15 points
    I have sent a pull request on github for webP support in the core: https://github.com/processwire/processwire/pull/141 Explanation of its usage: I implemented two new options for the imagesizer that can be set globally in the site/config.php or can be passed within an individual options array to any size-method: $options = [ "webpAdd" => true, // boolean, if true, an additional webp variation will be created "webpQuality" => 80 // integer range 0 - 100, 100 is best ]; This creates an additional webp variation file besides the regular JPEG, PNG or GIF variations. In the template files you have two new image properties to work with the webp variation: $image->hasWebp; // boolean, true indicates that a webp variation is available for that image variation ?> <img src="<?= $image->srcWebp ?>" alt="" /> So we can create conditional markup like in this example: $image = $page->images->first()->size(300, 300); ?> <picture> <?php if($image->hasWebp) { ?> <source srcset="<?=$image->srcWebp?>" type="image/webp" /> <?php } ?> <source srcset="<?=$image->src?>" type="image/jpeg" /> <img src="<?=$image->url?>" alt="Alt Text!" /> </picture> The pull request and my test branch are based on this weeks pw dev branch. So if someone want to test it, please grab a copy, play with it and report back here. I don't know what timeline @ryan has and what parts need to be modified / rearanged, etc. Maybe the property names or the option names will be changed, but I think the main functionality will be close to that in the current test branch. ----- And here are a filesize comparision with different quality settings and with both engines, GD-Lib and IMagick: EDIT: An approach without conditional markup for webp comes from @arjen see lazyload. ...
  3. 12 points
    I've done both so far. Since we use PW for our corporate intranet, there are a number of additional databases we pull data from, which is quite straight forward (just an include that instantiates a new WireDatabasePDO and wire()s it). We have a search interface to our test report database where all the data for on-site test runs of our machines are stored, pull in infos about the processing state of lab samples and display an ajax loading tree of standard parts lists for the project engineers from the ERP. Other DBs have been converted to PW pages, like e.g. the archive for the old support ticket system. We even have a mix at some places. For our sales department, we pull the contact information for our worldwide offices from the ERP, create pages if they don't exist yet, and the department augments these pages with additional infos like contractual details that the ERP can't store without climbing through major hoops. We have a semi-live attendance list (the most visitied page by far) filled with data combined from PW's user list (synchronized from Active Directory), attendance status from the time accounting software and person info like the building/room number from the ERP, with the HTML output being generated every five minutes by a background job to ease server load a bit. We have some additional, non-PW tables in the PW database for speeding up things, like caching the listings of large directories with parts drawings, and even wrote our own CKEditor plugins to easily embed links or image tags for these files. You could say PW runs as a big "spider web" that connects all the apps in our company, with data being pulled in wherever necessary. There are a few apps where we thought about storing the content in PW but decided against it due to the sheer amount of data and the performance impact PW's normalization would bring. Right now we're at around 25k pages and a little over 100 fields in 50 templates. We use the UserGroups module and template settings to limit backend access to individual templates and keep the list of available templates short for our editors (~60 editors who never see more than 6 templates in their selection list). Our intranet was built on a different CMS in 2006 and migrated to PW a few years ago, and the possibilities we gained were simply astonishing. It's always fun to have a sales rep for one of the intranet platform solutions on site and, after listing to their spiel about the great features they offer, show them what we have and ask innocently, "How much work would it be to implement all of this?"
  4. 9 points
    Hey just bringing up as a point for discussion. I find in various areas of the admin there is quite a lot of reflowing of content and flash of unstyled content (FOUC). Examples are: the pages listing animation pushes the footer down the page every time, and this can also be seen on various pages where content doesn't load immediately (footer will fly down the page) basic pages with no fields – sit there and refresh a basic page a few times, you will see a flash of all content before tabs are created pages with lots of fields – progressive loading and rendering of different fields and groups causes lots of reflow, particularly loading wysiwyg and image fields modules eg lister-pro – loads the add new button initially on the left then it jumps to the top right as the lister loads, then columns reflow and resize as content loads in and classes are applied Whilst pw is very fast to render admin page html, to me the above makes it feel quite jarring and heavy. Generally speaking you want to aim for no reflow or FOUC whatsoever for a good user experience. I know there is a lot going on here and it is not a simple thing to manage an admin like this, but does anyone notice the same thing and have any ideas about how this can be optimised? Below are some relevant links. Minimising animations is the best place to start, although before anyone suggests it just using AdminOnSteroids to disable animations doesn't fix a lot of what I am talking about. https://developers.google.com/speed/docs/insights/browser-reflow https://gist.github.com/paulirish/5d52fb081b3570c81e3a
  5. 9 points
    Super cool, congratulations on the upgraded infrastructure. I definitely would like to read more details about how you two setup ProcessWire in that environment. That would make for a good, enterprise-y tutorial here on the page too.
  6. 8 points
    @Tom. I have downloaded all four images and what you are saying, at least how I do understand it, seems not to be completly valid. What exactly was the source for what variation, as you said without resizing? (The original is larger than the others) I found these images: The original image is 4x larger (in pixel) than the compared variations. And it only has 157k, whereas the other have 300k. The original image is from a source of 1920x1080 resized in Photoshop CC2017 to 1500x1074 px and is very strong compressed. That is NOT a useful choice for a master image! Masterimages should be saved in 100% quality, (or quality 12 in Photoshop), in every single item of a workflow chain. Once you saved with lesser quality, you damaged the image, regardless if you later on save it with better quality. When I save your original image in Photoshop with quality 12, I get a 427k image file, not 157k. Another ProTip is: work with images in 16bit colordepth all the time, best in a larger color spectrum like AdobeRGB, not sRGB, use PSD or TIFF as your local master image, and only transform from this local master image to every desired target format according these steps, respecting the chronology: - 1) resize to target dimensions - 2) transform into target color space, (AdobeRGB into sRGB, or AdobeRGB into CMYK, etc) - 3) reduce the color depth from 16 bit to 8 bit, (the last step always!) - 4) save into your target fileformat, for ProcessWire (online) master images, with the max quality in JPEG. From these (online) master images you can create very good results with the GD-Lib and with the IMagick-Lib. If you do not resize the original or only resize a very small value, you may set the sharpening property to "none". Also when using the GD-Lib, you may set the "defaultGamma" to -1. Experimenting with this two properties should be enough to render good results for all possible usecases. At least this are my experiances. Can you tell me why the original is compressed so strong? And do you have an uncompressed version too? (uncompressed means: never ever compressed in its total live workflow chain!) ------------ There definetly is a difference when using the same sharpening values with GD-Lib and IMagick. This is due to the fact that IMagick internally already uses a sharpening algorythm when resizing images, and GD-Lib completly lacks about this feature. Looking at PWs image resizing history, there first only was GD-Lib without sharpening, resulting in blurry images. Than we introduced a sharpening algorythm with four available values: none | soft | medium | strong, (defaults to soft) A long time later, we introduced the ImageMagick-Lib with all the same params available as for the GD-Lib. At this time my thinking was, when switching from GD to IMagick, one may switch from medium to soft, or from soft to none in the site/config.php file, as it is a global decision what image library to use. But a review / rework of the used algorythmvalues in the core libs is possible, so that we maybe will have nearly no differences between IMagick none and soft, but keep the currently used differences within the GD-Lib.
  7. 7 points
    @Mikie - I completely agree - the PW admin interface is full of these jarring FOUCs (it's not just the UiKit theme either). I hope Ryan will give this some serious consideration going forward.
  8. 6 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.
  9. 5 points
    @Tom. Many thanks for your feedback! And, uhm, - GD does not use the compressed jpeg for webp creation, but currently IMagick does. But this is not intended and I locally have a version that uses the uncompressed src variation for webp creation. I will finalize this and commit an update to the test branch later this evening. So the intended usage is that you can define independend quality settings for jpeg and webp, and both final variations will be created from the uncompressed variation bitimage. ["quality" => 80; "webpQuality" => 90] If you simply want to test out GD-Lib when IMagick is installed with higher priority, you can pass the param "forceEngine" with the options array to the size method: $options = [ 'forceEngine' => 'ImageSizerEngineGD', // ImageSizerEngineGD | ImageSizerEngineIMagick 'forceNew' => true, 'webpAdd' => true, 'webpQuality' => 90, 'quality' => 80, 'sharpening' => 'none' ];
  10. 4 points
    What I've done so far, is a small implementation of webp-convert. Currently without a ProcessWire specific module or something, but that's planned. Just added a file called webp-on-demand.php in the ProcessWire root directory with following content: <?php // docs https://github.com/rosell-dk/webp-convert require 'webp/webp-on-demand-1.inc'; use WebPConvert\WebPConvert; $docRoot = rtrim($_SERVER["DOCUMENT_ROOT"], '/'); $requestUriNoQS = explode('?', $_SERVER['REQUEST_URI'])[0]; $source = $docRoot . urldecode($requestUriNoQS); $destination = $source . '.webp'; // Store the converted images besides the original images (other options are available!) $options = [ // Tell where to find the webp-convert-and-serve library, which will // be dynamically loaded, if need be. //'reconvert' => true, 'require-for-conversion' => 'webp/webp-on-demand-2.inc', 'quality' => 'auto', 'max-quality' => 75, 'fail' => 'serve-original' // see https://github.com/rosell-dk/webp-on-demand/blob/master/docs/api.md for more info ]; WebPConvert::convertAndServe($source, $destination, $options); Then in the folder webp the two on-demand files from here. After that I added following to the .htaccess: <IfModule mod_rewrite.c> RewriteEngine On # Redirect images to webp-on-demand.php (if browser supports webp) RewriteCond %{HTTP_ACCEPT} image/webp RewriteCond %{REQUEST_FILENAME} -f RewriteRule ^(.*)\.(jpe?g|png)$ webp-on-demand.php [NC,L] </IfModule> AddType image/webp .webp And that's it. If the browser supports webp, all requests of .jpg and .png are redirectet to the webp-on-demand.php which desides if it needs to convert the image or serve the already converted one. A small caveat: the standard installation of Plesk has no webp support included, so on webservers with Plesk you either need to wait for their implementation or compile it yourself.
  11. 4 points
    @Robin S was just typing a reply to say I was thinking there might be quick css fixes, maybe more complicated js ones. I was hoping someone with a bit more knowledge of the theme code might know some quick ones, and lo and behold! This is good stuff thanks. Totally get Ryan doesn't monitor the forums but just wanted to see if anyone had any more knowledge of this before attempting to do so myself. Issue / requests definitely the most proactive way to move forward. @wbmnfktr its just little bits and pieces that I feel could be optimized. I am maybe noticing it right now because I am clicking around the admin a lot for a new site. Generally didnt want to bring this up as a major flaw or need for a rewrite, just hoping there might be ways to optimise this stuff. Beyond Robin's suggestions my hunch is there is also probably also some weird interplay between UIKit js and jqueryui going, but I need to dig in and have a look. Thanks all for the feedback, if anyone has any other fixes maybe PM me or post back here, at some point soon I'll put these into issues / requests.
  12. 4 points
    Frontend built in UIkit 3. Backend is a modified version of what I did for HealthCARE Express. I am using the top level pages to hold information only, so no design rows as children. Children are always sub pages. The page builder area is under a settings page that has children for things like the navigation menus, and themes. (The themes hold the page layouts, color schemes and uikit and theme components.) Here is a video showing adding an intro section to a basic page. (Basic page has an inner page heading row already added.) . Instead of adding a text item, I could have added a code item and echoed text tied to the basic page. I may also make a hook for auto creating the layout page to save that step, and add a link on the front end for adding new rows without needing to visit the backend settings area. I put menus under settings so you can design the top menus, main menu, and footer column menus from one spot, and every widget that reads them gets set at one time. You can also control if they open in the same or new windows, and add off site links this way. I just feel like depending on only hidden and non hidden root pages is not enough. Also, an incoming theme can default to reading a menu named a certain way. Menus are primarily set via selector, so you do not need to edit it them every time you add a service for example, like if you wanted to have a service menu in wordpress. So if I do a page template for a Service, there can still be a rich text box and image field for that service attached to the page template, so there is no way for someone to mess up the design just to edit, and to reduce confusion, but if you want to use the page builder to add rows, you can dig into that settings page and edit the rows for the page. I also have front end editing turned on so you can double click almost anything to edit, and added a small drop down at the top right of the page that loops through all rows on your page so you have a shortcut to edit just that row from the backend. The page builder rows are matched by path. ie. /about/ would match /settings/themes/selectedtheme/bypage/about/ and might match /settings/themes/selectedtheme/bytemplate/basic-page/ also, if the about page was a basic page template. Everything will match the sitewide folder. This type of thing lets you do things like add a call to action on a group of pages by adding that row to the template instead of the page. Or add a css file or javascript file to a group or sitewide. The layouts template holds the layout types, like per page or per template, and layout types can have children like sections, containers, grids, cells, images, text, accordions, php or html code, etc. I have also played with doing a page group layout type so you can group a few pages together and add a row or code snippet to those as well. This output method does not require php eval. I actually just start an output buffer and include. That gets added to a snippet array variable that I can sort and edit until the very end when it is time to output. The first level in the array is 8 slots that works as placeholders, and then each of those 8 slots holds the rows or code snippets for that placeholder. ie. before html, head, body-top, body-header, body-main, body-footer, body-bottom, after html are the default placements code can target. The second level also has weights. In addition to targeting a placeholder, a section will also have a priority drop down of highest, high, medium, low, lowest. That way a bottom call to action can be tied to the body-main spot as low priority, and no matter if it is added to the template, page group, page or sitewide, it will always sink to the bottom. Plugins used: Inputfield Ace Extended, MarkInPageTree, Breadcrumb Dropdowns, Prev/Next Tabs (for switch from row to row), Hanna Code The page builder has almost all of UIkit added so you can add a grid to a section and set the child width by drop downs, or you can use drop downs to set them on the child cell pages individually. The cell pages would allow you to add heading, text, images, accordions, etc. If you add a text item to a cell for example, the first tab is content for the rich text editor, and the second tab is design for things like text alignment per device. (So you can say center on mobile or left align on desktop without writing any code!) . The advanced tab holds an id over ride, extra classes box, and a javascript and css box that will minify on page save and be included into your website. This allows any item to add advanced css or js in a portable way. I will attach some screenshots! https://www.medpracticesuccess.com/
  13. 3 points
    Thanks for posting that little trick. I took some inspiration there and made a small module that does the same without AOS. Should work with Default, Reno and Uikit themes. You can enable dev mode in the module's settings or by setting $config->devMode to true in site/config.php. Text and colors can be adapted in module settings.
  14. 3 points
    Just a side note: imo such things just increase the percieved page load time and are an unnecessary complication unless the page is expected to load slowly. I would avoid it if possible, even that I have done it a few times in the past.
  15. 3 points
    $log->save('modulename', 'message to log'); will take care of it for you, putting it in /site/assets/logs/modulename.txt
  16. 3 points
    Yes, once the webp variation is created and cached, it only will be served, but the PHP engine is invoked for every image call. This makes a difference compared to simply serve a static file directly by apache on sites with lots of images, like archives. Thats why I said it is a nice solution for sites with smaller amounts of images. For example: I maintain sites with 60k+ images, that presents 100 thumbs per page and have infinite scrolling, that may result fastly in 100 to 1000 thumbs on a single page view. There it makes a difference, if apache serves 1000 thumbs from static files, or if the webserver has to invoke 1000 times the PHP engine for serving static files. And multiply this with a decend amount of simultaneous visitors of the site, I bet you too definetly want to avoid invoking the PHP engine for serving static image files.
  17. 3 points
    @Mikie, you will probably need to open separate issues for each concern in the Issues or Request repos in order for Ryan to notice - he doesn't tend to participate much in the general forums these days. In terms of which repo, I'd say that it belongs in the Issues repo if something is broken or not working as expected, and in the Request repo if it's about adding a new feature or improving something that already works. In each issue please describe exactly what the problem is and what a solution would look like. And if you are able to contribute code for a suggested fix that's great (but not essential). I have some possible fixes for some of the things you mentioned that you'd be welcome to include in any issue report if you want... The footer sits under whatever content makes up the page, so if new content is loaded into the page by AJAX or page elements change in height then it's expected that the footer will move. Are you suggesting that the footer should be sticky to the bottom of the viewport when the height of the page content is less than the viewport height? Personally I would prefer that, but it's perhaps a matter of opinion. Here is some CSS that could be used for a sticky footer: /* Sticky footer */ html { height:100%; } body { display:flex; flex-direction:column; height:100%; } #main { flex:1 0 auto; width:100%; } footer { flex-shrink:0; } This FOUC with WireTabs was much worse with the older admin themes - I hardly notice it in AdminThemeUikit but it is there. A CSS fix: /* Prevent FOUC for WireTabs content */ .WireTabs + .Inputfields > .InputfieldWrapper { display:none; } The main FOUC relating to fields that bugs me is the delay in hiding inputfields with show-if conditions. I'd rather have show-if fields hidden by default and then shown when necessary. There's an open request about that, along with a roll-your-own fix for the meantime: https://github.com/processwire/processwire-requests/issues/179 I'm not sure what sort of change you want to see with regard to CKEditor fields or image fields. Some inputfields take a moment to initialise - I'd rather see the interface as soon as possible even if parts of it need to adjust slightly after loading than have the whole interface hidden until loading is complete (not sure if that's what you're suggesting). Generally speaking the behaviour of non-core modules is up to the author of those modules. But in the case of the Lister Pro button you mentioned this is due to the way the admin theme wraps and clones "head" buttons. A CSS fix: /* Hide Lister button links at bottom when results are empty */ #ProcessListerResults:empty + .InputfieldButtonLink { display:none; }
  18. 3 points
    Hi @MilenKo, It's still rough, but feel free to read my notes on the different techniques for flexible page layouts https://docs.google.com/document/d/1peY-FUpevKgy87cKOxIVz8jwcv2-3c61zbiJr3QKO6c/edit?usp=sharing
  19. 3 points
    Thanks for the tips! Note that @adrian's Tracy Debugger has similar options – in the case that one is installed too –, just look for: Indicator type and Custom Indicator CSS in settings.
  20. 3 points
    I think it will required a complete rewrite, based on some JS "framework" magic... Sure. While adding UIkit 3 to the mix was possible, it just added another layer of complexity. The current admin is a patchwork, although a good one, but there is room for improvement as always I think. Ryan likes proven tech, so I wish he took a closer look at JsViews by Boris Moore: https://www.jsviews.com/#samples/editable/submit 6+ years of constant development without breaking changes and reinventing the wheel, in this sense similar to ProcessWire's path, so I started using it too. It took me a while to stumble upon it by accident.
  21. 3 points
    @nfil are you running a PHP version older than 7.0? It seems this shorthand syntax ("syntactical sugar") has only been added with PHP 7. line 49 is: $isTranslatable = $info['translatable'] ?? false; https://php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op https://lornajane.net/posts/2015/new-in-php-7-null-coalesce-operator
  22. 3 points
    You can do something similar for the frontend: body.dev::before { content: 'DEV'; display: block; position: fixed; bottom: 0; left: 0; color: white; background-color: red; padding: 3px; font-size: 2rem; z-index: 99999; } (If you add a body class .dev when in dev mode) similarly, you could add a few breakpoints, and display stuff like "sm", "m", "l", "xl" so you always know on which viewport you are, while debugging your frontend...
  23. 3 points
    Related: https://github.com/processwire/processwire-requests/issues/268
  24. 3 points
    I'd call it an Easter Egg sorry, couldn't resist
  25. 3 points
    You can also change settings via API: $tpl = $templates->get("location"); $tpl->noAppendTemplateFile = 1; $tpl->appendFile = ""; $tpl->save();
  26. 3 points
    @Juergen I think that a hacker will easily find other ways to determine the underlying CMS by inspecting the markup or headers (or https://builtwith.com/). But I see your point For now, you can use a hook to disable the generator tag: $wire->addHookAfter('SeoMaestro::renderMetatags', function (HookEvent $event) { $tags = $event->arguments(0); $group = $event->arguments(1); if ($group === null) { unset($tags['meta_generator']); $event->return = $tags; } }); Feel free to open a feature request on GitHub. Cheers
  27. 3 points
    @Juergen @Peter Knight There is a render() method for any "group", but in case of the robots it will only return something if at least one option (noIndex, noFollow) is checked. Your example to access the individual data is correct, you can also use the following syntax, which looks slightly nicer: $page->seo->robots->noIndex Cheers
  28. 3 points
    If you set the HC to PHP, you would have to echo your HTML of course, or concatenate and then echo it. <?php $out .= '<div class="seo-block seo-interviews">'; $out .= "<h2>{$heading}</h2>"; $out .= '<ul>'; foreach( $interviews as $one ){ $out .= "<li> // ... </li>"; } $out .= '</ul>'; $out .= '</div>'; echo $out;
  29. 3 points
    A terminal for running server commands: http://modules.processwire.com/modules/process-terminal/ https://github.com/adrianbj/ProcessTerminal NOTE: It does not support interactive commands like vi, nano, apt, etc. DO NOT attempt to use these as they may result in you needing to restart apache. This is a bash terminal that lets you quickly execute commands on a server. In addition to normal commands like: ls, cd, cat, mkdir, rm, chmod, chown, etc, you can also do mysql command line calls which is very handy if you need to add a new user, create a mysqldump etc. Note that for mysql commands you need to issue them individually - you can't simply start "mysql" and issue commands from there - each call needs to include your username and password and the command to be run, eg: mysql -u root -p mypassword -e "CREATE DATABASE newtablename"; There is also an upload and download command, eg "upload test.txt" which will spawn a file selector dialog on your machine to upload that file to your server with the given name. It also has arrow up and down for command history as well as tab autocompletion of commands and file names. This module was separated from Tracy because some shared hosts were flagging it as spam. This is because it uses system_exec to run server commands. This can certainly be dangerous, but in my opinion it is no more dangerous than the HannaCode module or the Tracy Console panel which both allow you to run system_exec. The key thing is that ProcessWire's htaccess rules prevent the shell.php file from being run directly and because this is a process module it uses PW's permissions to restrict usage to superusers.
  30. 2 points
    Inspired by this thread with a little nugget based on AOS by @benbyf to visually distinguish development systems from production ones, I wrote a small module that does the same and lets you adapt colors and text. Link to the github repo: AdminDevModeColors Version 0.0.1 is still very alpha and only tested on PW 3.0.124. Description This module lets you change the color for the top toolbar and add a small piece of text for development systems, so you are immediately you aren't working on production (and vice versa). The adaptions are made through pure CSS and applied if either the "Enable DEV mode" checkbox in the module's configuration is checked or the property $config->devMode is set to true in site/config.php. Works with Default, Reno and Uikit admin themes (though probably needs a lot of testing with different versions still). Since a screenshot says more than thousand words... Production system (unchanged): Dev system (Default admin theme): Dev system (Reno admin theme): Dev system (Uikit admin theme): Feel free to leave any feedback here and report any problems either in this thread or the github issue tracker.
  31. 2 points
    There you are The github version adds touch-enabled color pickers.
  32. 2 points
    As mentioned I am going to try to submit some issues / pull requests for this, just super busy right now and want to take some time to fully understand how Ryan has set up the admin theme first.
  33. 2 points
    @horst, it's perfect for me. I already had WebP since your code from late 2018 and use my own ImageSizer, which relies on LibVips. The Vips engine is very fast - about 5 times faster than ImageMagick. I hope WebP will make it into the core soon - many thanks for your hard work!
  34. 2 points
    The Page Hit Counter module for ProcessWire implements a simple page view counter in backend. Page views of visitors are automatically tracked on defined templates, with monitoring of multiple page views. This gives you a quick overview of how many visitors have read a news or a blog post, for example, without first having to open complex tools such as Google Analytics. This module quickly provides simple information, e.g. for editors. Or, for example, to sort certain news by most page views. For example for "Trending Topics". Works with ProCache and AdBlockers. With a lightweight tracking code of only ~320 bytes (gzipped). And no code changes necessary! In addition GDPR compliant, since no personal data or IP addresses are stored. Only session cookies are stored without information. In addition, there are some options, for example filtering IP addresses (for CronJobs) and filtering bots, spiders and crawlers. You can also configure the lifetime of the session cookies. Repeated page views are not counted during this period. It is also possible to exclude certain roles from tracking. For example, logged in editors who work on a page are not counted as page views. Sort by hits and access page views (hit value) Each trackable template has an additional field called phits. For example, you want to output all news sorted by the number of page views. // It is assumed that the template, e.g. with the name "news", has been configured for tracking. $news = $pages->find("template=news, sort=-phits"); To output the page views of a tracked page, use: echo $page->phits; Example: Tracking a page hit via API and jQuery If you want to track a template that does not represent a full page to automatically inject a tracking script, you can define allowed API templates in the module that you can track. Below is an example of how you can track a click on news tag using jQuery. This will allow you to find out which keywords are clicked the most. For example, you can sort and display a tag cloud by the number of hits. Suppose your keywords have the template "news_tag". The template "news_tag" was also configured in the Page Hit Counter Module as a trackable API template. Example PHP output of keywords / tags: // Required: the data attribute "data-pid" with the ID of the template to be tracked. echo $pages->find("template=news_tag, sort=-phits")->each("<a href='{url}' class='news_tag' data-pid='{id}'>{title}</a>"); Example Tracking Script with jQuery: /** * Required: Data attribute "data-pid" with the ID of the news tag template * Required: Send the POST request to the URL "location.pathname.replace(/\/?$/, '/') + 'phcv1'" * Required: The POST parameter "pid" with the ID of the template */ $(function(){ if($('a.news_tag').length > 0) { $('a.news_tag').each(function(){ var tPID = $(this).data("pid"); if(tPID) { $(this).on("click", function(){ $.post(location.pathname.replace(/\/?$/, '/') + 'phcv1', {pid: tPID}); }); } }); } }); So simply every click on a tag is counted. Including all checks as for automatic tracking. Like Bot Filtering, Session Lifetime, etc. Notice: Tracking with URL segments If the option "Allow URL Segments" is activated on a template, the hits are only counted if the base URL of the page is called. If you want the hit to be counted even when a segment is requested, you MUST configure the segments in the template configuration. How to do this can be found here. If you use dynamic segments, configure them as RegEx. There is currently no other option. The problem is that the Page Hit Counter hooked into the PageNotFound process. If URL segments are allowed but not defined, a 404 is never triggered. This means that the Page Hit Counter cannot be called. _______________________________________________________ Background: This module is the result of a customer requirement, where the editors are overwhelmed with analytics or no tracking tools were allowed to be used. However, a way had to be found to at least count page views in a simple form for evaluations. Furthermore, by using ProCache, a way had to be found to count views of a page without clearing the cache. _______________________________________________________ Pros Automatic Page View Tracking Lightweight tracking code, only ~320 bytes (gzipped) No code or frontend changes necessary Works with ProCache! Even if no PHP is executed on the cached page, the tracking works Works with browser AdBlockers No cache triggers (for example, ProCache) are triggered. The cache remains persistent GDPR compliant, session-based cookie only, no personal information Filtering of IPs and bots possible Exclude certain roles from tracking Ability to reset Page Views Works with all admin themes Counter database is created as write-optimized InnoDB API to track events for templates that are not viewable No dependencies on libraries, pure VanillaJS (Automatic tracking script) Works in all modern browsers Pages are sortable by hits Cons Only for ProcessWire version 3.0.80 or higher (Requires wireCount()) Only for PHP version 5.6.x or higher No support for Internet Explorer <= version 9 (Because of XMLHttpRequest()) No historical data, just simple summation (Because of GDPR) Segment URLs can only be counted if the segments are defined Planned Features / ToDos API access to hit values Since version 1.2.1 Possibility to sort the pages by hits (Request by @Zeka) Since version 1.2.0 Don't track logged in users with certain roles (Request by @wbmnfktr) Since version 1.1.0 Possibility to reset the counter for certain pages or templates (Request by @wbmnfktr) Since version 1.1.0 Better bot filter Since version 1.1.0 Disable session lifetime, don't store cookies to track every page view (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree (Request by @matjazp) Since version 1.2.1 Option to hide the counter in the page tree on certain templates Since version 1.2.1 API to track events for templates that are not viewable Since version 1.2.2 Changelog 1.2.5 Bug-Fix: When counting 404 hits, cookies are no longer set. The session lifetime is deactivated for the 404 page Enhancement: Documentation improvement regarding URL segments 1.2.4 Bug-Fix: Resetting the counters on system pages (e.g. 404) does not work (Reported by wbmnfktr) Bug-Fix: Tracking endpoint is logged as 404 if module "Jumplinks" is installed (Reported by wbmnfktr) Enhancement: Corrected few typos (Merged from Sergio #6 – THX!) 1.2.3 Bug-Fix: Tracking script triggers 404 if pages are configured without slash (#3) Reported by @maxf5 Enhancement: Reduction of the tracking script size if it's gzipped (~320 bytes) Enhancement: Documentation improvement Enhancement: Corrected few typos 1.2.2 New feature: API to track events for templates that are not viewable Enhancement: Documentation improvement 1.2.1 API access to hit values Use $page->phits Bug-Fix: No tracking on welcomepage (Reported by wbmnfktr; Thx to matjazp) Bug-Fix: Tracking script path on subfolders (Reported by matjazp) Bug-Fix: Tracking on pages with status "hidden" Enhancement: Change database engine to InnoDB for phits field Enhancement: Option to disable session lifetime set session lifetime to 0, no cookies Enhancement: Better installation check Enhancement: AJAX Request asyncron Enhancement: Reduction of the tracking script size by ~20% Enhancement: Option to hide the counter in the page tree You can output the counter with the field name "phits" Enhancement: Option to hide the counter in the page tree on certain templates Enhancement: Option for activate general IP validation Enhancement: Reduction of tracking overhead up to ~30ms Enhancement: Better bot list for detection 1.2.0 New feature: Sort pages by hits – New field phits Migrate old counter data to new field 1.1.0 New feature: Exclude tracking of certain roles New feature: Reset Page Views Better bot filter and detection 1.0.0 Initial release Notes By default, the page views are stored as INT in the database. This allows a maximum counter value of 4.2 billion views (4,294,967,295) per page. If you need more, change the type to BIGINT directly in the database. But I recommend to use Google Analytics or similar tools if you have such a large number of users. _______________________________________________________ Download GitHub: ProcessWire Page Hit Counter (Version 1.2.5) PW Module Directory: ProcessWire Page Hit Counter (Version 1.2.5) Install via ProcessWire (Classname): PageHitCounter _______________________________________________________ Update information If you have used version 1.2.1 from the DEV branch, please replace it completely with the new master version.
  35. 2 points
    @horst Thank you so much, I'm playing with this now - I'll let you know if I come across anything. Appreciate the hard work. Edit: Looking good! Edit: One thing I've noticed is let's say you set the quality of the jpeg to 50 on resize, WebP will use the resized jpeg at 50 quality. Does this mean that using also webpQuality 50 would compress it twice? @horst
  36. 2 points
    I have not used Padloper yet, but I built a custom shop lately and it's a LOT of work The problem is not the payment integration, the problem is handling all the user interactions (shopping cart, taxes, product variations etc). So it depends a lot on your scenario. If you only want to collect donations without any other features, then you might not need padloper (but then you could also just use a payment button from one of the providers)
  37. 2 points
    What about this? $wire->addHookAfter("Pages::added", function($event) { $page = $event->arguments(0); // check for page template if necessary here $page->setAndSave('check', 1); }); PS: Did you see @Robin S module?
  38. 2 points
    I wanted to create a HTML Sitemap with the same pages as the XML sitemap. Unfortunately the $pages->find() method doesn´t support the order of the page tree, so I could not use the provided function to get all pages from the XML-Sitemap in the same order as the page tree. $pages->find('seo.sitemap_include=1'); So I wrote a little recursive function to render all the pages except the ones which were not included in the XML sitemap. The pages have the same order as in the page tree. function renderSitemap($items, $depth = 0) { $separator = ''; for ($x = 0; $x <= $depth; $x++) { $separator .= '-'; } foreach ($items as $item) { if ($item->seo->sitemap->include == 1) { $subitems = $item->children(); if (count($subitems)>0) { echo '<b>'.$separator.$item->title . '</b><br />'; } else { echo $separator.$item->title . '<br />'; } $subitems = $item->children(); renderSitemap($subitems, $depth+1); } } } //OUTPUT INSIDE TEMPLATE FILE $items = $pages->get("/")->children(); echo '-'.$pages->get("/")->title.'<br />';//this is only for the homepage renderSitemap($items); This little function is not intended as a complete HTML sitemap markup generation solution. It only outputs the title of the pages (without links). It should only be a starting point for others to show you how to use SEOMaestro settings in combination with a frontend sitemap. Maybe if someone has a better solution it would be great if you post it here. Best regards This is what it looks like:
  39. 2 points
    I don't want to downplay anything here but... how often do you all see FOUC in PW admin? I just started to look closer while admin pages load/reload... but to be honest... I see only some minor reflow issues here and there but nothing that annoys me. Right now I'm working on three different systems... local (Laragon) Remote (webgo) Remote (Dreamhost) While Dreamhost is remote and kind of slow only reflow issues appear on bigger pages there once in a while. No FOUC or something similar to that. Laragon and webgo are fast and those reflow issues are gone even before I really notice them. I don't use AOS, Tracy, Lister Pro or similar modules that may cause those... FOUC issues. Nonetheless... count me in for optimizing the backend to make it even better. Tested on: PW version 3.0.123 and 3.0.130
  40. 2 points
    Does anyone have the perception the old admin is "snappier"? I'm using both and I get that feeling, could this be the reason?
  41. 2 points
    @lokomotivan @Sergio I have now experimented with many options to solve this problem. However, there is only one way, which covers both behaviors. If you don't want segments to be counted, just enable the option as the behavior is current. But if segments are to be counted as well, the segments MUST be defined in the template configuration. For dynamic segments with RegEx. For this I have inserted a passage in the readme with the link to the PW help. There is currently no other option. The problem is that the Page Hit Counter hooked into the PageNotFound process (But I also tried PageRender, etc.). If URL segments are allowed but not defined, a 404 is never triggered from Processwire. This means that the Page Hit Counter cannot be called. For the tracking of segments, so simply define the segments. I also released an update with version 1.2.5, which improves the behavior when tracking 404 errors. All infos and download as always in the first post.
  42. 2 points
    General thoughts on this... I never installed Matomo into a subfolder on a ProcessWire website. Therefore I can't tell if this works out of the box or if ProcessWire tries to protect that folder in some way. I'd suggest installing matomo somewhere else - a subdomain for example. https://matomo.domain.tld/ - would probably be the easiest way here. After that tracking should work - unless you misconfigured Matomo or block tracking with DNT or the Ghostery extension. But... there is one thing I don't understand. You are saying "place the map in the template folders" - what map?
  43. 2 points
    After doing a fresh install of MySQL 5.7 on macOS High Sierra, the installer generates a temporary password for the root user. The problem is as soon the installer is finished, the given root password is already expired. Resulting in not being able to login as root to MySQL. It took me a while of reading, fiddling around, and trying all kinds of tips and examples on how to reset the root password. The following worked for me. And in the hope it an help somebody else, and for backup purposes, I'll leave it here. Open the following folder in a Terminal window: /usr/local/mysql/bin Type in (copy + paste) the following commands, where `xxxxxxxx` is the desired root password: ./mysql -u root -p --connect-expired-password SET PASSWORD FOR 'root'@'localhost' = PASSWORD('xxxxxxxx'); UPDATE user SET authentication_string='xxxxxxxx' WHERE User='root' The last line with the UPDATE command was necessary for me to finish the process.
  44. 2 points
    If you're brave enough, you could try to clone the admin search module: /wire/modules/Process/ProcessPageSearch/ rename it and put it under site/modules/ - you would have to alter rights (the admin search requires edit-rights) and certainly some other stuff. The way I did it once, is: http://www.runningcoder.org/jquerytypeahead/ - for autosuggest / type-ahead functionality $(document).ready(function () { $.typeahead({ input: '#q', hint: true, maxItem: 20, order: "asc", cache: 'localStorage', ttl: 3600000, // 1 hour display: ["title", "vertec", "year", "project_desc_short"], source: { url: 'https://prototypes.domain.com/project-abc/autocomplete/json/' // Ajax request to get JSON from the action url }, callback: { onResult: function (node, query, result, resultCount, resultCountPerGroup) { $('#resultCountIndicator').text(resultCount + " hits"); }, onCancel: function (node, event) { $('#resultCountIndicator').text(''); }, // Redirect to url after clicking or pressing enter onClickAfter: function () { var keyword = $('#q').val(); window.open( 'https://prototypes.domain.com/project-abc/search-results/?search-type=text&keyword=' + keyword, '_blank' ); } } }); }); To optimize performance, I created a hook or cron job: Store all the searchable fields in JSON format in one special PW page. That's the autocomplete/json above in source url. This special template has URL segments enabled: <?php namespace ProcessWire; ini_set('max_execution_time', 600); // 10 minutes ini_set('memory_limit', '256M'); // update process triggered (here it's done manually - it's just a normal link in the admin dashboard) if ($input->urlSegment1 === 'update') { $selector = "parent=1041, has_parent!=2, include=all"; $matches = $pages->findMany($selector); foreach ($matches as $match) { $result = array( "title" => $match->title, "year" => $match->year, "client_name" => $match->client_name, "vertec" => $match->vertec, "project_desc_short" => htmlspecialchars_decode(strip_tags($match->project_desc_short)), ); $results[] = $result; } header("Content-type: text/html; charset=UTF-8"); echo "<p>New autocomplete JSON is being generated...</p>"; $content = json_encode($results); $page->setOutputFormatting(false); $page->autocomplete_json = json_encode($results); $page->save(); $resCount = count($results); $url = $page->url . "json"; echo "<p>et puis voilà: $resCount projects found in <a href='$url' target='_blank'>JSON</a></p>"; } // just output the generated JSON to the frontend (JS) if ($input->urlSegment1 === 'json') { header("Content-type: application/json; charset=UTF-8"); echo $page->autocomplete_json; } In other words, I generate a JSON that holds all the infos I need. I only query PW directly, when something has been updated. The fullscreen thingy you mention is just plain CSS, I guess.
  45. 2 points
    $res = pages(1067)->files->sort("filename"); // or page()->files->sort("filename") btw: this syntax assumes you have enabled functions API in site/config.php: $config->useFunctionsAPI = true; otherwise you'd just use $page->files->sort("filename");
  46. 2 points
    Hi @horst, thank you for your fast implementation! Looks good on my end. However, I had to remove the creation of "hn_basic" (I think it's not intended to be there, is it?). Thank you and have a nice weekend
  47. 2 points
    You could try using a PHP hannacode with: ?> <html>test</html> <?php
  48. 2 points
    If each FAQ item belongs to one treatment only, I would use a Repeater instead of a page reference, so that the questions and answers can be edited in one place, on the same page where you edit the treatment itself. The repeater field is bundled in the core, but isn't active by default (go to Modules -> Core to install it). In this case, you would create a Repeater field faq containing two text fields question and answer (for example). Then you can loop over the repeater items in your frontend template and display them: foreach ($page->faq as $faq_item) { echo "<details><summary>{$faq_item->question}</summary>{$faq_item->answer}</details>"; }
  49. 1 point
    Checking for empty value is usually enough $emptyPages = $pages->find("myField=''") // note the empty string with single quotes $filledPages = $pages->find("myField!=''")
  50. 1 point
    Is there a place for CKEditor and processwire implementation, always seem to have to hunt around the forums to create workable edits to CKeditor in PW.
  • Create New...