Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 08/31/2018 in all areas

  1. This week flew by too fast. I did some work on the core, but mostly had to focus on some end-of-the-month client work deadlines, in ProcessWire-powered projects. As a result, I don't have enough core updates to warrant a version bump on the dev branch this week, so putting a quick update here rather than a blog post. ProcessWire 3.0.112 should be ready by this time next week. One of my clients recently requested a URL field that intermittently verifies itself—to make sure that the URL is still returning a 200 success, and not a 404 error, or some other error code. Their site has thousands of external URLs (more than they can check manually), and they want some way to avoid showing links for URLs that are no longer working. I thought a self-healing URL field sounded like a cool idea, so put a little work into that this week, and will likely finish it up next week. The module is called FieldtypeVerifiedURL and it extends the regular FieldtypeURL field, except that in its configuration you can specify how often you want it to verify that the URL is still valid. It also performs the verification whenever the value changes. It uses WireHttp to obtain and store the response code with the field, whether a 2xx (success), 3xx (redirect) or 4xx (error) code. So if you wanted to, you could filter the pages with this URL field by response code (like to find all those returning 404s for instance). It can optionally save the <title> tag found at the URL for you as well. In our case, we will be configuring it to check that URLs are valid once a week, and this is something that it will do in the background automatically. When a URL is found to be returning an error code (like a 404), the output of the field can be optionally configured to return an empty value rather than the URL (when output formatting is on). I'm not anywhere near finished with this one, but if this sounds useful to you, stay tuned for more on this soon. Have a great weekend!
    8 points
  2. 4 points
  3. Both would probably be doable, though a massive use of data URIs would probably also necessitate caching them, or processing time and memory use may lead to performance issues. Here's a small example Textformatter module that converts image links in HTML fields to data URIs. You can set a size limit in the module configuration so any images equal or bigger in file size aren't converted. The default is really conservative (16kB) since not requesting larger images through regular client caching will do more for recurring visitors than saving them a roundtrip but squeezing the images over the wire with every page reload. <?php namespace ProcessWire; /** * Proof-of-concept module for the ProcessWire CMS * * Implements a textformatter for HTML fields that turns regular src URLs to * inline data URIs to avoid separate http requests. * * The default maximum size for images to inline is 16kB. * Feel free to raise this in the module's configuration. * * This code comes without restrictions or warranties. */ class TextformatterImgDataUri extends Textformatter implements Module, ConfigurableModule { protected static $defaultDataUriLimit = 8192; public static function getModuleInfo() { return array( "title" => "Textformatter Image Data URI", "summary" => "Replace image URIs in HTML body with their encoded data URI to speed up page loads", "version" => "0.0.6", ); } public function __construct() { $this->dataUriLimit = self::$defaultDataUriLimit; } public function format(&$str) { $src = preg_replace_callback('/(<img[^>]+(?<!-)src=)(["\'])(.*?)(\\2)([^>]*>)/', function($match) { // Only use files in site/assets/files if(strpos($match[3], $this->config->urls->assets) === 0) { // Translate url to paths $filepath = str_replace($this->config->urls->files, $this->config->paths->files, $match[3]); // If pagefileSecure is active, the path prefix probably needs to be inserted if(!file_exists($filepath) && $this->config->pagefileSecure && strpos($filepath, $this->config->paths->files . $this->config->pagefileSecurePathPrefix) !== 0) { $filepath = str_replace($this->config->paths->files, $this->config->paths->files . $this->config->pagefileSecurePathPrefix, $filepath); //$this->log->save('imgdatauri', sprintf(_("Added pagefileSecurePathPrefix to file path %s"), $filepath)); } // If the file isn't found, we return the original url if(! file_exists($filepath)) { //$this->log->save('imgdatauri', sprintf(_("File %s not found"), $filepath)); return $match[0]; } // Only output images inline that are smaller than the value set in the module's configuration $fsize = filesize($filepath); if($fsize >= $this->dataUriLimit) { //$this->log->save('imgdatauri', sprintf(_("File %s too big, %d >= %d"), $filepath, $fsize, $this->dataUriLimit)); return $match[0]; } // On windows, make sure extension php_fileinfo.dll is loaded $mime = mime_content_type($filepath); $dataUri = "data:$mime;base64," . base64_encode(file_get_contents($filepath)); return $match[1] . $match[2] . $dataUri . $match[4] . ' data-orig-src="' . $match[3] . '"' . $match[5]; } //$this->log->save('imgdatauri', sprintf(_('Not an img with src: %s'), $match[0])); return $match[0]; }, $str); $str = $src; } public function formatValue(Page $page, Field $field, &$value) { $this->format($value); } public function getModuleConfigInputfields() { $wrap = new InputfieldWrapper(); $f = $this->modules->get("InputfieldInteger"); $f->label = _("Maximum size to convert"); $f->attr('name', 'dataUriLimit'); $f->attr('value', $this->dataUriLimit); $f->description = _("Images smaller than the value entered here in bytes will included directly in the HTML (base64 encoded data uri) instead of their links. Note that this text formatter only affects images under site/assets/files"); $wrap->append($f); return $wrap; } }
    4 points
  4. Additionally to adrians suggestion to use TracyDebugger, there also is a possible solution to programmatically adjust between different installed WireMail extensions. (Initially I understood your question in a wrong context. I thought you would want to use both directly in production mode. But if you want to use one for debug mode and one for production, you may define / setup something in your config.php and ready.php.) I would define an extra var in site/config.php that, set to true, enables the wiremailsmtp (production) mode. If it is set to something other or completly missing, enable the wiremail debug extension. needed code may look like this: // in site/config.php $config->useProductionMailclass = false; // in site/ready.php $wireMailClassProduction = 'WireMailSmtp'; $wireMailClassDebug = 'WireMailTesting'; $neededWireMailClass = true === $config->$config->useProductionMailclass ? $wireMailClassProduction : $wireMailClassDebug; // now read which version currently is set to use if($mail->className != $neededWireMailClass) { // the wrong class is in use, change it: foreach($modules as $module) { $parents = class_parents("$module"); if(in_array('WireMail', $parents) && $modules->isInstalled("$module")) { if($module->className == $neededWireMailClass) { $mail = wire('modules')->get("$module"); break; } } } } // do a final validation and add an error handling for when the desired module isn't loaded at this step! if($mail->className != $neededWireMailClass) { die('Something weird is gooing on here with WireMail-Classes'); }
    4 points
  5. This is how I understood @Ivan Gretsky but I may be wrong. Regardless of this, it depends on how many devs work on one site. If I'm the only one, I mostly know what I'm doing. ?
    3 points
  6. PW can in fact do that. It's entirely up to the developer what PW should output. JSON, XML, CSVs, HTML... re: Vue.js If you search here for Vue you'll find a few forum topics with tips and project insights, e.g. https://medium.com/icf-church-developers/processwire-vue-js-a-lovestory-d4d5bca365
    3 points
  7. Some great examples here already and these are probably the best approach, but just another alternative (in case it's useful) is to use a Profields Table field - this way you can easily define a new string to translate as a new row in the table.
    3 points
  8. When "Use HTML Purifier" is enabled for a CKEditor field any data-* attributes are stripped out. This happens regardless of the CKEditor ACF settings, and is pretty annoying considering how frequently data attributes are used/needed these days. I'd like to keep HTML Purifier activated but I want to change the configuration to allow specific data attributes. I know how to do this via addAttribute() - as mentioned here - and I can get this working if I directly edit MarkupHTMLPurifier::init() and clear the HTML Purifier cached files from /site/assets/cache/. public function init() { $this->settings->set('Cache.SerializerPath', $this->getCachePath()); $this->settings->set('Attr.AllowedRel', array('nofollow')); $this->settings->set('HTML.DefinitionID', 'html5-definitions'); $this->settings->set('HTML.DefinitionRev', 1); if($def = $this->settings->maybeGetRawHTMLDefinition()) { $def->addElement('figure', 'Block', 'Optional: (figcaption, Flow) | (Flow, figcaption) | Flow', 'Common'); $def->addElement('figcaption', 'Inline', 'Flow', 'Common'); // Added line below to allow data-ext attribute on 'a' elements $def->addAttribute('a', 'data-ext', 'Text'); } } But how can I change the configuration like this without modifying a core file? I want to set the configuration from a custom module. I don't see any hookable methods in MarkupHTMLPurifier but surely it must be configurable somehow. Does anyone know a way to do this?
    2 points
  9. I see your point for sure. I guess I thought it was more about ensuring the default panels on the local install vs a live one. If you're migrating a database between the two, Tracy settings could get mixed up easily, but by using the config.php file you can more easily keep track of these. You could even use PW's built-in config-dev.php file to ensure that locally the mailInterceptor is loaded, but not on the live server. I think if we need to prevent some panels from being adjusted via the debug bar's Panel Selector, then this needs to be a new config setting where you can select all the panels that you want excluded from the Panel Selector interface. This list of panels could of course be set in the config settings, or it could also be done via: $config->tracy = array( 'nonToggleablePanels' => array('mailInterceptor') ) What do you think about this option - this would make it very difficult to accidentally remove the Mail Interceptor panel. I think perhaps it would also be worth adding a few extra settings to config-dev.php so it looks like this: $config->tracy = array( 'enabled' => true, 'guestForceDevelopmentLocal' => true, 'frontendPanels' => array ("mailInterceptor","processwireInfo","requestInfo","processwireLogs","tracyLogs","methodsInfo","debugMode","console","panelSelector"), 'nonToggleablePanels' => array("mailInterceptor", "tracyToggler") ); This setup would ensure that Tracy is always enabled, the Mail Interceptor panel is on and can't be toggled off, and the Tracy Toggler panel/button can't be enabled. The only remaining way to disable Tracy would be via the Disable Tracy button on the Panel Selector, but I would add an option to remove this as well. @Ivan Gretsky - is this the sort of functionality you would need to feel comfortable with this approach? The other consideration in all this is the load order of modules by PW. The hook that intercepts emails from being sent is in Tracy's init() method, but I suppose if you have another module sends an email in init(), rather than ready(), then it's possible it could be sent before Tracy intercepts it, but that like a highly unlikely situation.
    2 points
  10. The most recent version includes @Robin S's suggestion for "Expand/Collapse All" functionality. Both Robin and @tpr have helped significantly with testing of this feature - thank you both. Also new in this version is the ability to override any module config settings using: $config->tracy = array() You can read more about this and why it was introduced here:
    2 points
  11. same here, looks like i need data- attributes available on paragraph elements...
    2 points
  12. Ok, I have added the ability for Tracy to respect any settings added to the $config->tracy array, eg: $config->tracy = array( 'guestForceDevelopmentLocal' => true, 'frontendPanels' => array("mailInterceptor","processwireInfo","requestInfo","processwireLogs","tracyLogs","methodsInfo","debugMode","console","panelSelector","tracyToggler") ); This ensures that Tracy is always loaded and the mailInterceptor panel is always loaded on the frontend. You may also want to include it in a backendPanels array as well if that is an issue with your setup. To get settings for $config->tracy, I would recommend installing: http://modules.processwire.com/modules/module-settings-import-export/ so you can grab them like this:
    2 points
  13. Hi Ivan, Not currently, but it would be a very simple addition for Tracy to support $config->tracyFrontendPanels and $config->tracyBackendPanels arrays that if defined would override the selected panels from the module's config settings. Is this what you are looking for here?
    2 points
  14. I had the need to do something similar before. We wanted to know how far users got into a multi-step order process, and also what values they were putting in during each step and the referring pages. I found inserting a record on every page load worked well and was fast. Don't increment anything or it is slow, just insert new records and use a weekly or monthly cron to process the data to keep the table size manageable. Add in an optimize command also to clear db overhead after rows are deleted. I insert the session_id, timestamp, ip address, etc, but none of the data is public. Used for troubleshooting.
    2 points
  15. this is working really well for inserting images, audio players and videos from a central media library, inline into ck editor. It saves so much time since it is so fast to insert the page reference to the media item... and i can just intercept my custom insert templates and replace with the video player popup, or audio player (soundmanager2), or responsive image...
    2 points
  16. I think it should work everywhere. I just tested a bootstrapped page: <?php require './index.php'; $mail = \ProcessWire\wireMail(); $mail->to('test@gmail.com', 'Test User'); $mail->from = 'me@gmail.com'; $mail->subject('Test'); $mail->body('Blah blah'); $numSent = $mail->send(); and Tracy captured it just fine: The one key thing I would do is ensure that Mail Interceptor is enabled in the config settings, rather than via Sticky in the Panel Selector so that it can't be disabled accidentally. I would also check the "Force Guest users into Development mode on localhost" option so that even if you're not logged in, Tracy will be active and intercepting an emails. Also, for your own peace of mind, I would suggest checking everything with your email address as the only TO/CC/BCC until you are convinced that Tracy is working as expected. I find it invaluable when testing all sorts of emails.
    2 points
  17. Hi, this is one of examples how can be used ConfigurationForm module. 1. Create field "translate", fieldtype ConfigurationForm Fieldtype 2. In field setup create desired fields what would store translations (eg. textLanguage fields: readmore and submit, and textareaLanguage fields error and success) Please note how to setup these fields: There is no image for success field setup, but it is the same like for the "error note" (textarea, type: textareaLanguage, name: success). 3. In Actions tab, add "translate" field to desired template (eg. Home). 4. Press ProcessWire Save button (ignore blue Save button). 5. After, on Homepage, you will get this: 6. Write desired translations, please note to language switcher on inputfields right side. Press page Save button. How to render translations? 1. call field->subfield and echo it (subfield name). <?php // get main field (container where are all translations) // our translations are on Homepage $translate = $pages->get(1)->translate; //Submit echo $translate->submit; // Read more echo $translate->readmore // etc... ?> With this you can get elegant solution to store all needed translations, easy to add new and easy to administrate. Also if someone forget to write some translation, output would be default translation content. Regards.
    2 points
  18. code: https://processwire.com/talk/topic/12081-ad-banner-module-with-click-through-rates/
    1 point
  19. Hi @horst - sorry was just posting when this came through. The changes I just committed allow overriding of the module's config settings. They don't prevent changes from being made via the panel selector so I guess you could potentially uncheck the Mail Interceptor panel and do a once/sticky but I think that should be the expected behavior. Do you think this is ok, or do you think we need an option to prevent overriding of certain panels?
    1 point
  20. What about this: The config setting should not override the fronten selection, but should make the named ones stay visible (unhideable). ? Or is it that what you allready have in mind? Thinking that someone enables per frontend a panel, that is not within the config setting.
    1 point
  21. Just to correct, if you have edit right and a language or page is unpublished you still can see it if logged in. It's just that maybe something like the language nav that wouldn't show the switch link for that language, but it can be coded to be seen by editors.
    1 point
  22. If you set an explicit protocol on the template, $page->httpUrl() will return correct https if set. $input->httpUrl(true); Will return the full requested url with protocol and query string / url segments.
    1 point
  23. One thing I would like to see is editUrl work properly for users, roles, permissions, templates, and fields. Currently the first 3 kind of work, but they take you to page/edit/?id= instead of /access/users/edit/?id= etc.
    1 point
  24. I know it exists, but have never used it myself. Perhaps this Pro module would help? https://processwire.com/api/modules/prodrafts/
    1 point
  25. Un-tick the active checkbox on pages, not the language itself. Use the ChildBatchEditor or AdminActions module to quickly activate or de-activate pages and entire trees/nodes at once.
    1 point
  26. There's no group by feature in PW. WireArray->unique() doesn't work for this purpose. Using the API you could Just build an array using WireArray->explode() and use array_unique(). Depending how large the result set is you could cache the array so it only builds the array when it expires or based on a selector. $uniquedates = $cache->get("uniquedates", "template=basic-page", function(){ return array_unique(wire("pages")->find("template=basic-page, sort=date")->explode("date")); }); print_r($uniquedates); If the amount of entries is very large and it would take several seconds to build the array, it could make sense to use something like direct SQL query.
    1 point
  27. One more offtop question here, @adrian. Is it possible to set Tracy mail interceptor option programmatically as part of environment config?
    1 point
  28. OK, so as promised, for a use-case with Functional Fields, here's a simple code example and a screenshot how it might look like in the backend: __fieldset('plain,textarea,rich,hello', 'jsStrings', 'Javascript Strings'); // $pages->get(1044)->functional->plain // how you would get it from anywhere in your templates and pages echo "<p>" . __text('your plain text', 'plain', 'Label Text for Plain Text String') . "</p>"; // $pages->get(1044)->functional->textarea // how you would get it from anywhere in your templates and pages echo "<p>" . nl2br(__textarea('your textarea text', 'textarea', 'Label Text for Textarea')) . "</p>"; // $pages->get(1044)->functional->rich // how you would get it from anywhere in your templates and pages echo "<div>" . __richtext('<p>your richtext</p>', 'rich', 'Label for WYSIWYG') . "</div>"; echo "<div>" . __richtext('<p>Hello Wörld!!!</p>', 'hello', 'Label for Hello World') . "</div>"; This is how it looks like in the backend. The big advantage imho is that you have the familiar user interface you're used to when you are also in charge of creating or editing PW-pages. It all seems familiar, and if you have a multi-lang setup, you can edit it all without page-reloads and navigating to another language.
    1 point
  29. If you want the customer to easily update the fields you can create a translate and translate_string templates. You will be able to easily create translations using pages ... Next, create function inside the _translate file to show translateable field title as in the movie, for example: <?php namespace ProcessWire; function trStr($page, $str) { $tr_page = pages()->get("/translate/$page/")->title; if($tr_page) { return $tr_page; } else { return $str; } } // Translate Strings page()->ts = [ 'your_awesome_string' => trStr('your-awesome-string', __('Your Awesome Strings')), ]; And display on the site: <h1><?=page()->ts['your_awesome_string']?></h1> You can download this profile from here:
    1 point
  30. I would probably do something like this: Have a "stats" page somewhere (hidden), with one big raw textarea field. Each visit would add one line to that field: 1234,guest,username,1535646198 = page-id,user-role,username,unix-timestamp You could get fancy and install a geo-IP-lookup PHP library and add lat/long infos as well. Instead of using a comma-separated list for each item, you could save it as JSON. But I guess this would mean a slight performance hint on a bigger site (the bigger it gets, the more time it takes to transform JSON into an PHP array, add one item, and use json_encode again). I've used a similar approach, when I played around with chatbots and certain API calls back and forth. It would be quite easy to output some sort of stats / infographics from such raw data. And of course easy to export it to Excel or somesuch... The only thing I would make sure and investigate some time before going that route: Check if there are some size-restrictions, i.e. how much data can actually be stored in a PW textarea field? Even this could be easily solved: Create a new stats-field for each year/month...
    1 point
  31. There‘ll certainly be a shift in what tools like google analytics need to be able to do in terms of preserving user privacy (and they already do), but I don‘t see anyone wanting to seriously build page counters in php again. Matomo (piwik) already exists and there are even new alternatives like fathom, which are already enough for simple needs.
    1 point
  32. Hi ... Here you should find a lot about the translations https://processwire.com/api/multi-language-support/code-i18n/ I do not know if this is the best solution, but it works for me ... Thanks to this, I do not have to search for translations in all of the template's peaks ... So I create a simple file responsible for all translations _translate.php Include this file inside _init.php include_once('./_func.php'); include_once('./_translate.php'); And define in the table as below <?php namespace ProcessWire; // Translate Strings page()->ts = [ // Language => locale / code prefx 'locale' => _x('en_US', 'HTML locale code'), 'lang_code' => _x('en', 'HTML language code'), // Main Page ( main.php ) 'site_name' => __('Your Site Name'), 'logo_alt' => __('Show My Awesome Logo'), // Archives Page 's_archives' => __('Select The Archives'), 'date' => __('Date'), ]; Then you can call globally using page() <h1><?=page()->ts['site_name'];?></h1> And there is a pro option Functional Fields: https://processwire.com/blog/posts/functional-fields/ But I can not say too much about it because I have not tested it but it looks interesting ?
    1 point
  33. Thanks @adrian I think I got it sorted out. New version 1.0.4 is pushed.
    1 point
  34. Looks like there are lots of other issues along the same lines. So far I have also come across trying to set the "twitter_params" option. It is not sticking because this line: $params = $this->get($item . "_params"); needs to be: $params = $this->options[$item . "_params"]; but there are lots of other instances like this as well that I think need changing. Thanks again.
    1 point
  35. "Is HTML Purifier configurable in PW?" I searched the forum for this a few days ago, and the answer to this question was: NO. We do need core support for this, preferably in the admin. And it is not just data- attributes, but a class attribute not set by CKE was stripped too in my case.
    1 point
×
×
  • Create New...