Leaderboard
Popular Content
Showing content with the highest reputation on 01/28/2020 in all areas
-
This is an update about how it's been running blog sites using ProcessWire. I hope it's OK for me to post in this category even though I've already showcased my sites awhile back. I thought it would be helpful for people to get a feel for what it's like to use ProcessWire on an ongoing basis for blogging. Often people talk about the development of a site, but it's not quite as often that we hear about the ongoing running of a PW site and how the PW API influences that, which is what I'll cover here. As background, we at The GrayFly Group own and run the blogs goodkidsclothes.com and flipfall.com. The development of these PW sites has been covered in a showcase thread for GoodKidsClothes and another for FlipFall. Here are some of the unique experiences I've had running these two sites. "Running" covers everything from coding and making modifications to the templates, to writing our articles, to interacting with ad partners or with others seeking us out for something related to one of those sites. So this is a different experience from agencies who develop for others; we develop for ourselves. As background, the main traffic to the websites comes from organic search results. Income from sites is from affiliate marketing and advertisements. GoodKidsClothes PW experience: "to think it is to do it." For GoodKidsClothes.com, one of the things we noticed was that if we could think it, we could do it, thanks to the easy-to-use PW API. The need for a change Here is a concrete example of what I mean: we noticed that many people would enter the site on an older article (e.g. via a search result). However, we continually put out a lot of time-sensitive information, e.g. a style guide, a piece of news relating to a change in a children's clothing company, etc. I didn't want people to miss out on this, yet many were, because after reading their entry page, they'd leave. They had no idea (unless they clicked on the link to home page) that there was another article that could be of value to them. All too often, by the time people learned about that new article via search results, they'd be too late for the news to be relevant - in fact, it wouldn't even be the newest article anymore by that point. The solution So, using the PW API, we modified the article template so that if someone was reading any article that was not the most recent article, then at the end of what they're reading, they'd see a small section highlighting the most recent article. Here is a screenshot: As you can see above, our newest article is highlighted immediately below the article they're reading, unless of course they are already reading the newest article. In the case shown above, the newest article (recipe-related) did not happen to be time-sensitive, but in most cases that article would be time-sensitive, so that's why we made this change. To make the change we simply used the PW API to query what the latest article was and store its identity in a variable - those sorts of queries we set up in _init.php. Then we modified the article template such that if the current page was not the latest article, to include the featured box that you see above. Another need for a change You'll also notice links in boxes above and below where the featured article box is. These are ads (they blend OK right?!) These ads brought another problem to our attention: we'd put the ads blocks on all articles equally. However, in the case of the most recent article, often the most recent article would usually have a time-sensitive offer or some other call to action e.g. signing up for our newsletter (well, not in the case of the recipe article above, but in most cases the latest article would have something we prefer the reader to do). We didn't then want our readers to get distracted by the ads and either leave the site, or click on an ad and click away from the site, instead of doing whatever the call to action is. The solution Again using the ProcessWire API, we modified the "article" template so that there was conditional logic on the ads: if the current page is not the latest article, include the ad code (otherwise no ads). This mean no ads were seen on the most recent article, allowing for less distractions to the reader on time-sensitive articles and more likelihood of them following through on the call to action. Conclusion for GoodKidsClothes We were able to make all these changes within minutes of thinking of them! In-house, without a ton of knowledge of programming, thanks to the awesome ProcessWire API. We actually made all those changes live, i.e. going in there and making changes to the code of the site as its running live. Yes, we had backups of the entire site and we always first save a copy of the template file under a different name (usually prefixing it with OLD_ ) before modifying the live version. This is how helpful ProcessWire is. We can make changes that benefit our site and make them in-house as we think of them. If this was done under some other CMS, we would be unable to make those changes without either a) hiring a developer or b) training up in whatever the other CMS is to make the changes in-house. Either way, it would take considerably more time to do anything. So, despite not having a formal programming background, we now have a very "nimble" site that we can adapt as needed to changes that we desire, within minutes of thinking of the change we need, with only needing to know a little PHP, html, and CSS, just the very basics, and looking up the PW API. FlipFall PW experience: "the answer is yes." In the case of FlipFall, there have been times when a potential ad partner asks a question like "can you put different ads on different categories?" or other things. Sometimes they are questions I ask myself of the website "Can we do A/B testing of different ads; i.e. show a certain ad block 50% of the time totally randomly and another ad block the other 50% of the time?" "How about ads from this company some of the time and a different company other times?" The answer is always "yes." Coming from other CMS's (that I used but did not program with) I used to brace myself a bit if I saw an email that asked "Can you....?" but now thanks to ProcessWire I don't have that bracing reaction any more. So long as I can think of a way to do it (and so far I always have, thanks to the PW API), I can say "Yes we can." More to the point, I can actually say "Yes, we can make those changes in-house within [whatever brief timeframe I think it will be]" instead of having to be vague about timeframes because of needing a developer. So I no longer worry about "Can you ...?" questions because the answer is yes. Overall conclusions ProcessWire is a superb CMS for those who own and run a site. The PW API makes it easy to make changes to the look and functionality of the site as needed. Such modifications wouldn't easily be possible on alternative CMS's that are heavily "theme-based".7 points
-
Just a heads up, I hope this might save someone some time in the future. TL:DR> It's taken me hours to work out that Apache version 2.4 <If> statements are broken when trying to do regular expression matches against the %REQUEST_URI variable. Try matching against the variable called %THE_REQUEST instead - but be careful with your regex. Background: I've been trying to add more relaxed CSP headers for the admin portion of one of my PW sites because my default, strict, CSP headers stop some admin features from working properly. After diving in to Apache2 regexs and conditionals, I thought I had the answer with this... <If "%{REQUEST_URI} !~ m#^/admin/?#i"> # CSP headers for external visitors. Header set Content-Security-Policy "<strict policy for public site>" </If> <Else> # CSP headers for admin visitors. Header set Content-Security-Policy "<lax policy for admin>" </Else> ...but I couldn't make it work. After experimenting for several hours I found that the regex shown above does work if you limit it to a single-character match; which is essentially useless for determining if we are in the admin interface. However, you can achieve a useful match with the following... <If "%{THE_REQUEST} !~ m# /admin/?#i"> ... </If> <Else> ... </Else> ...which checks verses the entire HTTP request line made to the server. This block can go in your vhosts file or in the site's .htaccess file. Here's the Apache documentation: https://httpd.apache.org/docs/current/expr.html and it seems I'm not alone in having this issue: https://serverfault.com/questions/940953/apache-if-statement-not-working?noredirect=1&lq=1 although neither of these links had workable solutions for me.5 points
-
For CK Editor fields, I always use the option to force pasting text as plain text. This strips any markup and formatting when pasting, it has prevented so many headaches for me ... It does mean that you can't paste formatted text even if you know what you're doing, but this way no weird formatting from Word can make it into the source code. You can activate this option through the Custom Config Options for the CK Editor field: forcePasteAsPlainText: true I'm not sure that will remove the extra non-breaking space (the paragraphs get added by CK Editor, so you only need to get rid of the NBSP), but it's worth a try and it does deal with most problems when pasting from Word.4 points
-
During a recent maintenance routine we found that our website's database (1,700+ pages) had thousands of instances of unnecessary, garbage code that had come with copied text from Word. Passages with margins expressed in points, cms and inches, and some that were wrapped in upwards of 7 spans were among the most easily identified crimes. Purging all of this dropped our database size by over 4%. A few of the code examples above nuke all inline styles, which will impact some important out-of-the-box functionality for PW3 and CkEditor (depending on your use); specifically with many of the options with tables and lists, such as setting a column width or changing the bullet styles within a nested list. To work around that, I made some changes to Ryan's code to target specific tags and to eliminate spans (which you can only add via Source view without pasting them in). $wire->addHookAfter('InputfieldCKEditor::processInput', function($event) { $inputfield = $event->object; $value = $inputfield->attr('value'); if ((strpos($value, 'style=') === false) && (strpos($value, '<span>') === false)) return; $count = 0; $qty = 0; // Optional remove spans $value = preg_replace('/<span.*?>/i', '', $value, -1, $qty); $value = preg_replace('/<\/span.*?>/i', '', $value, -1); $count = $count + $qty; // Remove inline styles from specified tags $tags = array('p','h2','h3','h4','li'); foreach ($tags as $tag){ $value = preg_replace('/(<'.$tag.'[^>]*) style=("[^"]+"|\'[^\']+\')([^>]*>)/i', '$1$3', $value, -1, $qty); $count = $count + $qty; } if(!$count) return; $inputfield->attr('value', $value); $inputfield->trackChange('value'); $inputfield->warning("Stripped $count style attribute(s) from field $inputfield->name"); });3 points
-
UPDATE 2020-01-28 I just added the Snipcart "Custom Order Fields" feature! Thank's @Noboru & @d'Hinnisdaël & @szabesz for your help and hints! Custom order fields can be added/configured by editing a hidden config page under Admin > Setup > SnipWire > Custom Cart Fields. The corresponding template/page/field resources are preinstalled by SnipWire installer. If you update to the new module versions, those resources will be added too! The config page has a single textarea field where you can add the configuration strings for your custom cart fields: (multi language support is also available) ... can also be edited and enabled/disabled from within SnipWire module config. The config from the screenshot above leads to the custom step "Order Info" in checkout process: The Snipcart docs for Custom Order Fields (v 2.0) can be read here: https://docs.snipcart.com/v2/configuration/custom-fields Next step is to implement custom product fields! When this is done, I'll release the first official version. SnipWire will then be added to the ProcessWire module directory (as far as @ryan accepts it).2 points
-
The response I was going to give is aptly summarised by @gornycreative (quoted below...) It would be a nightmare to keep track of global freight. We will provide hooks on our side to facilitate this. However, whilst we will strive to cater for different scenarios, we will prioritise making sure the API works for the bigger providers first and/or the most popular (with respect to our client base). Please note that this (and other advanced features will be incrementally added to Padloper 2 but will certainly not make it in the first release). This is not currently planned. It might make it on my to do list for future releases, depending on demand. No. This is not planned. It might be considered depending on demand, though. Thanks! ?2 points
-
One field for each role could cause problems, because a new user might have more than one role. Then: which message do you send? All of them? You would need some complicated conditional logic in the UI. Not all that easy.1 point
-
Wow, @adrian – that looks good, it might be exactly what I need for my client. I’ll chedk this out in the next few days. Do you have a small hint in which format I set line breaks? $u->emailMessage = "Hello {name}\n\nwelcome to the show"; or better this way? $u->emailMessage = 'Hello {name} welcome to the show';1 point
-
Thank you! That worked perfectly. I new I was missing something! Just for completeness here's my resulting code for now: // Prepare and output body text (cleans <p> tags with inside) $bodyCopy = preg_replace('/<p>\x{00A0}<\/p>/u', '', $page->body); echo $bodyCopy;1 point
-
Ok, in that case you can still filter out the unnecessary paragraph with the non-breaking space inside. Your str_replace function probably doesn't work because you are trying to replace the literal string . That won't work because the non-breaking space is (most likely) stored inside the database as a Unicode character, not as the HTML entity. Matching "<p> </p>" won't work either, because that is a regular space, not a non-breaking space. To replace the non-breaking space, you can use a regular expression and match the specific NO-BREAK SPACE Unicode character. This works for me: $string = "<p> </p>"; $string_unicode = html_entity_decode($string); // $string_unicode now contains a non-breaking space unicode character echo preg_replace('/<p>\x{00A0}<\/p>/u', 'Successfully replaced!', $string_unicode); // Successfully replaced! Make sure to include the u flag to treat the string as UTF-8. You could also modify this to match multiple non-breaking spaces or whatever CK Editor throws at you ? You can use that either to remove the superfluous paragraph in your template output, or write a little script to convert the text saved in the database (which is the cleaner way to go, if you ask me).1 point
-
This works just fine: $input->cookie->set("foo", "bar"); // set the cookie d($input->cookie->foo); // get it you're printing out $c, which is the set command.1 point
-
Update: Menu Builder 0.2.7 Changelog Added the property extra_fields for use with getMenuItems() ONLY. This enables returning the page field values for some selected Fieldtypes. For example, the description field in the page corresponding to the menu item. Thanks @e0f for the inspiration. Full documentation of this new feature is available here. Menus in multi-lingual sites can now be called using their multi-lingual titles or names irrespective of the current user's language. For example, a multi-lingual site with English, German and Finnish languages could have a menu with the respective titles My Awesome Menu / Mein Tolles Menü / Oma Mahtava Valikko. Any of these titles can be used in the code to call the menu (using render() or getMenuItems() methods). [PS: blame you-know-who for these language translations :-)] Changed the way new menus are added. Only one menu can be added at a time. The title field/input is multi-lingual ready. See screens below. Improved the backend GUI when viewing locked menus. Only the menu items and and exit button are shown in such cases. Fixed bug that allowed access to unpublished menus for frontend rendering. Updated the documentation Refactored code to improve efficiency. In dev branch only for testing. Screenshots a. Add Menu (Multi-lingual) b. Edit Menu (Multi-lingual) c. Locked Menu d. An example usage of extra_fields (I am no designer, so yeah, nothing much to see here...but you get the idea :-)) Thanks for testing!1 point
-
Maybe not what you need, but could be worth looking at the new module Dashboard?1 point
-
1 point
-
Looking forward to when the good news comes! ?? As @Pete said earlier, if you need anyone to test it out, give us a shout.1 point
-
I know this sounds super easy, and for one provider it sortof is. The issue might be that updating and keeping track of freight APIs for everyone would become a costly development project in itself. Might make more sense to provide API hooks that can be used to push to services like IFTTT or Zapier and see if they already have connectors to postal service APIs. Same goes for accounting bits. I know Xero has Zapier integration: https://zapier.com/apps/xero/integrations This whole vertical integrations issue is something X-Cart and CS-Cart struggled with for a long time, most clients in the meantime ended up opting to work with ShipStation if they had complex freight calculation requirements - they passed the freight on to a piece of software dedicated to the task. I think they had a tax tool integration also to handle various tax jurisdictions, etc. which is also fun. https://www.shipstation.com/developer-api/#/introduction/shipstation-api-requirements/server-responses or (as we ended up doing) doing direct integration because we had simple vertical distribution (FBA) and Amazon controlled the rates - which got a little more complicated once we needed to have separate FBA accounts for different regions, different inventory counts for different FBA accounts, and different shopping locales. To make things nuttier, CS-Cart recently added in warehousing which is let's you balance inventory between multiple freight locations: https://blog.cs-cart.com/2019/11/07/meet-cs-cart-4-11-1-with-warehouses-and-other-improvements/ I haven't gone through the nuts and bolts to see how box count, product distribution per box per order, warehouse location for boxes and freight accounts for warehouse locations all work together in a multi-vendor e-commerce package. I imagine it is trying to run a synchronized swimming routine with farm animals.1 point
-
@Gadgetto There is no problem with getting pages with the name field. Just use default language value as selector value. Getting page by name has some pitfalls, $pages->get() return the first found page, but you can have several pages with the same name under different parents, so you should specify parent selector to make sure that you are looking for the needed page. So basically you can use this in English and Deutsch languages d($lang->title); // english d($pages->get("name=sample-page")->title); // Sample page $user->language = $languages->get('deutsch'); // change user language to deutsch d($pages->get("name=sample-page")->title); // beispiel-seite But if you want to find your page by Deutsch name: $lang = $languages->get('deutsch'); get deutsch language d($lang->title); // deutsch d($user->language->title); // english d($pages->get("name{$lang}=beispiel-seite")->title); // beispiel-seite1 point
-
I've run into this problem on a client site before. I was never able to duplicate it myself, but noticed there were style attributes ending up in the CKE field of my client's site somehow, and the client said they pasted from Word. I don't have Word, and I'm not observing the issue occurring with pasting from anything else, so there must be some Microsoft trickery going on, who knows. I don't understand why CKE's ACF allows it. It does seem like a CKE bug. I'm sure it's possible to configure HTML Purifier to remove that stuff, but haven't looked too closely into it. While there is a way to force CKE to paste as plain text (see thread that flydev linked), I don't really like losing links and normal CKE formatting when I paste, because I'm often pasting from one CKE field to another, and having to redo all the formatting is a pain. Usually if I want to paste as plain text, I just use SHIFT-CMD-V on Mac (SHIFT-CTRL-V on PC), as this is a pretty universal way to paste as plain text, anywhere. But the reality is, clients aren't likely to remember it, and many are doing Edit > Paste, rather than using the keyboard. I'd rather not have the client have to think about whether they need to use plain text pasting or not. A simple way to remove style attributes from CKE fields is to hook after the process input, look for them, and then remove them. This hook at the top of your /site/templates/admin.php file should do the trick: $wire->addHookAfter('InputfieldCKEditor::processInput', function($event) { $inputfield = $event->object; $value = $inputfield->attr('value'); if(strpos($value, 'style=') === false) return; $qty = 0; $value = preg_replace('/\bstyle=(["\'])([^\1]+?)\1/i', '', $value, -1, $qty); if(!$qty) return; $inputfield->attr('value', $value); $inputfield->trackChange('value'); $inputfield->warning("Stripped $qty style attribute(s) from field $inputfield->name"); }); Word may be adding some other weirdness too, but I don't have a good example to look at to know what else there might be (MSO-specific class names?). In any case, we could probably remove it in a similar manner.1 point
-
Here's some more info: https://github.com/ryancramerdesign/ProcessWire/issues/1613 ryancramerdesign commented Language fields fallback to default when a localized version isn't available. This is one case where you may want to retrieve the localized value programatically. $value = $page->get('mytablefield' . ($user->language->isDefault() ? '' : '_' . $user->language->name));1 point