-
Posts
311 -
Joined
-
Last visited
-
Days Won
8
Everything posted by nbcommunication
-
Hi @adrian, will be back in the office on Friday so will take a look then. Happy New Year to all when it comes! Chris
-
Hi @Jonathan Lahijani - I've just seen the open issue in Github, which should be resolved now. Are you still getting the issue above on this latest version?
-
Hi @ryan, Thanks for the new module! During the development of a module this week, I wondered whether it was possible to save module config data without the "modules" log being added to. I think this may be a useful addition as I'm finding that when I've got a log open in the admin and a new entry is generated and fetched with AJAX, UserActivity is saving config data (hookProcessWireFinished), and generating another "Saved module 'UserActivity' config data" entry. Perhaps there's a simpler tweak that could be made, e.g. checking if AJAX, but a quiet mode for saveModuleConfigData might be a good addition and solve this very minor issue! Cheers, Chris
-
Yep - that happens! Mac Mail was doing the same to me when testing last night.
-
Haha, up to version 1.1.6 now. I realised that ProMailer probably needs to use batch mode, so I've added some checks in the module config to set batch mode to on by default if it is installed.
-
Hi @adrian, I've made another update to the module. I've removed the inferring of "id" if addRecipientVariables() isn't used, as it was confusing and didn't really work anyway... I'm not getting the comma issue (also using Mac Mail), and multiple batches is working for me also - if it still persists for you after the latest update, please let me know and I'll debug further in the morning. I've added an example to the README which should hopefully explain batch sending/recipient variables a little more: // If using batch mode, the recipient variable "name" is inferred from the `to` addresses, e.g. $mg = $mail->new(); $mg->to([ "user@domain.com" => "A User", "user2@domain.com" => "Another User", ]) ->setBatchMode(true) ->subject("Message Subject") ->bodyHTML("<p>Dear %recipient.name%,</p>") ->send(); // to = A User <user@domain.com>, Another User <user2@domain.com> // recipientVariables = {"user@domain.com": {"name": "A User"}, "user@domain.com": {"name": "Another User"}} // bodyHTML[user@domain.com] = <p>Dear A User,</p> // bodyHTML[user2@domain.com] = <p>Dear Another User,</p> // Alternatively, you can omit the `to` recipients if setting `recipientVariables` explictly e.g. $mg = $mail->new(); $mg->setBatchMode(true) ->addRecipientVariables([ "user@domain.com" => "A User", // "name" is inferred "user2@domain.com" => [ "name" => "Another User", "customVar" => "A custom variable", ], ]) ->subject("Message Subject") ->bodyHTML("<p>Dear %recipient.name%,</p><p>Custom: %recipient.customVar%!</p>") ->send(); // to = A User <user@domain.com>, Another User <user2@domain.com> // recipientVariables = {"user@domain.com": {"name": "A User"}, "user@domain.com": {"name": "Another User", "customVar": "A custom variable"}} // bodyHTML[user@domain.com] = <p>Dear A User,</p><p>Custom: %recipient.customVar%!</p> // bodyHTML[user2@domain.com] = <p>Dear Another User,</p><p>Custom: A custom variable!</p> // %recipient.customVar% only prints for second email, so not a particularly useful example! // You can also use `addRecipientVariables()` to extend/override the inferred `recipientVariables` e.g. $mg = $mail->new(); $mg->to([ "user@domain.com" => "A User", "user2@domain.com" => "Another User", ]) ->addRecipientVariables([ "user@domain.com" => [ "title" => "A User (title)", ], "user2@domain.com" => [ "name" => "Another User (changed name)", "title" => "Another User (title)", ], ]) ->setBatchMode(true) ->subject("Message Subject") ->bodyHTML("<p>Dear %recipient.name%,</p><p>Title: %recipient.title%!</p>") ->send(); // to = A User <user@domain.com>, Another User (changed name) <user2@domain.com> // recipientVariables = {"user@domain.com": {"name": "A User", "title": "A User (title)"}, "user@domain.com": {"name": "Another User (changed name)", "title": "Another User (title)"}} // bodyHTML[user@domain.com] = <p>Dear A User,</p><p>Title: A User (title)!</p> // bodyHTML[user2@domain.com] = <p>Dear Another User (changed name),</p><p>Title: Another User (title)!</p> Cheers, Chris
-
Hi @adrian, Ah bugger, I'll see if I can figure that out... As I understand it, WireMail calls should always use to() to set the recipients. However, it does make sense to allow for recipients to be set from addRecipientVariables(), as this prevents repetition should you want to set custom variables (id and name are the ones inferred from the "to" recipients). Hopefully this example makes some sense of that: $to = array(); $recipientsArr = array(); foreach($recipients as $u) { if($u->$email) { $name = $u->first_name . ' ' . $u->last_name; $to[$u->email] = $name; /* If addRecipientVariables() isn't used, the recipient variable is inferred as: $recipientsArr[$u->$email] = array( 'id' => $i++, // index increment (%recipient.id% in bodyHTML) 'name' => $name, // (%recipient.name% in bodyHTML) ); */ $recipientsArr[$u->$email] = array( 'id' => $u->id, 'toName' => $name, // (%recipient.toName% in bodyHTML) ); } } // Previous usage $mailer = $mail->new(); $mailer->setBatchMode(true); $mailer->to($to); $mailer->addRecipientVariables($recipientsArr); $mailer->from('me@google.com', 'My Name'); $mailer->subject($newsletter->title); $mailer->bodyHTML($message); $numSent = $mailer->send(); // Now simplified, no need for to() $mailer = $mail->new(); $mailer->setBatchMode(true); $mailer->addRecipientVariables($recipientsArr); $mailer->from('me@google.com', 'My Name'); $mailer->subject($newsletter->title); $mailer->bodyHTML($message); $numSent = $mailer->send(); // After the next update, records in $recipientsArr above must contain a value for either "name" or "toName" // for this to be set as the "to" recipient name, e.g. $mailer->to($email, $name); Some more info about toName: $mail["toName"] is set by the core WireMail.php to() function as seen in the example in my previous post. The reason I pull the recipient emails from $mail["toName"] is that this array is a key=>value store of email addresses and the name set for them (if set), whereas $mail["to"] just contains the email addresses. In WireMail::send(), $mail["to"] is traversed and the name is set if it exists in $mail["toName"]: // WireMail.php 611-619 foreach($this->to as $to) { $toName = isset($this->mail['toName'][$to]) ? $this->mail['toName'][$to] : ''; if($toName) $to = $this->bundleEmailAndName($to, $toName); // bundle to "User Name <user@example.com>" if($param) { if(@mail($to, $subject, $body, $header, $param)) $numSent++; } else { if(@mail($to, $subject, $body, $header)) $numSent++; } } I suspect this is probably a result of an earlier implementation of WireMail that didn't have the toName option - I think it makes more sense to traverse $mail["toName"] in this module's implementation. The WireMail::toName() method isn't actually used by this module directly - in core WireMail this sets the "name" for the last added "to" email address, so could be used like so: $mg = $mail->new(); $mg->to("email@example.com") ->toName("An Example Name") ->subject("A Subject") ->bodyHTML("<p>Test</p>") ->send(); // Sends to "An Example Name <email@example.com>" // An alternative to $mg->to("email@example.com", "An Example Name"); On another note, while reviewing the docs I see there's a line length limit on X-Mailgun-Recipient-Variables which I'll likely need to handle too. Will see what I can do with this. Cheers, Chris
-
Hi @adrian, How are the "to" email addresses being passed? As I understand it, the "toName" variable should be populated when calling WireMail::to()? // WireMail.php 304-309 if(empty($toName)) $toName = $name; // use function arg if not overwritten $toEmail = $this->sanitizeEmail($toEmail); if(strlen($toEmail)) { $this->mail['to'][$toEmail] = $toEmail; $this->mail['toName'][$toEmail] = $this->sanitizeHeaderValue($toName); } I think what you're saying is that you aren't using the to() method, and instead the "to" addresses are being set using addRecipientVariables()? I've tweaked the module to handle this implementation. Technically the recipients should be set using to() and addRecipientVariables() is for overriding the recipientVariables set by default from $mail["toName"], but I can't see the harm in allowing for this different implementation. Cheers, Chris
-
Hi @adrian, I'll check this later, but I'm pretty sure it should work as expected - "to" is set on line 469 regardless of batchMode, and then overridden if split into batches (line 594) so "to" and "recipientVariables" are limited to 1000 at a time. Cheers, Chris
-
Hi @adrian, Got a chance to look at this today. Batch requests (batch mode on, to emails > 1000) now get split up into separate API requests with 1000 emails per request. The only way I could test this was to reduce the limit to 2 and then try sending a batch request to more than two email addresses. Seems to work fine, however I'd recommend enabling test mode and testing with this to confirm that it works correctly for emails being sent to 1000+ users prior to sending for real. I've also moved the batchMode setting into the module config, so it can be set to ON by default. Cheers, Chris
-
Hi @adrian, I did look at using the SDK for the module, but felt it was overkill for what was required - A more fully featured Mailgun API module could be built with it, but that's a job for someone with more experience and need for it. I'll have a look at this in the next week though. Not sure I'll be able to test it fully, but it should just be a case of splitting the to array into batches of 1000 and sending each of these. Cheers, Chris
-
Hello. I'd somewhat rewritten WireMailMailgun a while back, to implement some more features and implement PW coding guidelines etc. My version has been somewhat in limbo, although there's been various discussions in the thread linked above. I've decided to release my version as a separate module called WireMailgun, as it has breaking changes and a slightly different implementation. I've also got it using the email validation v4 endpoint. For simple usage, either module will do what you need it to do. If you need to do some more advanced things e.g inline images or adding data, this module will help you with that. Here's the readme... WireMail Mailgun Extends WireMail to use the Mailgun API for sending emails. Installation Download the zip file at Github or clone the repo into your site/modules directory. If you downloaded the zip file, extract it in your sites/modules directory. In your admin, go to Modules > Refresh, then Modules > New, then click on the Install button for this module. API Prior to using this module, you must set up a domain in your Mailgun account to create an API key. Add the API key and domain to the module's settings. Usage Usage is similar to the basic WireMail implementation, although a few extra options are available. Please refer to the WireMail documentation for full instructions on using WireMail, and to the examples below. Extra Methods The following are extra methods implemented by this module: Chainable The following methods can be used in a chained statement: cc(string|array|null $email) - Set a "cc" email address. Only used when $batchMode is set to false. Please refer to WireMail::to() for more information on how to use this method. bcc(string|array|null $email) - Set a "bcc" email address. Only used when $batchMode is set to false. Please refer to WireMail::to() for more information on how to use this method. addData(string $key, string $value) - Add custom data to the email. See https://documentation.mailgun.com/en/latest/user_manual.html#attaching-data-to-messages for more information. addInlineImage(string $file, string $filename) - Add an inline image for referencing in HTML. Reference using "cid:" e.g. <img src='cid:filename.ext'> Requires curl_file_create() (PHP >= 5.5.0) See https://documentation.mailgun.com/en/latest/user_manual.html#sending-inline-images for more information. addRecipientVariables(array $recipients) - Add recipient variables. $recipients should be an array of data, keyed by the recipient email address See https://documentation.mailgun.com/en/latest/user_manual.html#batch-sending for more information. addTag(string $tag) - Add a tag to the email. Only ASCII allowed Maximum length of 128 characters There is a maximum number of 3 tags allowed per email. addTags(array $tags) - Add tags in a batch. setApiKey(string $apiKey) - Override the Mailgun API Key module setting. setBatchMode(bool $batchMode) - Enables or disables batch mode. This is off by default, meaning that a single email is sent with each recipient seeing the other recipients If this is on, any email addresses set by cc() and bcc() will be ignored Mailgun has a maximum hard limit of recipients allowed per batch of 1,000. Read more about batch sending. setDeliveryTime(int $time) - The (unix)time the email should be scheduled for. setDomainName(string $domain) - Override the "Domain Name" module setting. setRegion(string $region) - Override the "Region" module setting. Valid regions are "us" and "eu" Fails silently if an invalid region is passed setSender(string $domain, string $key) - Set a different API sender than the default. The third argument is $region which is optional A shortcut for calling setDomainName(), setApiKey() and setRegion() setTestMode(bool $testMode) - Override the "Test Mode" module setting. setTrackOpens(bool $trackOpens) - Override "Track Message Opens" module setting on a per-email basis. Open tracking only works for emails with bodyHTML() set setTrackClicks(bool $trackClicks) - Override "Track Message Clicks" module setting on a per-email basis. Click tracking only works for emails with bodyHTML() set Other send() - Send the email. Returns a positive number (indicating number of emails sent) or 0 on failure. validateEmail(string $email) - Validates a single address using Mailgun's address validation service. Returns an associative array. To return the response as an object, set the second argument to false For more information on what this method returns, see Mailgun's documentation. getHttpCode() - Get the API HTTP response code. A response code of 200 indicates a successful response Examples Basic Example Send an email: $mg = $mail->new(); $sent = $mg->to("user@domain.com") ->from("you@company.com") ->subject("Message Subject") ->body("Message Body") ->send(); Advanced Example Send an email using all supported WireMail methods and extra methods implemented by WireMailgun: $mg = $mail->new(); // WireMail methods $mg->to([ "user@domain.com" => "A User", "user2@domain.com" => "Another User", ]) ->from("you@company.com", "Company Name") ->replyTo("reply@company.com", "Company Name") ->subject("Message Subject") ->bodyHTML("<p>Message Body</p>") // A text version will be automatically created ->header("key1", "value1") ->headers(["key2" => "value2"]) ->attachment("/path/to/file.ext", "filename.ext"); // WireMailgun methods $mg->cc("cc@domain.com") ->bcc(["bcc@domain.com", "bcc2@domain.com"]) ->addData("key", "value") // Custom X-Mailgun-Variables data ->addInlineImage("/path/to/file-inline.jpg", "filename-inline.jpg") // Add inline image ->addTag("tag1") // Add a single tag ->addTags(["tag2", "tag3"]) // Add tags in a batch ->setBatchMode(false) // A single email will be sent, both "to" recipients shown ->setDeliveryTime(time() + 3600) // The email will be delivered in an hour ->setSender($domain, $key, "eu") // Use a different domain to send, this one in the EU region ->setTestMode(true) // Mailgun won't actually send the email ->setTrackOpens(false) // Disable tracking opens ->setTrackClicks(false); // Disable tracking clicks // Batch mode is set to false, so 1 returned if successful $numSent = $mg->send(); echo "The email was " . ($numSent ? "" : "not ") . "sent."; Validate an Email Address $mg = $mail->new(); $response = $mg->validateEmail("user@domain.com", false); if($mg->getHttpCode() == 200) { echo $response->result == "deliverable" ? "Valid" : "Not valid"; } else { echo "Could not validate"; } I hope it is useful! Cheers, Chris
- 47 replies
-
- 12
-
-
-
Hi @Macrura, I think the best thing to do is to keep them separate so there are no backwards compatibility issues, and you can mine my version for additional features if they aren't already present in yours (and should you wish to add them).
-
Hi, I see Mailgun have updated their API to version 4. I'm going to implement this then submit my version to the directory as a separate module - no idea what to call it though... maybe WiremailMailgunApi. Cheers, Chris EDIT: turns out that it is only the email validation that's been updated to version 4...!
-
Haha, I spent last week working on a GraphQL API module built upon the webonyx library! Not wasted time though, I think I've probably implemented a few things that would be welcome additions (e.g. WireCache for $pages->find()). When I get a chance I'll have a look at the new version of this module and see whether I can suggest any additions. Cheers, Chris
-
Hi @Jonathan Lahijani, I'm not seeing this with the latest version (0.0.7) - I get the data-src attribute and the src attribute is the blank pixel gif: <img data-src='/site/assets/files/1033/placeholder-city.webp' alt='' data-uk-img src='data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==' data-srcset='/site/assets/files/1033/placeholder-city.320x569-srcset-hidpi.jpg 320w, /site/assets/files/1033/placeholder-city.640x1138-srcset-hidpi.jpg 640w, /site/assets/files/1033/placeholder-city.768x1365-srcset-hidpi.jpg 768w, /site/assets/files/1033/placeholder-city.webp 1024w' data-sizes='(orientation: portrait) and (max-width: 768px) 50vw'> It isn't actually necessary to pass "srcset" as true by the way. This is actually telling the module to use portrait mode: echo $page->image->render(["uk-img" => true]); // Should return the above <img> tag but without the "sizes" attribute. The render() method is a bit limited unfortunately - you can't access all the options that can be accessed by using $page->image->srcset() and $page->image->sizes(). However, what you are trying to do should work - are you on the latest version? Cheers, Chris
-
I was also getting the same warning for a dual English/French install I'm working on. First time using multi-language. I had setlocale(LC_ALL, "en_GB.utf8"); in site/config.php, and had set the values in LanguageSupport "C" fields as the error requests (en_GB.utf8 & fr_FR.utf8). Still getting the error message on login. SSH checked the locales using locale -a, and they were listed. Hmm... Tried a few things, but what worked for me was putting setlocale(LC_ALL, "en_GB.utf8", "fr_FR.utf8"); in site_ready.php. Error message now gone - hurrah!
-
Strange code inserted by... css? js? a module?
nbcommunication replied to creativejay's topic in General Support
I'm pretty sure I've seen something similar happen when nesting an <a></a> inside another <a></a> - looks "fine" in page source but the browser attempts to escape them or something and it displays differently in the inspector. Steps I would go through is to to replace each var value with a blank string, go through each methodically, or maybe remove each <a></a> and add each one back in to identify which one is triggering it. You might find it completely unrelated to the above, but it'll get you closer to the source of the issue! PS - Grammarly browser extension and CKEditor 4 don't mix well. Had to ask a number of clients and colleagues to disable it so they can actually save content. -
Hi, The main breaking change with my version of the module is that Cc/Bcc is ignored if batch mode is set to on. Seemed absurd to me that an email sent to multiple addresses individually would be sent each time to any cc/bcc addresses set. The latest version is compatible with 2.7 onwards. I implemented fallbacks for things (e.g. textTools) not present in the 2 branch. It also has more features and I've been using it in production without issue since I first posted it. However, I've not been using it for much more than sending simple emails. It's fully tested though ? I'd recommend using it if starting a new project, but I'm reluctant for it to be the main directory module as any users upgrading could encounter problems with their existing implementation. They'd be easy to fix, but that's not the point. I don't use any of the Pro modules that it integrates with (FormBuilder, ProMailer), and wouldn't want to interrupt "power" users of these. Perhaps my version should have a different name? WireMailMailgun3 and I could remove the fallbacks for the 2 branch? Cheers, Chris
-
@netcarver- I've got it automatically placed after the <title> element now, if that element exists (which it should!). @horst - I've added a renderMeta method to allow for manual outputting of the meta tag in the <head>. If this is used, it shouldn't output automatically.
-
Hi @alexmercenary - aye I didn't have the "uk-img" enabled by way of the data-src attribute. I've fixed that now, should be on the repo. Worth noting that enabling uk-img changes the src attribute to data-src, and adds a src attribute with a blank pixel: src='data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw=='. The src attribute is required for valid HTML5, so I've been in the habit of adding this blank pixel for this purpose.
-
Hi @netcarver, Thanks for the feedback - I'll have a look at this soon and see if I can get it placed better. Cheers, Chris
-
Hi @alexmercenary, "uk-img" doesn't validate as HTML5. I always use the data- prefix for this reason, it's one of the ways to use UIkit components: https://getuikit.com/docs/javascript#component-usage. As for the srcset attribute - I think they've updated the docs here, they had it without the data- prefix until recently. I'll update this when I get a chance - the current implementation will still work. Cheers, Chris
-
I've spent the last while experimenting with srcset implementation - and PageimageSrcset is the result: PageimageSrcset Provides configurable srcset and sizes properties/methods for Pageimage. Overview The main purpose of this module is to make srcset implementation as simple as possible in your template code. It does not handle images rendered in CKEditor or similar fields. For an introduction to srcset and sizes, please read this Mozilla article about responsive images. Pageimage::srcset() // The property, which uses the set rules in the module configuration $srcset = $image->srcset; // A method call, using a set rules string // Delimiting with a newline (\n) would also work, but not as readable $srcset = $image->srcset("320, 480, 640x480 768w, 1240, 2048 2x"); // The same as above but using an indexed/sequential array $srcset = $image->srcset([ "320", "480", "640x480 768w", "1240", "2048 2x", ]); // The same as above but using an associative array // No rule checking is performed $srcset = $image->srcset([ "320w" => [320], "480w" => [480], "768w" => [640, 480], "1240w" => [1240], "2x" => [2048], ]); // Use the default set rules with portrait images generated for mobile/tablet devices $srcset = $image->srcset(true); // Return the srcset using all arguments $srcset = $image->srcset("320, 480, 640x480 768w, 1240, 2048 2x", [ "portrait" => "320, 640", ]); // The set rules above are a demonstration, not a recommendation! Image variations are only created for set rules which require a smaller image than the Pageimage itself. On large sites this may still result in a lot of images being generated. If you have limited storage, please use this module wisely. Portrait Mode In many situations, the ratio of the image does not need to change at different screen sizes. However, images that cover the entire viewport are an exception to this and are often the ones that benefit most from srcset implementation. The main problem with cover images is that they need to display landscape on desktop devices and portrait when this orientation is used on mobile and tablet devices. You can automatically generate portrait images by enabling portrait mode. It is recommended that you use this in combination with Pageimage::focus() so that the portrait variations retain the correct subject. The generated variations are HiDPI/Retina versions. Their height is determined by the portrait ratio (e.g. 9:16). Variations are always generated, regardless of whether the original image is smaller. Upscaling is disabled though, so you may find that some variations are actually smaller than they say they are in their filename. The sizes attribute should be used when portrait mode is enabled. Pageimage::sizes will return (orientation: portrait) and (max-width: {maxWidth}px) 50vw by default, which handles the use of these images for retina devices. The maximum width used in this rule is the largest set width. Pageimage::sizes() There is no option to configure default sizes because in most cases 100vw is all you need, and you do not need to output this anyway as it is inferred when using the srcset attribute. You can use the method for custom sizes though: // The property $sizes = $image->sizes; // Returns 100vw in most cases // Returns '(orientation: portrait) and (max-width: {maxWidth}px)50vw' if portrait mode enabled // A method call, using a mixture of integer widths and media query rules // Integer widths are treated as a min-width media query rule $sizes = $image->sizes([ 480 => 50, "(orientation: portrait) and (max-width: 640px)" => 100, 960 => 25, ]); // (min-width: 480px) 50vw, (orientation: portrait) and (max-width: 640px) 100vw, (min-width: 960px) 25vw // Determine widths by UIkit 'child-width' classes $sizes = $image->sizes([ "uk-child-width-1-2@s", "uk-child-width-1-3@l", ]); // (min-width: 640px) 50vw, (min-width: 1200px) 33.33vw // Determine widths by UIkit 'width' classes $sizes = $image->sizes([ "uk-width-1-2@m", "uk-width-1-3@xl", ]); // (min-width: 960px) 50vw, (min-width: 1600px) 33.33vw // Return the portrait size rule $sizes = $image->sizes(true); // (orientation: portrait) and (max-width: {maxWidth}px) 50vw // The arguments above are a demonstration, not a recommendation! Pageimage::render() This module extends the options available to this method with: srcset: When the module is installed, this will always be added, unless set to false. Any values in the formats described above can be passed. sizes: Only used if specified. Any values in the formats described above can be passed. uk-img: If passed, as either true or as a valid uk-img value, then this attribute will be added. The srcset attribute will also become data-srcset. Please refer to the API Reference for more information about this method. // Render an image using the default set rules echo $image->render(); // <img src='image.jpg' alt='' srcset='{default set rules}'> // Render an image using custom set rules echo $image->render(["srcset" => "480, 1240x640"]); // <img src='image.jpg' alt='' srcset='image.480x0-srcset.jpg 480w, image.1240x640-srcset.jpg 1240w'> // Render an image using custom set rules and sizes // Also use the `markup` argument echo $image->render("<img class='image' src='{url}' alt='Image'>", [ "srcset" => "480, 1240", "sizes" => [1240 => 50], ]); // <img class='image' src='image.jpg' alt='Image' srcset='image.480x0-srcset.jpg 480w, image.1240x640-srcset.jpg 1240w' sizes='(min-width: 1240px) 50vw'> // Render an image using custom set rules and sizes // Enable uk-img echo $image->render([ "srcset" => "480, 1240", "sizes" => ["uk-child-width-1-2@m"], "uk-img" => true, ]); // <img src='image.jpg' alt='' data-uk-img data-srcset='image.480x0-srcset.jpg 480w, image.1240x640-srcset.jpg 1240w' sizes='(min-width: 960px) 50vw'> // Render an image using portrait mode // Default rule sets used: 320, 640, 768, 1024, 1366, 1600 // Portrait widths used: 320, 640, 768 // Original image is 1000px wide // Not possible to use portrait mode and custom sets or portrait widths in render() // Sizes attribute automatically added echo $image->render(["srcset" => true]); // <img src='image.jpg' alt='' srcset='image.320x569-srcset-hidpi.jpg 320w, image.640x1138-srcset-hidpi.jpg 640w, image.768x1365-srcset-hidpi.jpg 768w, image.jpg 1024w' sizes='(orientation: portrait) and (max-width: 768px) 50vw'> Configuration To configure this module, go to Modules > Configure > PageimageSrcset. Set Rules These are the default set rules that will be used when none are specified, e.g. when calling the property: $image->srcset. Each set rule should be entered on a new line, in the format {width}x{height} {inherentwidth}w|{resolution}x. Not all arguments are required - you will probably find that specifying the width is sufficient for most cases. Here's a few examples of valid set rules and the sets they generate: Set Rule Set Generated Arguments Used 320 image.320x0-srcset.jpg 320w {width} 480x540 image.480x540-srcset.jpg 480w {width}x{height} 640x480 768w image.640x480-srcset.jpg 768w {width}x{height} {inherentwidth}w 2048 2x image.2048x0-srcset.jpg 2x {width} {resolution}x How you configure your rules is dependent on the needs of the site you are developing; there are no prescriptive rules that will meet the needs of most situations. This article gives a good overview of some of the things to consider. When you save your rules, a preview of the sets generated and an equivalent method call will be displayed to the right. Invalid rules will not be used, and you will be notified of this. Portrait Mode Set Widths A comma limited list of widths to create HiDPI/Retina portrait variations for. Crop Ratio The portrait ratio that should be used to crop the image. The default of 9:16 should be fine for most circumstances as this is the standard portrait ratio of most devices. However, you can specify something different if you want. If you add a landscape ratio, it will be switched to portrait when used. Any crops in the set rules ({width}x{height}) are ignored for portrait mode variations as this ratio is used instead. UIkit Widths If your website theme uses UIkit, you can pass an array of UIkit width classes to Pageimage::sizes to be converted to sizes. The values stored here are used to do this. If you have customised the breakpoints on your theme, you should also customise them here. Please note that only 1- widths are evaluated by Pageimage::sizes, e.g. uk-width-2-3 will not work. Remove Variations If checked, the image variations generated by this module are cleared on Submit. On large sites, this may take a while. It makes sense to run this after you have made changes to the set rules. Image Suffix You will see this field when Remove Variations is checked. The value is appended to the name of the images generated by this module and is used to identify variations. You should not encounter any issues with the default suffix, but if you find that it conflicts with any other functionality on your site, you can set a custom suffix instead. Debug Mode When this is enabled, a range of information is logged to pageimage-srcset. PageimageSrcsetDebug.js is also added to the <head> of your HTML pages. This will console.log a range of information about the images and nodes using srcset on your page after a window.onresize event is triggered. This can assist you in debugging your implementation. The browser will always use the highest resolution image it has loaded or has cached. You may need to disable browser caching to determine whether your set rules are working, and it makes sense to work from a small screen size and up. If you do it the other way, the browser is going to continue to use the higher resolution image it loaded first. UIkit Features This module implements some additional features that are tailored towards UIkit being used as the front-end theme framework, but this is not required to use the module. Installation Download the zip file at Github or clone the repo into your site/modules directory. If you downloaded the zip file, extract it in your sites/modules directory. In your admin, go to Modules > Refresh, then Modules > New, then click on the Install button for this module. ProcessWire >= 3.0.123 is required to use this module.
- 29 replies
-
- 20
-
-
-
Hello, I thought it might be useful to post a CSP I've recently deployed using this module. Every site is different - there's no prescriptive policy and that's the main caveat here. This is for a site with an embedded Shopify store, an Issuu embed, a Google Tour embed and Google Maps implementation (JS API). It also uses Font Awesome 5 from their CDN, jQuery from CDNJS, and some Google Fonts. It also has TextformatterVideoEmbed installed alongside its extended options module. default-src 'none'; script-src 'self' cdnjs.cloudflare.com *.google.com *.gstatic.com *.googleapis.com www.google-analytics.com www.googletagmanager.com e.issuu.com sdks.shopifycdn.com; style-src 'self' 'unsafe-inline' cdnjs.cloudflare.com *.googleapis.com use.fontawesome.com; img-src 'self' data: *.google.com *.googleapis.com *.gstatic.com *.ggpht.com www.google-analytics.com www.googletagmanager.com brand.nbcommunication.com *.shopify.com sdks.shopifycdn.com; connect-src 'self' www.google-analytics.com ocean-kinetics.myshopify.com; font-src 'self' fonts.gstatic.com use.fontawesome.com; object-src 'self'; media-src 'self' data:; manifest-src 'self'; frame-src www.google.com www.youtube.com www.youtube-nocookie.com player.vimeo.com w.soundcloud.com e.issuu.com; form-action 'self'; base-uri 'self' The Shopify embed script and Google Analytics initialisation have been moved into script files so there are no inline scripts at all. The script-src 'unsafe-inline' directive is an obstacle to getting that A+ on Observatory. Google Analytics is also a bit of an impediment to getting a top-drawer score, as its script doesn't use SRI. However, there is a reason for that as I understand it - it is a script that just loads other scripts so SRI implementation would just be token, it wouldn't actually be improving security. Still, it is possible to get A+ without dealing with this. It would be great to get some discussion going on CSP implementation - I'm only a few weeks in myself, so have much to learn! Cheers, Chris NB