Leaderboard
Popular Content
Showing content with the highest reputation on 07/28/2020 in all areas
-
Ryan might've had other reasons as well, but... this keeps the textformatter from making a mess out of user-generated content where video URLs could be used in links, within regular text, inside table cells, in image captions, etc. ? That being said, it'd be nice if the module provided a public method for converting known single video URL into an embed code. Currently it looks a little hacky: $url = '<p>https://www.youtube.com/watch?v=ytWz0qVvBZ0</p>'; $modules->get('TextformatterVideoEmbed')->format($url); echo $url;3 points
-
@Zeka Thanks for the examples. Reading what you write made me realize I've got a similar case too: https://www.tripsite.com/reviews/ — it's just one page, but hundreds (maybe thousands) of URLs underneath are all URL segment powered for 3 levels. What you are asking for would come in handy here for sure. In the hook example below (which is functional) I clear all /reviews/bike-tours/* segments on the /reviews/ page when a page using template "tour" is saved. And when a page using template "boat" is saved, it clears all of the /reviews/boat-[name]/ segments, where [name] is the name of the boat page that was saved. This is going to come in very handy here, and if I understand your case correctly, I think it's what you are looking for also? $wire->addHook('ProCacheStaticClear::clearedPage', function($event) { $page = $event->arguments(0); // Page that was saved/cleared $clearSegment = ''; if($page->template == 'tour') { // clear all /reviews/bike-tours* segments $clearSegment = 'bike-tours*'; } else if($page->template == 'boat') { // clear all /reviews/boat-name/ segments $clearSegment = "boat-{$page->name}*"; } if($clearSegment) { // clear segments below the /reviews/ page $reviews = $event->pages->get('/reviews/'); $event->object->clearPage($reviews, [ 'urlSegmentStr' => $clearSegment ]); } });2 points
-
Whilst I appreciate the inherent advantages, I'd like to point out that the forum rules/guidelines currently don't allow this. Edit I see @teppo beat me to it :-)2 points
-
Just an observation from "an outsider": folks who are not competent in German might still need a German language pack for their projects. It'd be a little difficult to figure out what's going on if the discussion related to said language pack was in German as well. Also, forum guidelines state that the language here is English — though personally I don't think it's going to be a major issue if you do decide that German would be better (in this specific context, based on a good reason; the key point being that it would be an exception to the rule) ?2 points
-
Some fresh sounds I discovered recently. I didn't know I'd like this Synthwave music but... can't get anything done without it. Whole YT Channel: https://www.youtube.com/channel/UCmYTgpKxd-QOJCPDrmaXuqQ Some more on Basecamp. If you loved Stranger Things (Netflix) you will probably like this too. https://synthwavecafe.bandcamp.com/album/stranger-things-tribute2 points
-
Hello, I'm very new to ProcessWire but already fell in love with this CMS/CMF! I just finished my first small project and as I saw a lot of questions and different answers in this forum on how to set up a nice language switcher for your website, I decided to write my first tutorial. ---------- Please note: I rewrote this tutorial since I was made aware and learned that flags should not be used for language selectors! There are some threads here in the forum (and from external sources) where this question is discussed: https://processwire.com/talk/topic/13196-adding-image-field-to-language/ http://daily.unitedlanguagegroup.com/stories/editorials/inside-design-language-selector-no-flags https://processwire.com/talk/topic/16524-extending-languages-template/ http://www.flagsarenotlanguages.com/blog/why-flags-do-not-represent-language/ https://processwire.com/talk/topic/14241-language-names-and-utf8-page-names/ Thanks, @ottogal @bernhard @jmartsch @kongondo an all others for your hints! ---------- TUTORIAL - Set up a nice language switcher for your website - here we go: This will be the desired result! Step 1) Setup at least 2 languages in your PW install. In my case it's German (default language) + English: Step 2) Add a custom field Type = Text Name = languagecode This will hold the ISO 639-1 two-letter language code for the respective language. The field is needed to provide a simple method for outputting the language code in your templates. Without this field, you will need to programmatically construct your two-letter language code output via PHP (at least for the default language, as ProcessWire doesn't allow to rename the default language and it will always be called default). Here is an overview for ISO 639-1 two-letter language codes: https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes Step 3) Add this field to the system template: language. To achieve this, go to Setup / Templates and activate the filter Show system templates: Now you can add the previously created field languagecode to the language template. Step 4) Edit your languages and fill in the appropriate values. a) default (German) Name = default (this can't be changed and is read only) Title = Deutsch (in both language tabs! - this is important as your visitor should always see his language item ... in his language) languagecode = de b) english (English) Name = english Title = English (in both language tabs! - this is important as your visitor should always see his language item ... in his language) languagecode = en Step 5) Now we are ready to write our template output! As we already have the appropriate two-letter ISO language code (languagecode field), we can use this in our html lang property: <html lang="<?php echo $user->language->languagecode; ?>"> Also the rel alternate output in the html head is simple. Put the following code within your <head></head> area: <?php // Handle output of 'hreflang' link tags for multi-language (SEO!) foreach ($languages as $language) { if (!$page->viewable($language)) { continue; } // Get the http URL for this page in the given language $url = $page->localHttpUrl($language); // Get the language code using custom languagecode field $languagecode = $language->languagecode; echo PHP_EOL.'<link rel="alternate" hreflang="'.$languagecode.'" href="'.$url.'">'; } ?> In my sample I've used Boostrap 4 and the code below shows a complete navbar with our language switcher (BTW the language switcher will always be visible, even when the bootstrap navbar is collapsed): <nav id="mainnav" class="navbar navbar-expand-lg navbar-light px-4 px-md-5 sticky-top"> <a class="navbar-brand" href="<?php echo $config->urls->root; ?>"> <img src="<?php echo $config->urls->templates; ?>images/logo-rund-80x80.png" alt=""> Your Site Title </a> <ul class="navbar-nav ml-auto mr-3 mr-lg-0 order-lg-last d-none d-xs-custom-flex language-switcher" aria-label="<?php echo __('Sprache wechseln') ?>"> <?php echo '<li class="nav-item dropdown">'; // Construct the language prompt in the current user language $prompt = $user->language->title.' ('.strtoupper($user->language->languagecode).')'; // Current language = dropdown-toggle echo '<a class="nav-link dropdown-toggle" href="#languages" id="language-select" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">'; echo '<span class="world-icon"></span><span class="sr-only">'._x('(aktuelle Sprache)', 'navigation').': </span> '.$prompt; echo '</a>'; echo '<div id="languages" class="dropdown-menu dropdown-menu-right" aria-labelledby="language-select">'; foreach ($languages as $language) { // Get the http URL for current page in the given language $url = $page->localHttpUrl($language); // Construct the language prompt in the given language $prompt = $language->title.' ('.strtoupper($language->languagecode).')'; // Next language item (except current language) if ($user->language->id != $language->id) { if (!$page->viewable($language)) { echo '<span class="dropdown-item disabled">'.$prompt.'</span>'; } else { echo '<a class="dropdown-item" href="'.$url.'">'.$prompt.'</a>'; } } } echo '</div>'; echo '</li>'; ?> </ul> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarMainMenu" aria-controls="navbarMainMenu" aria-expanded="false" aria-label="<?php echo __('Menü einblenden / ausblenden') ?>"> <span class="navbar-toggler-icon"></span> </button> <div class="collapse navbar-collapse my-3 my-lg-0" id="navbarMainMenu"> <ul class="navbar-nav mr-auto"> <?php // Top navigation consists of homepage and its visible children foreach ($homepage->and($homepage->children("template=main-page|news|contact-points")) as $item) { if ($item->id == $page->rootParent->id) { echo '<li class="nav-item active">'; echo '<a class="nav-link" href="'.$item->url.'">'.$item->title.'<span class="sr-only"> '._x('(aktuelle Seite)', 'navigation').'</span></a>'; echo '</li>'; } else { echo '<li class="nav-item">'; echo '<a class="nav-link" href="'.$item->url.'">'.$item->title.'</a>'; echo '</li>'; } } ?> </ul> </div> </nav> That's it! I hope you will like my tutorial and if there are any questions, critics or improvements please let me know! Thanks, Martin1 point
-
We relaunched the website of German health insurance broker KLforExpats, who provide a service that is specifically tailored for expatriates in Germany. The website includes very extensive, completely custom-built forms for data entry and multiple custom interfaces for management and handling of requests. Concept, design, branding and development by schwarzdesign. If you are moving to Germany and need health insurance, KLforExpats is the contact for you! Read on below for some technical insights. Features A beautful, streamlined website including an extensive knowledge area (Expert Corner) Custom-built forms for initial contact and data collection A central database of clients / leads An analytics dashboard that displays key performance indicators based on the lead database A client / lead template with multiple workflow-related actions Automatic generation of Trello cards for new leads using the Trello API Notable modules Dashboard TrelloWire ProFields Hanna Code ListerPro Cacheable Placeholders Cache Control Automatically link page titles Unique Image Variations Regular shoutout to Tracy Debugger Building custom forms based on ProcessWire fields The forms on the site are built from scratch, which is a lot of work but opens up a lot of fine-tuning that isn't possible with form builder modules or services. There are a couple of interesting features of the form system we built. In particular, using built-in HTML5 features for form input and constraint validation makes developing simple, cross-browser and mobile-friendly forms a breeze. The forms make heavy use of modern input types and attributes. In particular, all date fields use the date input type, which is supported in all major browsers except Safari. This way, the forms come with good accessibility out of the box. A cleaner solution than using some rickety jQuery UI datepicker. Client-side validation is pure HTML5 as well. Since each form consists of multiple steps, the validation is triggered when the user tries to go to the next step. This is easily done by iterating through the inputs in the current step and calling reportValidity on them. The browser takes care of reporting errors – no need for a popup library. We use ProcessWire's field settings to generate field labels and validation attributes (like the required flag, minimum and maximum length settings etc.). This way, changes to the fields are always kept in sync between the frontend and the backend. For server-side validation, we used an open source library (rakit/validation). We added some custom rules to integrate it with ProcessWire's CSRF protection, a honeypot spam protection, and file uploads using WireUpload. This way, validation and error reporting can be done through a uniform interface. Using custom page classes as data models New leads are represented by ProcessWire pages. We ended up writing a lot of custom functionality for those pages – for example, automatically generating a vCard based on the contact information entered in the form. We used a custom page class as a nice way to group those methods and be able to call them from anywhere. <?php namespace schwarzdesign\Page; use Processwire\Page; class ClientPage extends Page { /*** methods here */ } Since each lead is a regular page, we used the regular page template to display all the data collected for this lead as well as to provide an interface to perform lead-related actions, like create form access keys, generate PDF protocols, etc. Since we use Twig as a templating layer, we ended up with a MVC-like approach, where the PHP-template is only used to call the appropriate methods of the ClientPage based on URL parameters. You can read more on the process and the client-facing functionality on the KLforExpats project showcase on our website (in German).1 point
-
A huge thank you to @Gadgetto for this tutorial. This is my first time with multi-language, and Gadgetto provided the perfect tutorial for beginners such as myself to learn from. I worked my way through the tutorial and can attest it works beautifully and I could follow along without getting lost. I now have a wonderful language switcher on my site AND the html lang tag AND the href lang alternate tags, all thanks to Gadgetto's great tutorial above. The screenshots were really helpful too. His code really should be a must-read for those making their first multi-language site. Thanks again! ?1 point
-
There are hints in this thread: https://processwire.com/talk/topic/7971-renaming-the-content-tab-when-editing-pages-of-a-given-template/ As mentioned there, this is a working, albeit very hacky solution: (content instead of view tab) // site/ready.php wire()->addHookAfter("ProcessPageEdit::execute", function($event) { $render = $event->return; $template_name = "basic-page"; // Change this to match the exact template name of pages you want to apply tab-renaming to. if (false !== strpos($render, "template_{$template_name} ")) { $render = str_replace("Content</a>", "Content is King</a>", $render); // EN $render = str_replace("Inhalt</a>", "Inhalt ist Kaiser</a>", $render); // DE $render = str_replace("Contenu</a>", "Le roi, c'est le contenu</a>", $render); // FR $event->return = $render; } });1 point
-
->first() doesn't work for the View tab - try it without and you should be ok.1 point
-
If you look at the first post in this thread, you can see that this module requires a specific format in the texarea ("Converts contents of textarea field..." etc.) If what you've pasted above is literally the contents of your textarea field, then it won't work with this textformatter. Note, though, that this module and Textformatter Video Embed are probably not compatible out of the box due to different format requirements. Depending on your use case you could perhaps use PHP's explode() or preg_split() to split the value of your textarea field into an array (which could then be used in foreach), but it also kind of sounds like a Repeater field would make more sense in this case.1 point
-
I think it would make the communication easier because we wouldn't need to switch between languages within one single sentence. But I don't really care ?1 point
-
Just to add a suggestion. This field can't be used as a condition for another field's visibility. It's an easy fix though, just have to add an ID to the field (matching the name) and it starts working.1 point
-
1 point
-
@Zeka I don't think we've got hooks specific to what you are trying to do there, but I've pasted in the list of current hooks that ProCache provides for the static caching side of things. Can you expand on your need with an example? It may be something I can add, though want to make sure I fully understand what you are trying to do. // Is caching allowed for given page? Return true or false // Hooks can modify return value to dictate custom caching rules ProCache::allowCacheForPage(Page $page) // Called when entire cache is being cleared // Returns quantity of items cleared ProCache::clearAll() // Called right before a cache file is written // Hooks can modify $content to adjust what is saved in cache file ProCacheStatic::writeCacheFileReady(Page $page, $content, $file) // Called right before a Page is about to have its cache cleared. // Hooks can make it return false to bypass clearing of page. ProCacheStatic::clearPageReady(Page $page) // Called to execute cache clearing behaviors for given Page // Hooks can modify what behaviors are executed ($behaviors argument) // Returns array indexed by behavior name each with a count of files cleared ProCacheStaticBehaviors::executeCacheClearBehaviors(Page $page, array $behaviors)1 point
-
Hi @sebr, happy to hear that ? Unfortunately, no. And I have no time to investigate. I can only share my experience: In my setups/modules I tend to use one single migrate() method now. Instead of having a migration for every version this approach just makes sure that after running migrate() you end up with the setup you want (fields, templates, pages). This is very easy using the RM migrate() method: $rm->migrate([ 'fields' => [ 'foo' => ['type' => 'text'], ], 'templates' => [ 'foo' => ['fields' => 'foo'], ], ]); Lets say in the next version I need a new field "bar", I'd just add it to that migration: $rm->migrate([ 'fields' => [ 'foo' => ['type' => 'text', 'label' => 'Foo Label'], 'bar' => ['type' => 'text', 'label' => 'Bar Label'], ], 'templates' => [ 'foo' => ['fields' => 'foo', 'bar'], ], ]); This makes it really easy to grasp the setup, because you have everything in one place and you don't need to go through every migration and try to understand the whole picture. The example above with the "old" approach would be: $rm->setFieldData('foo', ['label' => 'Foo Label']); $rm->createField('bar', ['label' => 'Bar Label']); $rm->addFieldToTemplate('bar', 'foo'); Not to forget that with the new approach you can diff your changes: Of course this comes with the drawback of a little less control and it can get tricky when multiple modules to migrations and one depends on the other. But then you can still split migrations up or do necessary changes upfront. Also removing things needs some extra lines of code, but still very easy ones: $rm->deleteField('bar'); $rm->migrate([ 'fields' => [ 'foo' => ['type' => 'text', 'label' => 'Foo Label'], ], 'templates' => [ 'foo' => ['fields' => 'foo'], ], ]); On uninstall I just do all the cleanup and that's usually as easy as deleting all templates and fields (because all pages get deleted automatically). I've never ever needed to run a downgrade method. I usually have a cleanup migration that just removes fields or templates that I created during dev and maybe even pushed to the live server and then I change something and dont need those fields any more (like the "bar" field above). RM is still not perfect. I had a chat with horst and I'd like to have logging and test-run capability, but for now this is what we have and it is saving me a ton of time and headache already and I can really not understand how anybody can work with ProcessWire without RM ?1 point
-
This is generated on the fly when a result is rendered. Behind the scenes Renderer::renderResultDesc() and Renderer::renderResultsJson() both get field values using Renderer::getResultValue(), which in turn calls Renderer::getResultAutoDesc _auto_desc "pseudo field" (as in: not a real field) is requested. There's currently no public API for accessing this directly, but if you've got a use case that can be solved by adding one, I wouldn't be against it. Though in that case I'd like to know a bit more about the context ? Sorry! Accidentally introduced a dependency for ProcessWire 3.0.160 in the Config class. This is now fixed: latest module version (0.25.1) provides proper fallbacks for core versions prior to that.1 point
-
Well now we're suddenly number 2.... We've been overhauled by Kirby! Kirby does seem super duper sexy though. The high level of flexibility and easy customization does seem quite PW like... But Kirby costs 99 euro per website... Some big guys like Harvard, NYT, Smaszhing mag, Philips and Mercedes Benz are using it... I think one of the main reasons people would go with it over PW is its very very sleek and sexy looking design. It's very appealing to the creative designer types (like myself). PW looks more old-school, developer oriented and technical, branding and UI-wise, compared to Kirby. I think we could really win a lot of new PW users if the design was more appealing. What do you guys think? Personally I really really don't like the PW CMS UI colour scheme. It seems outdated and not contemporary enough. I always use AdminThemeBoss and in my opinion it makes PW look sooooooo much more sexy, appealing, user friendly and gives a better overview. Should it be on the PW roadmap looking at Kirby and alike and make the PW UI more sexy / more contemporary looking per default? Oh yeah, and also it's flatfile making switching between dev and production so much easier. Maybe a flatfile db option should also be a future key sales point for PW? Best, Jonatan1 point
-
1 point
-
Seemed (loosely) relevant: ... and since @wbmnfktr mentioned synthwave earlier, I have to throw a bunch of actual favourites in: Scandroid, Zombie Hyperdrive, and Carpenter Brut. All synthwave music, but each band has its unique approach or "theme". Synthwave in general is a great fit with programming ?1 point
-
ryan had helped me a few weeks ago via PN. sorry that i didn't write the solution in the forum before. i hope it's no problem that i write the private message here.1 point
-
1 point
-
IMHO this should be the default behaviour of a PageTable field. Having the PageTable pages as children of the page is confusing for editors and I've never understood the reasons why that should happen as the default.1 point
-
Always "installed": AllInOneMinify ProcessImageMinimize/minimize.pw (of course ) ProcessBatcher (setting up the site structure for the first time) TextformatterOEmbed or the Youtube Embed Formatter ProCache1 point
-
Hey, there are a lot of modules using submodules recently which is great in my opinion because it underlines the way Processwire works. Examples are for example: Apeisa's Payment and Shipping modules, netcarver's new ProcessDiagnostic module and Adrian's ProcessMigrator. All of them are using more or less different approaches - abstract classes, etc - and I'm not sure which is best. But I think a core support for submodules could be a nice addition. One way to do it could be a "parent-module" setting in submodule's "module config" and a "getSubmodules" function in parent classes. Maybe you could add an abstract class like done with ConfigurableModule for this reason (e.g. ParentModule). Additionally apeisas way to use a abstract class would stay possible but wouldn't be necessary with this approach. What do you think? -- Nico1 point
-
Has anyone implemented the jQuery version of Paul Irish's Infinite Scroll script on a site built with ProcessWire? If so, I'm interested in reading about your experience and tips on how you implemented it. https://github.com/paulirish/infinite-scroll1 point
-
I'm using a nice variation of the infinite scroll http://www.fieg.nl/i...a-jquery-plugin This plugin it's really easy to use, it doesn't requires any particular modification in the code because it uses the pagination links to generate the infinite scroll, in this way also google is happy because I generate my content with pagination as usual and the users have the enhanced version.1 point
-
It is possible $field2 = $page->field2; $result = $pages->find("template=something, field1>$field2"); Edit: ah hehe, ok this is what you're looking for. $results = new PageArray(); foreach( $pages->find('template=something') as $p) { if($p->field1 > $p->field2) $results->import($p); } Anyway have you tried your version if it would work?1 point