Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 01/14/2019 in all areas

  1. 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: Reset counter per API $modules->get("PageHitCounter")->resetPageViews("template=whatever", false); 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. New since 2.0.0: Ignore URL segments If a template has URL segments configured, each hit on a different segment is counted as a new hit. Enable "Ignore URL segments" so that dynamic segments are not counted individually on the base template / page. New since 2.0.0: Use cookieless tracking (Experimental) Enable this option to not use individual cookies for tracking or if you have many different pages you want to track. The limit for cookies is 50 per domain for all cookies on the page. If the option is enabled, PHP session storage is used. Downside: you can't set the lifetime higher than configured in your PHP.ini and the session will be terminated as soon as the browser is closed. Upgrade note for 2.0.0 from previous versions! Version 2.0.0 requires an update in the database schema, so that additionally the date of the last access / hit on the page can be displayed ($page->lastPageHit). To make this possible, you have to do the update via the upgrade module, upload the ZIP itself and do an update directly via the backend AND DO A MODULE REFRESH DIRECTLY AFTER UPLOAD/UPDATE. If you do not do this, you will get an error that a column is missing in the database table. _______________________________________________________ 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 Cookieless tracking Since version 2.0.0 Show last hit Since version 2.0.0 Ignore URL segments (Request by @bernhard) Since version 2.0.0 Add hookable method after pageview was tracked (Request by @bernhard) Since version 2.0.0 Changelog 2.0.0 Feature request: Add hookable method after pageview was tracked (___pageViewTracked($pageID)) (Requested by @bernhard) Feature request: Ignore URL segments option (Requested by @bernhard) New: Cookieless tracking New: Show date of last hit Update: Botlist Enhancement: Documentation improvement 1.2.7 Feature request: make buildPageListHitCounter-Function public (Requested by @bernhard) 1.2.6 Bug-Fix: Set the counter of a cloned page to 0 Enhancement: The function for resetting counters is now available in the module as a public function to reset counters via own scripts on the API side (Request by @VeiJari) Enhancement: Documentation improvement API reset 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 2.0.0) PW Module Directory: ProcessWire Page Hit Counter (Version 2.0.0) 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. Old stable version Download GitHub: ProcessWire Page Hit Counter (Version 1.2.7)
    7 points
  2. In the template context, how can $page be any page unless you have overridden it, which we always discourage. Otherwise, $page is always the current page. I do understand that page() can't be overridden like $page can, so maybe going forward the functions API should be the recommended approach, but we are going to confuse the hell out of beginners if homepage examples show both approaches. But the save() example won't work as is and will confuse the user to see an error about outputformatting which they will not understand anything about yet. We have setAndSave() - why not use that example? Same goes for my observation about the image example and the issue with the need for first() on the site profiles which I think mostly come with "images" fields, rather than an "image" field. As a new user to a system all it often takes is one unexpected error early on to send them packing - I know I have done that myself. Sorry to be so blunt but I feel like many of us here have expresses our concerns regarding this - either through lots of likes on my posts above about it, or through their own comments. Please accept these comments in the spirit they are intended, which is to help make PW easy for beginners to fall in love with.
    7 points
  3. How about a new favicon of the ProcessWire logo instead of being lost in the clouds? I attached two 512x512 PNG files (PNGs can be used for Favicons by the way and all browsers support it; worth ditching .ico).
    6 points
  4. ---DEPRECATED--- Please use RockSkinUikit Just install the module and you can change the look&feel of your admin instantly by changing only one color: Download: https://modules.processwire.com/modules/rock-skin-uikit/ https://github.com/BernhardBaumrock/RockSkinUikit I'd be very happy if any of the CSS pro's could do some final improvements to the default.less theme - though I'm already very happy with the result! Happy Admin-Theming ? PS: At the moment this downloads a fork of the original AdminThemeUikit module because one method is not yet hookable. You can support this request here: https://github.com/ryancramerdesign/AdminThemeUikit/pull/77 and then I can update my module to pull the original theme from ryan.
    5 points
  5. Regarding the code samples on the home page, what if we had little tabs above each sample (or one set of tabs that switched all the samples) that allowed the visitor to switch approaches for the API variables? So for a code sample using $pages the tabs would switch between (essentially) equivalent ways of getting that variable: pages() $pages wire('pages') $this->wire('pages') If we want to promote the Functions API then that could be the default tab. There would be a brief statement explaining the reason for the different equivalent samples with a link to more detailed information. I haven't fully thought through the next part, but I wonder if this could be at least partially automated, either server-side or client-side, and applied to all code samples across the API documentation.
    5 points
  6. I personally see just a single benefit in the functions api: It's beginner friendly as it's keeping you from needing to understand how scoping and classes work in php/pw. But it brings the the big downside of relying on a global processwire instance, which is a well known code smell. It might not matter for many simple websites, but especially in modules one should never use those as it will simply prevent the module from being usable in a multi instance setup. Currently I feel like the tradeoffs and why one would use one API access method over the other just isn't very well described. Maybe something of this post could be incorporated into the current explanations:
    5 points
  7. And whats about Nette Tester:
    5 points
  8. This will be more of a quick tip, and maybe obvious to many of you, but it's a technique I found very useful when building display options. By display options I mean fields that control how parts of the page are displayed on the frontend, for example background colors, sizing, spacing and alignment of certain elements. I'll also touch on how to make those options intuitive and comfortable to use for clients. It basically involves setting up option values that can be used directly in CSS classes or as HTML elements and mapping those to CSS styling (which can be quickly generated in a couple of lines using a pre-processor such as SASS). Another important aspect is to keep the option values seperate from their corresponding labels; the former can be technical, the latter should be semantically meaningful. The field type that lends itself to this this seperation of concerns is the Selectable Options field, the following examples mostly use this field type. Note that this module is part of the ProcessWire core, but not installed by default. The following examples all come from real projects I built (though some are slightly modified to better demonstrate the principle). #1: Headline levels & semantics For a project that had many pages with long texts, I used a Repeater field to represent sections of text. Each section has a headline. Those sections may have a hierarchical order, so I used a Selectable Option field to allow setting the headline level for each section (you can guess where this is going). The definition of the options looks something like this (those are all in the format value|label, with each line representing one option, see the blogpost above for details): h2|Section headline h3|Sub-section headline Of course, the PHP code that generates the corresponding HTML can use those values : // "sections" is the repeater field foreach ($page->sections as $section) { // create an h2 / h3 tag depending on the selected option (called headline_level here) echo "<{$section->headline_level->value}>{$section->headline}</{$section->headline_level->value}>"; echo $section->body; } That's a pretty obvious example, but there are two important takeaways: I only used two options. Just because there are six levels of headlines in HTML, doesn't mean those are all relevant to the client. The less options there are, the easier it is to understand them, so only the options that are relevant should be provided. In this case, the client had provided detailed, structured documents containing his articles, so I could determine how many levels of hierarchy were actually needed. I also started at h2, since there should be only one h1 per page, so that became it's own field separate from the repeater. The two options have a label that is semantically relevant to the client. It's much easier for a client who doesn't know anything about HTML to understand the options "Section headline" and "Sub-section headline" than "h2" and "h3". Sure, it can be cleared up in the field description, but this way it goes from something that's quickly explained to something that needs no explanation at all. #2: Image width and SASS In the same project, there was also an image section; in our layout, some images spanned the entire width of the text body, others only half of it. So again, I created an options field: 50|Half width 100|Full width In this case, I expected the client to request different sizes at some point, so I wanted it to be extensible. Of course, the values could be used to generate inline styles, but that's not a very clean solution (since inline styled break the cascade, and it's not semantic as HTML should be). Instead, I used it to create a class (admittedly, this isn't strictly semantic as well): <img src="..." class="w-<?= $section->image_width->value ?>"> With pure CSS, the amount of code needed to write out those class definitions will increase linearly with the number of options. In SASS however, you only need a couple of lines: @each $width in (50, 100) { .w-#{$width}{ max-width: percentage($width/100); } } This way, if you ever need to add other options like 25% or 75%, you only need to add those numbers to the list in parenthesis and you're done. You can even put the definition of the list in a variable that's defined in a central variables.scss file. Something like this also exists in Bootstrap 4 as a utility, by the way. It also becomes easier to modifiy those all at once. For example, if you decide all images should be full-width on mobile, you only need to add that once, no need to throw around !important's or modify multiple CSS definitions (this is also where the inline styles approach would break down) : # _variables.scss $image-widths: (25, 50, 75, 100); $breakpoint-mobile: 576px; # _images.scss @import "variables"; @each $width in $image-widths { .w-#{$width}{ max-width: percentage($width/100); @media (max-width: $breakpoint-mobile) { max-width: 100%; } } } One important gotcha: It might be tempting to just use an integer field with allowed values between 10 - 100. In fact, the amount of SASS code would be identical with a @for-directive to loop throuh the numbers. But that's exactly what makes point-and-click page builders so terrible for clients: too many options. No client wants to manually set numerical values for size, position and margins for each and every element (looking at you, Visual Composer). In fact, having too many options makes it much harder to create a consistent layout. So in those cases, less is more. #3: Multiple options in one field Another example for repeatable page sections, this time for a two-column layout. The design included multiple variants regarding column-span and alignment. Using a 12-column grid, we needed a 6-6 split, a centered 5-5 split, a left-aligned 6-4 split and a right-aligned 4-6 split. I didn't want to litter the repeater items with options, so I decided to put both settings in one field (called something like Column layout) : center_6_6|6 / 6 (Centered) center_5_5|5 / 5 (Centered) left_6_4|6 / 4 (Left-aligned) right_4_6|4 / 6 (Right-aligned) As long as the value format is consistent, the individual options can be quickly extracted and applied in PHP: [$alignment, $width['left'], $width['right']] = explode('_', $section->column_layout->value); echo '<section class="row justify-content-' . $alignment . '">'; foreach (['left', 'right'] as $side) { echo '<div class="col-lg-' . $width[$side] . '">'; echo $section->get("body_{$side}"); echo '</div>'; } echo '</section>'; If you don't recognize the syntax in the first line, it's symmetric array destructuring, introduced in PHP 7.1. For older versions you can use list() instead. This example uses Bootstrap 4 grid classes and flexbox utility classes for alignment. The corresponding CSS can be quickly generated in SASS as well, check the Bootstrap source code for a pointer. Again, I'm limiting the options to what is actually needed, while keeping it extensible. With this format, I can easily add other column layouts without having to touch the code at all. #4: Sorting page elements A final example. In this case I was working on a template for reference projects that had three main content sections in the frontend: A project description, an image gallery and embedded videos (each using their own set of fields). The client requested an option to change the order in which those sections appeared on the page. Had I known this earlier, I maybe would have gone for a Repeater Matrix approach once again, but that would have required restructuring all the fields (and the corresponding code), so instead I used a Selectable Option field (labelled "Display order"). My approach is similar to the one from the last example: body_gallery_embeds|Description - Gallery - Videos body_embeds_gallery|Description - Videos - Gallery gallery_body_embeds|Gallery - Description - Videos gallery_embeds_body|Gallery - Videos - Description embeds_body_gallery|Videos - Description - Gallery embeds_gallery_body|Videos - Gallery - Description Since there are six possibilities to sort three items, this is the expected number of options. So I decided to include them all, even though some are probably never going to be used. I also tried to use a predictable order for the options (i.e. the options come in pairs, depending on what element is first). And here is the code used on the frontend: // render the template files for each section and store the result in an associative array $contents = [ 'body' => wireRenderFile('partials/_section-body.php', $page), 'gallery' => wireRenderFile('partials/_section-gallery.php', $page), 'embeds' => wireRenderFile('partials/_section-embeds.php', $page), ]; // e.g. 'gallery_body_embeds' => ['gallery', 'body', 'embeds']; $order = explode('_', $page->display_order->value); // echo the contents in the order defined by the option value foreach ($order as $item) { echo $contents[$item]; } You can see how it will be easy to add an additional section and integrate it into the existing solution. Though a fourth item would result in 4! = 24 possibilities to sort them, so at that point I'd talk to my client about which layouts they actually need ? Conclusion I always try to keep my code and the interfaces I create with ProcessWire extensible and intuitive. Those are a couple of solutions I came up with for projects at work. They are certainly not the only approach, and there is nothing super special about those examples, but I found that putting a little more effort into defining options with meaningful labels and using option values that I can use directly in my templates makes the result less verbose and more maintainable. Some or most of this tutorial may be immediately obvious to you, but if you made it this far, hopefully you got something out of it ? Feel free to share your own methods to create display options, or how you would've approached those problems differently. Thanks for reading!
    4 points
  9. I agree, but even the small sip should taste like the beer. If it tastes like anything else other than the beer, then one may not be interested in the drink. The gist is if even the simple examples don't work right out of the box or are confusing (small sip of beer tastes like....[insert non-beer drink here]), then one may go elsewhere for their beer... [insert other non-ProcessWire CMS/CMF here]). Besides, it just screams unprofessional/rough edges, etc. What @adrian said ?.
    4 points
  10. Thanks ^^ I enjoy writing tutorials, I find it helps to consolidate the experience from my projects into organized knowledge. Most of the time I come across some areas where I'm not sure how something works, so I can look it up and further my own understanding (it's also great to improve my English as a non-native speaker). I think writing this stuff down helps bring out the core ideas or the important takeaways; before I started writing this one, I hadn't really considered the part about semantic/intuitive options, I mostly realized during writing that this was the crux of the matter. So yeah, I write for my own benefit as much as everyone else's ?
    4 points
  11. Now that Github topics tags have been around for a while and most of us are using them, this is becoming a pretty useful link: https://github.com/topics/processwire?o=desc&amp;s=stars
    4 points
  12. Ryan has just modified all included site profiles to turn on the functions API by default although I am not sure why the change wasn't made in the wire/config.php file so it works for all profiles even if they come from another source - I am sure I am overlooking a good reason though. Regardless I still don't like the mix of approaches used in those examples, but that has been discussed above ?
    4 points
  13. I forgot to mention that I also use the free https://www.spectacleapp.com/ "window-size manager" application. In the case of the Finder I use it in a semi-automatic way to quickly setup a "two-pane layout" for the Finder. I create a new window with half of the vertical size of the desktop ('cos I prefer landscape/horizontal windows for column view) and right away following that I create a new window because the Finder clones the last not-yet-resized window's dimensions, and I only need to reposition the two, similarly sized windows. Since I rarely move Finder windows around I do not need to do it too often.
    4 points
  14. https://processwire.com/blog/posts/introduction-migrations-module/
    4 points
  15. I don't fully understand the question, so a simple answer, yes with PHPUnit. And people was already doing it 6 years ago : https://github.com/niklaka/ProcessWireTests
    4 points
  16. I always do a quick install on unknown servers with the blank site profile, pull in the modules for Diagnostics and the ProcessDatabaseBackup, do a proper check of server, database (charset collations etc.), filesystem, PHP, image support, etc, and if all is well or changed to be well, I install the initial database dump and switch to the site profile. The times before I switched to that approach, I several times run into issues that could be ommitted with my current approach, and it took me much more time to find out what was not setup right or missing. - Sure, if you already know the server you deploy to, it can be done without the initial install and diagnostics step. But also on a known server, someone may set the wrong database charset, wrong file access rights, or bind a account to the wrong PHP version, or what ever. Do a fresh install and check with diagnostics modules all together takes 10 minutes max., to see if everything is as it should be. ?
    3 points
  17. Hi Ryan, can you make all the text left justified instead of centered when viewing the site on mobile? I find it hard to read when the text is ragged. I'm referring to the blog posts and the blue footer text (twitter posts, forum postings, Latest news, etc.) I also noticed after typing in the search field on the site, every time you hit the down arrow key to try to select one of the autocomplete suggestions a spinner shows like it is searching again.
    3 points
  18. Firstly, Great work on launching the new website! Looks great! The only feedback I have is a concern about the example code that is provided on the homepage. Which I believe may confuse some people. In 3.0.39 the FunctionsAPI was added (https://processwire.com/blog/posts/processwire-3.0.39-core-updates/#new-functions-api), which can be added in the config file, until you do that however, using functions will not work. Here are those examples: // Render your site’s primary navigation echo pages('/')->children->each('<li><a href={url}>{title}</a>'); // Find buildings: built before 1950, 10+ floors, sort by height pages('template=building, year<1950, floors>=10, sort=height'); // Get “email” field from /contact/ page and use it <a href='mailto:<?= pages('/contact/')->email ?>'>Email me</a> These will not actually work out of the box and cause Internal Server errors. I feel like most people learning will look at the API Reference, I don't believe that FunctionsAPI is very well documented. In fact, I doubt new people will read that far back in the blog posts. I do believe that there is a lot of functionality that gets lost in blog posts. What is everyone else's thoughts on this?
    3 points
  19. As always, excellent write-up! Clear and concise ?. If I had the money and you had the time and interest, I'd pay you to write many more ProcessWire tutorials ?.
    3 points
  20. @neophron You might also have a look at my blog article "Warum ProcessWire die beste Wahl für Ihre Website ist (nicht immer, aber in den meisten Fällen)" or a case study of the website of P. Jentschura, which is also based on ProcessWire.
    2 points
  21. It's been mentioned a couple of times. I think functions API should lead the examples, but I understand the concern. Per the mention in last week's post, I'll be writing up all the details this coming week. Take a look, and if I haven't convinced you guys at that point, I'll be happy to change the examples. The only thing is, we'll probably need to come up with new examples because they get too long without the functions API. And at that point, they no longer serve the intended purpose at least on the marketing aspect. Favicons now added. The same could be said of using an API variable inside of a function or method. These are short examples to get you interested, they lack surrounding context regardless of what style API you are using with PW, and there will be cases where they work and where they don't either way. We're just trying to give people a small sip to see if it tastes good, not show them how to brew the beer. However, with that said, the intention is that they will work out of the box. They do work on the dev branch right now (which is the branch we recommend for new installs). This will also merge to master again soon. The examples have always worked on the core Regular site profile as well. Error messages have also been added to detect when you use a functions API call without them enabled, and it then tells you exactly what you need to do to enable it. As far as the core goes, the values set in /wire/config.php have to be settings that work on all existing installations. Whereas the values set in /site/config.php are those intended for new installations. We can't enable the functions API on existing installations—only new installations. The reason is that someone may have defined their own pages() function (for example) years before we even had a functions API, and upgrading to a version of PW that has it pre-enabled would then break their installation. I make an effort to ensure anything that gets added in PW is done so in a backwards compatible manner, and this is why there are properties like $config->installed and independent config files. The mix of approaches is actually relevant here because anything using a function refers to something where only one instance can exist, and anything using a variable refers to something that can have any number of instances. So I would use a variable like $page in an example when the intention is to say "can be any page", whereas I would use page() when the intention is to say "page being viewed", as there can only be one. That is one benefit, but definitely not the only one. Read what I have to say later this week. Context is important here and the statement above skips that. I'm recommending the functions API for front-end templates, where PW manages the instance for you. But this is also where our audience is going to be 99% of the time. Of course if you are developing modules, then neither pages() or $pages is right for you, as you are going to need to ask for them from $this. I'm not trying to appeal to module developers, they already have a good handle on this stuff. I went back and forth on this one a couple weeks ago, but settled on the centered version after a lot of testing. Centered felt much more balanced, perhaps because the lines are so short that all the weight ends up on the left side. These are just short snippets of text, but if it were any longer then no doubt we'd want to go left aligned. Good one and I agree. I think Robin S. also mentioned this if I recall, and I do have it on my list to add this capability. Uikit 3 doesn't come with an autocomplete component (Uikit 2 did), and we don't have one to use from jQuery UI like we do in the admin (since not using jQuery UI on this site). So the current autocomplete search is completely homegrown. I don't really know how to add the arrow key nav to this at the moment but do plan to hopefully figure it out soon. Between the existing wire highlight pointer, and the existing darkened text, and then add on that the text usually matches that of the headline, to me this just seems like way too much emphasis and redundancy if we also add a color change to it as well? At least my opinion is I don't want my eyes to be drawn to that unless I'm specifically looking for it.
    2 points
  22. Here is another status report for development (early state) of my GroupMailer module: I've setup the dashboard to list all GroupMailer messages found in pages tree. The question is how messages (pages) should be managed in general. I plan to make the whole thing as flexible as possible. You can create messages wherever you want, in the root - directly under "Home" or within a container page. In the upper area of the dashboard you can select the desired container and all messages of this container will be listed. Messages are identified by the template "groupmailer-message". A field containing meta data for the message (dispatch status, number of recipients, number of mails sent, etc.) is attached to this template. The Messages grid will show these values. The Messages grid itself is a rewrite of the ProcessPageLister module matching the requirements of GroupMailer. It will provide all features of the original PageLister module + specific GroupMailer functions. It will be a live view of the current state of all Newsletters (Messages). That means you can watch how mails are sent out and immediately stop/restart etc. the sending process. Here is a screenshot of the current state: (The columns are not the final ones and will be adjusted according to my needs.) What do you think? Am I on the right way or do you have any hints?
    2 points
  23. I just noticed this topic, here is a related post for the Cookie Management Banner where this issue was also present: Here you can find the location of the phrase-index.txt file too.
    2 points
  24. @flydev, thanks for linking that thread – I had already forgotten the whole thing. Will come in handy for a project I'm currently working on ? That being said, TDD or test-driven development is a pretty specific process: essentially you define what the app should do (success criteria), create tests based on that, and finally write code to fulfil those tests. Iterate this until you have a complete application. I haven't heard anyone developing ProcessWire stuff like that, but technically it's doable, although it obviously depends a lot on what you're actually building with ProcessWire. For most sites out there I'd argue that TDD probably isn't the easiest thing to pull off, or perhaps even the most sensible approach. In my opinion it's more suitable to application development. The front-end layer alone adds loads of complexity to the equation. I'd love to hear if anyone is actually doing this in our context though ?
    2 points
  25. Did you just delete the template table and nothing else? This should be relatively easy to rebuild manually because it links to the fieldgroups and fieldgroups_fields tables which actually contain the details of the fields that belong to a template. The main thing you will have to do is to recreate template permissions etc once you have the basics set up. If you look through the columns of a templates table from another install you should be able to figure things out. If you have a lot of templates it might be easier to write a script that queries the fieldgroups table and rebuilds the templates table from that because there is actually some duplication of content between the two.
    2 points
  26. @kongondo you should consider crowdfunding this. Kickstarter or whatever. The community needs an official or reputable shopping solution and what you’re doing is so much work without a guarantee that it will pay off for you.
    2 points
  27. RockLESS Download: https://modules.processwire.com/modules/rock-less/ Docs: https://github.com/BernhardBaumrock/RockLESS
    1 point
  28. Anybody here using TDD in PW?
    1 point
  29. A little solution that maybe helps someone... Often when I'm writing documentation for a site I want to get the label text from an inputfield header so I can paste it into the document. But the problem is that you cannot drag a selection around the header label in order to copy the text. So as a solution I used a bit of jQuery to get the label text when the inputfield header is Alt+clicked. $(function() { // If an InputfieldHeader is clicked... $(document).on('click', '.InputfieldHeader', function(event) { // And the Alt key is down... if(event.altKey) { // Get the header text, excluding that within the AdminOnSteroids field edit link var text = $(this).clone().find('.aos_EditField').remove().end().text(); // Copy the text to the clipboard copyToClipboard(text); } }); }); // Copy a string to the clipboard function copyToClipboard(string) { var $temp = $('<input type="text" value="' + string + '">'); $('body').append($temp); $temp.select(); document.execCommand('copy'); $temp.remove(); } I added this to the PW admin using the Asset Paths feature of the AdminOnSteroids module: The solution in action: Okay, so those are short labels and I could have just typed them out by hand. But some labels are longer, copy/pasting reduces the chance of typos, I'm lazy, time is money, etc.
    1 point
  30. Yeah, that's what I have been doing up until now when the irritation finally became too much. ?
    1 point
  31. Nice - much better than my "Inspect Element" approach ?
    1 point
  32. This is not what I'm saying. You seem to think this is something complex, but I think that's because you are used to something different. New users will not already be used to something. What I'm suggesting is actually much simpler than you think, and is more specific and clear than using exclusively $var or var(). Please wait and see what I write up this week, and I think it'll make sense. Like I mentioned earlier, if you fully understand it and still don't agree about the benefits, then I'll reconsider, but for now trust me on this. I would agree if we were showing $pages and pages() in the same set of examples, or $page and page(). But we are not. The examples don’t state “this is from a template file” or “this is from another script”, or any number of other contexts you could access PW’s API from. There’s plenty of cases where this call will work exactly as-is. If you are in a context where it won’t, it even specifically tells you what you need to do: call $page->of(false); first. Any 1-line example could work in one context and not another, that's the nature of it. In this brief set of intro examples it's important that we show not just getting data, but also saving it—wouldn't you agree? Yet setAndSave() is an advanced call, there for people that know what they are doing with regards to output formatting. It's not something to put in a beginner example because it's not for beginners. It’s important to learn what output formatting is before you start bypassing it. So I’m a little shy about a setAndSave() call here, plus I think it’s kind of a unique one-off in PW’s API, so not a general API example to communicate the underlying flavor of the API. And these examples are trying to communicate the overall flavor of the API, something to get you interested enough to explore further. In the examples we also refer to floors, height, year, email. Immediately under the examples it states “All fields in ProcessWire are custom fields that you easily define and edit in the admin.” This is what the examples are showing, and this is actually a pretty important point of the homepage. The fields you access from a page are entirely your own and you configure them how you want. If this is something that causes one confusion, then that would be a good confusion because it's revealing a key "aha" point. If this is something that sends one packing, then they didn't get it and are likely looking for something different than what PW is, which is also fine. But my preference is not to present examples that imply a fixed-field system, because that is the opposite of what PW is. Ah okay, thanks, I'll revisit and test it out again for those elements.
    1 point
  33. By the way, I took a moment to test the module and it seems to be working pretty well on PW3, so I updated the compatibility info.
    1 point
  34. Good idea, Just did that! Also added it to the README.
    1 point
  35. I was just considering this approach, but it did not meet the requirements in my case. It should be live data, due to quick reactions at hot topics of the editors. And since some templates of the page in the ProCache have lifetimes of more than a week or more, an update of pages with a daily CronJob would also delete the cache unnecessarily. But as you already say, many approaches for very special requirements. ?
    1 point
  36. This module looks very cool, thank you! I've built a similar solution (although simpler in the config side) where I run a cronjob daily to update the count on a field on each page. It works like a charm, but of course, there are other ways.
    1 point
  37. Thank you. Not yet, because the data is stored in an extra table. But I will write the possibility for a future version on the ToDo-List. ?
    1 point
  38. Don't want to discredit your work, but maybe a note/link in the first post of this topic would make sense? Not saying that people should use "my" way, but it might make sense to mention it there so that they can make an educated decision ?
    1 point
  39. True, for example, I didn't written any test for our frontend, but the backend and the module managing the transactions with financial data is fully unit tested, and it's required (while writing that, I am thinking on what we discussed on Github about the example of the float type vs the integer one for managing financial data; Imagine the things without test... houston.. ?‍? ).
    1 point
  40. @szabesz While searching, I stumbled on this extension, its was tempting. I think I will try it someday. Funny change log ?
    1 point
  41. If you want to move an existing PW site to another server I suggest http://modules.processwire.com/modules/process-export-profile/. I just used it for a site and it worked perfectly, copied all files, database, templates, modules and assets. And it's just about fool proof simple. I used Soma's install script (https://processwire.com/download/core/), easiest way to get going.
    1 point
  42. Nothing has changed in this regard. But we have Duplicator now, that might help you:
    1 point
  43. Hi @ryan, Could we get the current version numbers back on the master/dev download buttons?
    1 point
  44. @ryan, the new site search is great - such an improvement over the previous version. After searching I find myself trying to use the keyboard (arrow keys, enter) to highlight and select results, like I can in the PW admin search. Would it be possible to add this feature to the processwire.com search?
    1 point
  45. You're talking about wall-time. To be really save for future dates you need to store not only the datetime (UTC) + timezone, but also the wall time. There are changes in timezones multiple times per year and some are even countries changing how their timezones work. If you have both UTC and wall-time you can detect such changes and react accordingly. The UTC time you need as soon as you need to compare / act on times, which are in multiple timezones, you need to interact with some APIs or export .ics calendar files. So for your examples it might be fine to disregard the timezone and only use wall-time. Here's some more information on why timezones are hard: https://zachholman.com/talk/utc-is-enough-for-everyone-right I've also found this to be a good blog with a bit more actionable advice: http://www.creativedeletion.com/
    1 point
  46. This is what I have so far (very early state, please do not pay attention to the column values) I have decided to use ProcessWire modules wherever possible. I also want to avoid dependency on third-party modules - there are so many out there which are abandoned or no longer supported. The grid in the screenshot is an MarkupAdminDataTable combined with parts of a PageLister. As this will be a live-view, where you can watch your mailings flying out, I'll refresh part of the columns via Ajax. As I said, we have already developed a very powerful multiprocessing sending engine for the mailing module. So we are good to go here. In general, I'd like to orient the Module as closely as possible to the ProcessWire look and feel and paradigm. The UIKit Admin Theme will be primarily supported.
    1 point
  47. An update to the hook in the first post for PW v3.0.117 or greater. // Add a new 'chunk' method to WireArray, the equivalent of PHP's array_chunk $wire->addHookMethod('WireArray::chunk', function(HookEvent $event) { /* @var WireArray $wire_array */ $wire_array = $event->object; $size = $event->arguments(0); if( !((int) $size > 0) ) throw new WireException('WireArray::chunk requires an integer $size argument greater than zero'); $chunks = new WireArray(); for($n = 0; $n < count($wire_array); $n += $size) { $chunks->add($wire_array->slice($n, $size)); } $event->return = $chunks; }); This returns the chunks as a WireArray so you have the option of using WireArray methods. So if needed you could do something like: $items = $pages->find("template=foo"); $chunks = $items->chunk(5); $three_random_chunks = $chunks->find("limit=3, sort=random");
    1 point
  48. Let's say that you have an image called myimage.jpg and it's accessible via http://localhost/mysite/site/assets/files/1020/myimage.jpg. If you rename or delete that image and users keep visiting that link they will obviously view a 404 error page. Instead of displaying the 404 error page you can redirect them to the file's belonging page by adding the below code on top of your 404.php template: $url = $_SERVER["REQUEST_URI"]; $pattern = "@site/assets/files/(\d+)/@"; if (preg_match($pattern, $url, $pageid)) { $fp = $pages->get($pageid[1]); // get the page id from the file path if($fp instanceof RepeaterPage) $fp = $fp->getForPage(); // if the file is inside repeater item get the page where the repeater belongs if($fp->viewable()) $session->redirect($fp->url, false); // redirect only if the page is viewable // false = 302 temporary redirect - true = 301 permanent redirect }
    1 point
  49. Nearly ten months later, FormBuilder is happily at work here and I am testing a home-brewed module that implements repeating fieldsets for FB forms [TM]. I have named it FormBuilderMultiplier and put it on GitHub in case anybody is interested.
    1 point
×
×
  • Create New...