PrevProcessWire ProMailer now available
This week ProcessWire ProMailer has been released, plus we’ve got a nice upgrade in our community support forum, and more. More
This week we’ll take a detailed look at a few useful new API additions made in the last few weeks, along with examples of each.
Work continued in closing out issue reports this week. We’re down to about 60 of them now, though if we subtract issues that aren’t reproducible, are already marked as resolved (close pending), may be moved to the request repo, or are a discussion (rather than something to fix), then we’re closer to half that number. Over these last few weeks we’ve been working on issue reports, but I’ve also been enhancing the core in small ways as well. This post will cover a few of the useful enhancements that have been made in recent weeks.
When I released ProMailer a few weeks ago, one of the feature requests was to have a blacklist of email addresses that should not be allowed to subscribe or be sent email, ever. As it was explained, there are laws in some parts of the world where laws are pretty strict and you have to be careful to prevent emailing some addresses or entire domains. Given that, I thought it made sense to have this built into the ProcessWire core rather than just in a module. After all, if those email addresses are never supposed to be emailed, you don’t want to be sending them any email, regardless of which module it comes from. For instance, you wouldn’t want LoginRegister sending them a “confirm your account” email, nor would you want FormBuilder sending them an auto-responder… just two examples of many.
With the above in mind, the $config->wireMail
setting has been updated to contain a “blacklist” property. This property is an array that contains email addresses or email matching rules. WireMail looks at these rules every time you add an email address $mail->to('email@domain.com');
and refuses any that match blacklist rules.
The blacklist rules are best described by example. Below is how it might appear in your /site/config.php file:
$config->wireMail('blacklist', [
// blacklist this email address
'email@domain.com',
// blacklist all emails ending with @host.domain.com
'@host.domain.com',
// blacklist all emails ending with @domain.com
'@domain.com',
// blacklist any email ending with domain.com (would include mydomain.com too).
'domain.com',
// blacklist any email at any host on domain.com (domain.com, my.domain.com, but NOT mydomain.com).
'.domain.com',
// blacklist any email containing “xyz”. PCRE regex assumed when "/" is used as opening/closing delimiter.
'/xyz/',
// another example of using a PCRE regular expression (blocks all "@really.bad.com").
'/.+@really\.bad\.com$/',
]);
Here’s how you can test out your blacklist rules:
$email = 'somebody@bad-domain.com';
$result = $mail->isBlacklistEmail($email, [ 'why' => true ]);
if($result === false) {
echo "<p>Email address is not blacklisted</p>";
} else {
echo "<p>Email is blacklisted by rule: $result</p>";
}
WireMail automatically uses the blacklist rules in 3.0.129 and newer. Third party WireMail modules should also automatically use them as well, unless they have overridden the “to()” method logic. I didn’t find any WireMail modules where this was the case, but just to be safe, you should double check before assuming it works. You can do this by temporarily adding similar rules that match your own email address and then confirming that it works (or rather, doesn’t work—as in, doesn’t email the address).
This is one of my personal favorites in terms of recent additions. If you’ve used the $files->render() method or the function version of it called wireRenderFile(), then you might like the new $cache->renderFile() method. It does the same thing as $files->render() (rendering any PHP file as a template file with all API variables, etc.) except that it caches the output so that it doesn’t have to re-render the same file until your cache expiration rules take effect.
I added this method because I was repeatedly building combinations of $files->render(), $cache->get() and $cache->save(), and have been looking to do it with much less code. I also wanted a solution which would be aware of changes to the source file, and my previous combination of method calls couldn't easily accomplish that.
Unlike caching the result of a $files->render() method yourself, if you make any changes to the file you asked it to render, it automatically expires the cache and re-renders the file, generating the new cache. This makes it very friendly to use, as caching is never likely to interfere with development changes.
This method is very convenient for rendering expensive partials in your site like big navigation lists, or anything that takes some horsepower to render due to loading lots of pages and/or producing lots of resulting markup. I’ve found this method particularly helpful on the current processwire.com website for caching our primary navbar and offcanvas navigation, as well as category dropdown and lists that appear in the Showcase and Blog.
// render primary nav from site/templates/partials/primary-nav.php
// and cache for 3600 seconds (1 hour)
echo $cache->renderFile('partials/primary-nav.php', 3600);
The file you give it can be a full path to a file, or it can be relative to the current work directory (which would typically be /site/templates/ when on the front-end). Though when in doubt, use the full path. The second argument ($expire) is the expiration time. You can specify any of the following for this argument:
WireCache::expireNever
to prevent expiration.WireCache::expireSave
to expire when any page or template is saved.WireCache::expireDaily
.There’s also an optional 3rd argument for an $options array. There are several options here, but the one you might be most likely to use is the “vars” option. This lets you bundle in some variables to send to the file being rendered. They become locally scoped variables just like the existing API variables that are received by the file.
If you are already using $files->render() or wireRenderFile(), then you can also access the cache functionality using either of those existing functions and specifying a “cache” option in the $options argument, where the value is one of the $expire argument options specified above.
You may be familiar with the $datetime->relativeTimeStr() method which has been in the core for quite a long time (and one that I use quite a lot). However, I sometimes have the need to compare two relative times to each other (showing the difference) rather than just one time relative to the current. I’m guessing some of you have had a similar need. That’s where the new $datetime->elapsedTimeStr() method comes into play. It takes two dates/times rather than just one, and gives you the difference in a nicely formatted value .
Like the relativeTimeStr() method, the elapsedTimeStr() includes the ability to adjust the length of the output according to how much abbreviation you want. Depending on what abbreviation type you choose, it uses the same translations as wireRelativeTimeStr(). Though it also supports digital output, which is commonly used for showing stopwatch-style elapsed time.
Here are some examples of calls and the resulting output below. First, lets define an array of times to test where the keys are the start times and the values are the stop times. We'll use a few different formats just for demonstration purposes:
// start and stop times $times = [ // start time => stop time "2019-04-10 11:06 AM" => "2019-04-12 3:26 PM", "12 April 2019 7:00 AM" => "12 April 2019 1:15 PM", "-99 MINUTES" => time(), 30 => 3600, // can also be a quantity of seconds like this ];
Now let's call the elapsedTimeStr() method for each of those start/stop times above, and experiment with the $abbreviate argument to demonstrate different outputs:
foreach($times as $start => $stop) { $a = [ $datetime->elapsedTimeStr($start, $stop), // default (verbose) $datetime->elapsedTimeStr($start, $stop, true), // abbreviated $datetime->elapsedTimeStr($start, $stop, 1), // very-abbreviated $datetime->elapsedTimeStr($start, $stop, 0), // digital clock ]; echo "<h2>$start => $stop</h2>"; echo "<ul><li>" . implode("<li>", $a) . "</ul>"; }
Here's the resulting output:
2019-04-10 11:06 AM => 2019-04-12 3:26 PM
12 April 2019 7:00 AM => 12 April 2019 1:15 PM
-99 MINUTES => 1555081805
30 => 3600
Thanks for reading and I hope that you have a great weekend! Be sure to visit the ProcessWire Weekly this weekend for the latest and best ProcessWire news too.
15 March 2019
This week ProcessWire ProMailer has been released, plus we’ve got a nice upgrade in our community support forum, and more. More
19 April 2019 3
Quietly and without interruption this week, our whole website moved from a single static server to a load-balanced multi-server environment, giving us even more horsepower and redundancy than before. More
“ProcessWire is like a breath of fresh air. So powerful yet simple to build with and customise, and web editors love it too.” —Margaret Chatwin, Web developer
Ivan
Does $cache->renderFile() method works with direct output $files->include() ?
Reply