Jump to content

Leaderboard

Popular Content

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

  1. 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.
    6 points
  2. I don't think there's an inbuilt method for that, but you can quickly built your own! For the excerpt, you just need to find the first occurance of the search term inside the field you're searching, then display the text around that. A quick example: // get the search term from the GET-parameter and sanitize it $term = $sanitizer->text($input->get->q); // how many characters to include before and after the search term $include_around = 50; foreach ($pages->find('body~={$term}') as $result) { echo '<h2>' . $result->title . '</h2>'; // start and end positions of the search result in the body field $term_start = mb_strpos($result->body, $term); $term_end = $term_start + mb_strlen($term); // where to start and end the output, and additional // checks to make sure it's not out of bounds $offset_start = $term_start - $include_around; if ($offset_start < 0) $offset_start = 0; $offset_end = $term_end + $include_around; if ($offset_end > mb_strlen($result->body)) $offset_end = mb_strlen($result->body); $output = mb_substr($result->body, $offset_start, $term_start); $output .= '<mark>' . $result . '</mark>'; $output .= mb_substr($result->body, $term_end, $offset_end); echo '<p>&hellip; ' . $output . ' &hellip;</p>'; } I don't have a ProcessWire installation to test this right now, so might be some errors in there, but you get the idea ^^ Basically, find the term inside the field you're searching, then include some characters before and after it for context, and wrap the search term in <mark> tags for highlighting (you can also add a CSS class to target the search result for styling). You can of course refine this as much as you want, for example you can check for full stops to include complete sentences; you'll also want to make sure to find matches in the title as well, and in this case maybe only display the first X characters of the body ...
    5 points
  3. 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)
    4 points
  4. Just added a new Admin Actions panel - the available actions are context sensitive so you only get actions that are relevant to where you are in the admin (or frontend in some cases). This is just a first version, but so far we have: Delete all children This lets you delete all children of the current page without deleting the page itself which can be very helpful when you're testing API creation of page and you have forgotten to enable Tracy's Page Recorder panel. Delete field If you're on the edit interface for a field, this action will let you delete a field even if it is already added to templates, so you don't have to deal with the "This field may not be deleted because it is in use by one or more templates." notice you get when trying to delete the field. Change field type Again, if you're on the edit interface for a field, this lets you change the field to any installed field type. This ignores the compatible field type check that you are normally subject to. This is probably not good to use if you already have page data in this field, but it's really handy when you have already set up a field and added it to templates but decide you want to change its type to a non-compatible type. Delete template Like the delete field, this bypasses the "This template may not be deleted" because there are pages already using it. This takes care of deleting any pages using the template and then deletes the template, all with one click. Uninstall module This will take care of deleting any associated fields (for Fieldtype modules) and modules that require the one you are trying to uninstall so that you can uninstall the module with one click. Hopefully it goes without saying that these can be extremely destructive and bypass core protections against data loss so use with extreme caution. Each action has a confirmation dialog that you must confirm to reduce any accidental clicks and the entire panel is restricted to superusers only, but you must still use with extreme caution. I'll add other actions as ideas come to me, but if you have any requests, please let me know.
    4 points
  5. Here I'm writing up about my first ProcessWire site, Reached.space, a blog and directory about shops which offer international shipping. I'm from The GrayFly Group, which is the registered trade name for GrayFly Stationery, LLC, a limited liability company registered in the state of Kentucky, USA. You might ask, why is a stationery company creating websites?! Well, in a way both activities are very similar: both activities have the goal of getting written messages across in a pleasing manner to the reader. With that out of the way, let's move on and explain what went on behind the scenes of the Reached.space site: Template I used a free CSS-based template from W3CSS at https://www.w3schools.com/w3css/w3css_templates.asp , using mainly the "Architect" template as the basis and modifying it as needed. Pagination The pagination feature of ProcessWire was very helpful here; I kept the home page to just two blogroll articles so that the reader was not overwhelmed, but upon pressing "more articles" the remainder of the blogroll is paginated with 4 articles to a page. Screen reader I made adjustments to my usage of the template to make it screen-reader-friendly. I used the Google Chrome extension to test out how the site would be handled with a screen reader. Security Security is always important, so I was thrilled to find a great all-in-one-place security guide in the ProcessWire docs at https://processwire.com/docs/security/ - I simply went through the guide and did what it said, using it as a checklist. Modules As far as I'm aware, the only additional modules I used (that were not already activated by default in standard PW install) were the Upgrade and Upgrade Checker modules. The main reason for this was security considerations, but it was also an added convenience and peace of mind to have it check for updates every time I logged in. However, I did use additional software that was not modules, as described below. Other software - Simple HTML DOM Here I was very fortunate to receive help from the ProcessWire community on the forum. Due to the site's monetization model being affiliate marketing, I wished to make all my external links nofollow and target _blank by default. User @Robin S was instrumental in showing me how to do this using Simple HTML DOM in the forum post https://processwire.com/talk/topic/17295-solved-how-to-make-external-links-nofollow-and-target-_blank-by-default-if-using-source-code-toggle-in-editor/ Other software - Google Analytics cookie manager My site requirements for GDPR were specific enough that I felt I would rather develop my own code to handle Google Analytics tracking, which I'll describe here. I wanted to be certain GA tracking was disabled by default requiring opt-in, instead of opt-out. I also included in the Cookie Manager some written info about third party cookies (these are placed when clicking on affiliate links) and how the user can avoid such tracking (turn off third party cookies in their browser settings). I also disabled front-end PW cookies as described here: https://processwire.com/talk/topic/15270-session-storage-and-lifetime/ Google Analytics cookie settings The Google Analytics cookie setting code was done using JavaScript. I used a session storage variable to indicate whether the user had a) accepted GA tracking cookies b) declined them or c) had not made a choice yet. I also had to make some changes also to the <head> code to ensure Google Analytics cookies were not set unless the user had accepted them. Efficiency - optimizing 404s I used the guide at https://processwire.com/blog/posts/optimizing-404s-in-processwire/ to sinkhole bot-driven 404 requests to a static 404 file. Back office pic Below is an image of how ProcessWire allows helpful field descriptions and displays them when used in templates, so that when I come to actually use or enter content in fields I created months ago, I know what the ramifications are. Very helpful. Also, when using the back office I found the Reno admin theme to be very pleasing, efficient, and easy to use.
    3 points
  6. Sorry for the confusion @Robin S - it was a failed attempt at humor ? I was trying to make the point that there are way too many options - some are intentionally provided and some are just due to class inheritance etc, but I personally think we should be very careful to document just one default approach for all examples and then properly explain the other options and where they can/need to be different to the chosen default approach.
    3 points
  7. I would probably use such CSS instead: *:not(.pw-no-select) { user-select: text; }
    3 points
  8. 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.
    3 points
  9. Absolutely this needs to be covered in the official documentation. It's foundational stuff and too important leave to a scattering of forum discussions. I'd hazard to say there are many here who have been working with PW for years and are not 100% clear on this stuff (myself included).
    2 points
  10. With the examples and documentation I think we should focus on illustrating things that a new user should use (depending on context) rather than all the things they could use. So we should take a best practices approach rather than trying to cover everything that technically will work. Please correct me if I'm wrong here, but I don't think there are any circumstances where the extra examples you gave would be advantageous over the four examples I suggested (again, which of the four would depend on context). So although it's common to see the form $this->pages in modules it's actually more optimal to use $this->wire('pages') because it's more efficient (no extra check needed for a class property named "pages") and cannot clash with class properties with the same name. (To be honest I personally do use $this->wire()->pages over $this->wire('pages') but that's just because it's easier to automate with macros in my IDE rather than for any other advantage).
    2 points
  11. @neophron There's a WP-Migrator module floating around somewhere, iirc. And there are various code-bits from Ryan here (although, apparently the old WP-site had comments stored in Disqus, not native WP).
    2 points
  12. @Robin S and @adrian, a great discussion and follow-up solution(s). This is the type of stuff that makes this Forum so valuable and worth reading on a daily basis.
    2 points
  13. @horst There's also TracyDebugger's Diagnostics panel https://adrianbj.github.io/TracyDebugger/#/debug-bar?id=diagnostics that you can use.
    2 points
  14. 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 ?.
    2 points
  15. 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
  16. There is already some information on how to do this but it's a bit scattered, so here's a quick tutorial... This is how $session->CSRF->hasValidToken() handles AJAX requests, by getting the token name and value from request headers: if($this->config->ajax && isset($_SERVER["HTTP_X_$tokenName"]) && $_SERVER["HTTP_X_$tokenName"] === $tokenValue) { $valid = true; } else if($this->input->post($tokenName) === $tokenValue) { $valid = true; } So all we need to do is to pass the name and value to our JavaScript and set the right headers with our AJAX request. We could instead of setting headers put the name and value pair into the body of a POST request, as the second conditional doesn't care if the POST request is received via AJAX or not. But this limits the request to POST and the body data type to either multipart/form-data or application/x-www-form-urlencoded (because that's all that PHP's $_POST superglobal will handle). Admittedly this might be 99% of use cases, but for example if a GET request invokes significant processing then CSRF protection could be used to prevent a DOS attack on the endpoint. So, for the sake of a bit more flexibility, and to be more in keeping with what PW expects, we'll use request headers. I find it neater to write the token name and value into HTML and retrieve that using JavaScript DOM functions, instead of writing JavaScript with PHP ?. So somewhere, maybe in init.inc.php, get the token name and value: $csrfTokenName = $session->CSRF->getTokenName(); $csrfTokenValue = $session->CSRF->getTokenValue(); Then in a global footer template: <div class="js-csrf-token" style="display:none;" data-csrf-token-name="<?php echo $csrfTokenName; ?>" data-csrf-token-value="<?php echo $csrfTokenValue; ?>"></div> Now to retrieve the token in JavaScript: function getCsrfToken() { const csrfTokenNode = document.getElementsByClassName('js-csrf-token')[0]; return { name: csrfTokenNode.getAttribute('data-csrf-token-name'), value: csrfTokenNode.getAttribute('data-csrf-token-value'), } } Then in any AJAX request: const csrfToken = getCsrfToken(); let xhr = new XMLHttpRequest(); // ... // open the request and do some configuration // ... xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); // tell the server and PW that it's an AJAX request xhr.setRequestHeader('X-' + csrfToken.name, csrfToken.value); // create a header with the token // ... // send the request // ... And that's all, in the endpoint just do... if ($session->CSRF->hasValidToken()) { // works for AJAX! } This has used the default CSRF token created for every session, but to create and use a different token just specify an id: $csrfTokenName = $session->CSRF->getTokenName('myAjaxToken'); // this creates a token if one with the given id doesn't exist $csrfTokenValue = $session->CSRF->getTokenValue('myAjaxToken'); and... if ($session->CSRF->hasValidToken('myAjaxToken') { // ... }
    1 point
  17. I have used these functions in the past for search excerpts: https://github.com/boyter/php-excerpt Together with this jQuery library for highlighting: http://bartaz.github.io/sandbox.js/jquery.highlight.html You might like to consider maintaining a hidden "index" field in your templates that merges the text content from other fields in a Page::saveReady hook. Then you use this field for searching/excerpting/highlighting.
    1 point
  18. Well I am assuming at some point I'll be adding some actions that aren't destructive ? Thanks @szabesz for the name suggestions. I'll marinate on it for a while.
    1 point
  19. or Destructive Actions?
    1 point
  20. Quick Actions Utility Actions Shortcut Actions Tracy Shortcuts Utilities
    1 point
  21. I'm not too worried about it, but I do see your point. I wasn't sure what else to call it at the moment. If you have a better idea, please let me know. Obviously this panel has has a few limited/restricted actions, so it's not meant to be a replacement for the Admin Actions module - just some quick shortcuts to a few things that I come across semi-regularly.
    1 point
  22. Thanks as always, the new panel does sound useful indeed. However, you already have a module called Admin Actions. It might be confusing in some circumstances that these share the same name, don't you think?
    1 point
  23. Right now I am working on filtering, but customers are nagging me about getting their sites done, so this module needs a little bit more time. Hope to find some time in the next days.
    1 point
  24. Hmm.. Too many tabs already? ?
    1 point
  25. More info: https://github.com/processwire/processwire-issues/issues/126
    1 point
  26. Wow... that's indeed really nice. Two things came up while playing around with it. Is it planned to exclude logged-in users from tracking? I know that several of my clients publish new content and therefore check the new site over and over again. Right now they would create page counts that are kind of fake. Is it planned to reset all or some counters? Right now I created ~50 page counts and would like to reset those to zero again.
    1 point
  27. https://github.com/nicoknoll/MigratorWordpress - it handles post and comments automatically but if you already have the posts imported maybe you could at least steal some code from this to help with your comment importing.
    1 point
  28. @Chris Bennett @Noel Boss, I don't know how look your user edit page, but on mine, the checkboxes are not customized. It was also necessary to add the rule for : .InputfieldCheckboxesStacked { } Below the modified @3fingers version :
    1 point
  29. Going here causes internal server error: https://processwire.com/blog/posts/
    1 point
  30. Nice - much better than my "Inspect Element" approach ?
    1 point
  31. Please inform the module authors to use HTML entities in notes for html tags. I've already fixed my PayPal module and also informed @Soma for EmailObfuscator module. It seems that with HTML entities just removes the whole messed up text but Live Search still remains broken. I will wait for an official fix from @ryan.
    1 point
  32. @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.
    1 point
  33. @Soma Please update the module with the following fix to avoid breaking "Live Search" in Languages. Replace the 92 line with this: $field->notes = __("Example &lt;/head&gt; or &lt;/body&gt;.");
    1 point
  34. 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. ?
    1 point
  35. First work in progress version ? Built with vue.js for fast DOM updates. Needs to be AJAXified and more details. So maybe wait a little bit with feedback. I know there is lots of information missing. OK, now I go to sleep, because it's 4:30 am and I am invited to a birthday today.
    1 point
  36. Just a thought but instead of diving in headfirst, maybe those interested in creating content whether articles or video should create a content outline. - Purpose of said educational piece - Overview of what students will be learning - Framework requirements (version of PW; any modules required, etc.) - Section overviews (think of this as chapter titles in a book and brief description of what’s covered) - Paid or free Those are a few thoughts. Although I am not a programmer, from a brand standpoint, I’ve watched Laravel develop from its inception. It’s been a beautiful process to watch. And it’s been successful for being opinionated and rigorous in documentation, besides paying attention to the craft of good design.
    1 point
  37. Great point thanks for the guidance its really knowledgeable discussion.
    1 point
  38. Yes, Bootstrap https://getbootstrap.com/, Zurb Foundation https://foundation.zurb.com/ & UiKit https://getuikit.com/ are good places to start if you're unfamiliar with responsive websites. Actually, even if you are, they can save you a lot coding time. ThemeForest is a good place to start. I often buy a license for Canvas, https://themeforest.net/item/canvas-the-multipurpose-html5-template/9228123 which is based on Bootstrap, then place all the files in site/assets and as mentioned previously, use overrides/changes in site/templates. ProcessWire uses UiKit3 as it's default responsive admin theme
    1 point
  39. Yes it is possible but it depends on your needs. I also built several software with ProcessWire as a base. But you have to tweak the backend to your likings (which requires much hooks), or create an own backend instead of the default one.
    1 point
  40. Hi, This is my another PW website - http://pkrosifoundation.org No Modules used
    1 point
  41. I tested it too, and the problem occurs when the paragraph is longer than the truncate length, causing there to be no closing </p> tag present in the truncated string. There is an option for the fixUnclosedTags() method used by truncate, to close instead of remove unclosed tags... * Fix/close unclosed tags: * ------------------------ * When the remove option is false, it will attempt to close unclosed tags rather than * remove them. It doesn't know exactly where they should be closed, so it appends the * close tags to the end of the string. ...but the truncate method calls fixUnclosedTags() with remove = true and doesn't provide a way to do otherwise. I guess you could use WireTextTools::fixUnclosedTags() before calling $sanitizer->truncate but it would be nice to have the option built into the truncate method. Maybe an oversight by Ryan? Edit: request opened here: https://github.com/processwire/processwire-requests/issues/253 @bibsch, because your truncate length is short and will only contain a single paragraph you can achieve your objective by adding <p> tags around your truncated text: echo '<p>' . $sanitizer->truncate($child->body, 200) . '</p>';
    1 point
  42. New in version 0.1.2: show test method and assertion count for passed tests display breadcrumb above test file name (configurable)
    1 point
  43. Just released this language pack for the latest master 3.0.123 (only 3 days after release)
    1 point
  44. Last night I did some researches for a client with an old WordPress site. I was looking for german web articles about Processwire, cause the client is from Berlin. I found this article: https://www.sputnika.de/dresden/news/campus-halensis-de-das-neue-online-magazin-der-martin-luther-universitaet-gid-5976 It's about the redesign of this site: https://www.campus-halensis.de/ The old version was a WordPress site, now it runs with ProcessWire.
    1 point
  45. PageListSelect is different because it doesn't get pages via Pages::find, but rather gets the children of individual pages if they are listable. This is what I came up with: $wire->addHookAfter('Page::listable', function(HookEvent $event) { $page = $event->object; // Page is listable if it is the Users parent or a user page and the current user has a given role if(($page->id === 29 || $page->template == 'user') && $this->wire()->user->hasRole('editor')) { $event->return = true; } }); $wire->addHookBefore('ProcessPageList::find', function(HookEvent $event) { $selector = $event->arguments(0); $page = $event->arguments(1); // Don't check access if getting children of the Users parent and the current user has a given role if($page->id === 29 && $this->wire()->user->hasRole('editor')) { $event->arguments(0, $selector . ', check_access=0'); } });
    1 point
  46. See this note: Because of this requirement this input type won't be suitable for non-superusers to select users because you don't have the possibility to specify check_access=0.
    1 point
  47. I am right now working on a quite similar project. In my case I import from an XML that I get through an API and populate product pages, check for there status etc. I can encourage you to go on the way you started. It is all pretty straight forward and nice to handle with the PW API. Your import code looks basically fine. So you shouldn't have major problems there. I set up a process module that creates a page in the backend where admins can manually trigger imports. If you would like to go that route, there is a skeleton Hello Process module that you can use and @bernhard wrote a great article on building admin pages with process modules. I find this approach much cleaner than doing all the logic in a template file. Regarding your concerns Use lazy cron module for automation. Each time you get a new JSON, loop through it and compare it to the single-movie pages you have and act on them (modify/delete) or create new ones. You can use custom fields on the single-movie template to store that Have a look at https://github.com/webcreate/infinite-ajax-scroll You can use kongondos Blog module or at least get a lot of inspiration from it ;-)
    1 point
  48. This should do it - just change "body" to the name of the existing field that you want to insert before. You can of course change insertBefore to insertAfter if that is easier/needed. if($page->template == 'service-type') { $f = new Field(); $f->type = $this->modules->get("FieldtypeRangeSlider"); $f->name = 'servicetype_' . $page->name; $f->label = 'Service-Type ' . $page->get('title')->getDefaultValue(); $f->set('suffix','%'); $f->set('tags','servicetype'); $f->set('icon','fa-sliders'); $f->save(); $existingField = $page->template->fieldgroup->fields->get("body"); $template = $page->template; $template->fieldgroup->insertBefore($f, $existingField); $template->fieldgroup->save(); } Here's a relevant section from the core ProcessField module that shows this in action: https://github.com/ryancramerdesign/ProcessWire/blob/master/wire/modules/Process/ProcessField/ProcessField.module#L1850
    1 point
×
×
  • Create New...