Last active
February 19, 2023 15:42
-
-
Save Accudio/00010ee93e1a78d2dfed0bd86a45afbc to your computer and use it in GitHub Desktop.
Image macros and functions for Imgix on Daysmart
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{# using macro directly #} | |
{{ image({ | |
url: '/path/to/image.jpg', | |
alt: 'Image alt attribute', | |
class: 'mb-30', | |
imgClass: 'rounded', | |
lazy: false, | |
width: 1920, | |
height: 1080, | |
ratio: 0.5, | |
srcset: { | |
sizes: '100vw', | |
ldpiMin: 700, | |
ldpiMax: 837, | |
hdpiMin: 300, | |
hdpiMax: 700 | |
} | |
}) }} | |
{# using ACF image array and Timber #} | |
{{ acfImage({ | |
image: post.meta('photo'), | |
class: 'mb-30', | |
imgClass: 'rounded', | |
ratio: 0.5, | |
srcset: { | |
sizes: '100vw', | |
ldpiMin: 700, | |
ldpiMax: 837, | |
hdpiMin: 300, | |
hdpiMax: 700 | |
} | |
}) }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{# ============================================== | |
# Image Macros | |
# ============================================== #} | |
{## | |
# main image macro with full arguments | |
# | |
# arguments: | |
{ | |
// required | |
url, // URL to original image, either relative or with Imgix subdomain | |
width, // width of original image in pixels | |
height, // height of original image in pixels | |
// optional | |
alt, // alt attribute. Defaults to empty string | |
class, // classes to apply to <picture> element | |
imgClass, // classes to apply to <img> element | |
lazy, // should this image be lazyloaded. Defaults to true | |
ratio, // force a specific aspect ratio. In decimal format found by height / width. | |
srcset: { // see https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/ for info about ldpi/hdpi | |
sizes, // sizes attribute, if not set browsers assume 100vw | |
ldpiMin, // the minimum image width to generate for srcset at 1x dpi screens | |
ldpiMax, // the maximum image width to generate for srcset at 1x dpi screens | |
hdpiMin, // the minimum image width to generate for srcset at >1.5x dpi screens | |
hdpiMax // the maximum image width to generate for srcset at >1.5x dpi screens | |
}, | |
type, // if set to svg+xml SVG won't be transformed | |
params // object of parameters to provide to imgix to add to URL. See https://docs.imgix.com/apis/rendering for options | |
} | |
#} | |
{% macro image(args) %} | |
{% set opts = { | |
url: args.url, | |
alt: ( args.alt ?? '' ), | |
class: ( args.class ?? '' ), | |
imgClass: ( args.imgClass ?? '' ), | |
lazy: ( args.lazy ?? true ), | |
width: args.width, | |
sizes: args.sizes, | |
srcset: ( args.srcset ?? false ), | |
params: ( args.params ?? false ), | |
type: ( args.type ?? 'image' ) | |
} %} | |
{% set height = args.height %} | |
{# if image is an SVG #} | |
{% if opts.type == 'svg+xml' %} | |
<div class="image{% if opts.class %} {{ opts.class }}{% endif %}"> | |
<img | |
class="image__img{% if opts.imgClass %} {{ opts.imgClass }}{% endif %}" | |
alt="{{ opts.alt }}" | |
src="{{ imgix_url(opts.url) }}" | |
{# only output width and height attributes for SVG if they are true, WP doesn't store this #} | |
{% if opts.width %} | |
width="{{ opts.width }}" | |
{% endif %} | |
{% if height %} | |
height="{{ height }}" | |
{% endif %} | |
{# if lazy, set native loading attribute #} | |
{% if opts.lazy %} | |
loading="lazy" | |
{% endif %} | |
> | |
</div> | |
{# image is not an SVG #} | |
{% else %} | |
{% set ratio = (args.ratio ?? false) %} | |
{% set intrinsicRatio = (height / opts.width)|round(2) %} | |
{% if ratio %} | |
{# if ratio is set, we need to ensure width and height match ratio #} | |
{# if desired ratio is not within 5% of intrinsic, calculate new height attribute based on provided ratio #} | |
{% if ((ratio - intrinsicRatio)|abs) > 0.05 %} | |
{% set height = args.width * ratio %} | |
{% endif %} | |
{% else %} | |
{# if ratio not set, use image's intrinsic ratio #} | |
{% set ratio = intrinsicRatio %} | |
{% endif %} | |
<picture class="image{% if opts.class %} {{ opts.class }}{% endif %}"> | |
{% if opts.srcset %} | |
{# source for hi-dpi (1.5x up) displays #} | |
{# @see https://jakearchibald.com/2021/serving-sharp-images-to-high-density-screens/ #} | |
<source | |
media="(-webkit-min-device-pixel-ratio: 1.5)" | |
sizes="{{ sizes }}" | |
{# get and output srcset with 2x resolution but reduced quality to keep file size down #} | |
srcset="{{ imgix_srcset({ | |
url: opts.url, | |
min: (opts.srcset.hdpiMin * 2), | |
max: (opts.srcset.hdpiMax * 2), | |
ratio: ratio, | |
quality: 45, | |
params: opts.params | |
}) }}" | |
> | |
{% endif %} | |
{# img for low-dpi (1x) displays and fallback #} | |
<img | |
class="image__img{% if opts.imgClass %} {{ opts.imgClass }}{% endif %}" | |
alt="{{ opts.alt }}" | |
{# if srcset provided #} | |
{% if opts.srcset %} | |
{# get and output srcset #} | |
srcset="{{ imgix_srcset({ | |
url: opts.url, | |
min: opts.srcset.ldpiMin, | |
max: opts.srcset.ldpiMax, | |
ratio: ratio, | |
quality: 85, | |
params: opts.params | |
}) }}" | |
sizes="{{ sizes }}" | |
{% else %} | |
{# get URL to image on imgix with added parameters #} | |
src="{{ imgix_url(opts.url, opts.params) }}" | |
{% endif %} | |
{# set dimensions to prevent layout shift #} | |
width="{{ opts.width }}" | |
height="{{ height }}" | |
{# if lazy, set native loading attribute #} | |
{% if opts.lazy %} | |
loading="lazy" | |
{% endif %} | |
> | |
</picture> | |
{% endif %} | |
{% endspaceless %} | |
{%- endmacro %} | |
{## | |
# acf image macro that pulls from acf image array | |
# | |
# arguments: | |
{ | |
// required | |
image, | |
// optional | |
alt, | |
class, | |
imgClass, | |
lazy, | |
width, | |
height, | |
ratio, | |
srcset: { | |
sizes, | |
ldpiMin, | |
ldpiMax, | |
hdpiMin, | |
hdpiMax, | |
}, | |
params | |
} | |
#} | |
{% macro acfImage(args) -%} | |
{% if args.image %} | |
{% set image = args.image %} | |
{% set width = args.width ?? false %} | |
{% set height = args.height ?? false %} | |
{% if args.height == 'auto' and width %} | |
{% set height = (width / image.width) * image.height %} | |
{% endif %} | |
{% if args.width == 'auto' and height %} | |
{% set width = (height / image.height) * image.width %} | |
{% endif %} | |
{{ _self.image({ | |
url: image.url, | |
type: image.subtype, | |
alt: ( args.alt ?? image.alt ?? '' ), | |
class: ( args.class ?? '' ), | |
imgClass: ( args.imgClass ?? '' ), | |
lazy: ( args.lazy ?? true ), | |
width: width|default(image.width), | |
height: height|default(image.height), | |
ratio: ( args.ratio ?? false ), | |
srcset: ( args.srcset ?? false ), | |
params: ( args.params ?? false ) | |
}) }} | |
{% endif %} | |
{% endmacro %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Utilities for images with imgix | |
* | |
* @package Daysmart | |
* @subpackage Imgix | |
*/ | |
namespace Daysmart; | |
use Timber; | |
use Imgix\UrlBuilder; | |
class Imgix | |
{ | |
/** | |
* __construct | |
* | |
* Add actions and filters | |
* | |
* @return void | |
*/ | |
public function __construct() | |
{ | |
add_filter('timber/twig', [self::class, 'add_to_twig']); | |
// add preconnect header | |
add_action('send_headers', [self::class, 'preconnect']); | |
} | |
/** | |
* add_to_twig | |
* | |
* Adds any functions, extensions or filters to twig. | |
* | |
* @see https://timber.github.io/docs/guides/extending-timber/ | |
* | |
* @param Twig $twig Instance of Twig we add functionality to | |
* @return Twig Twig instance with additions | |
*/ | |
public static function add_to_twig($twig) | |
{ | |
$twig->addFunction(new Timber\Twig_Function('imgix_url', [self::class, 'url'])); | |
$twig->addFunction(new Timber\Twig_Function('imgix_srcset', [self::class, 'srcset'])); | |
return $twig; | |
} | |
/** | |
* url | |
* | |
* Take URL for image and add parameters | |
* | |
* @param string $url URL to image including IMGIX domain | |
* @param array $params Imgix parameters to add to the image | |
* @return string URL to image with params | |
*/ | |
public static function url($url, $params = []) | |
{ | |
$path = self::path($url); | |
if ($params) { | |
$params = array_merge(['auto' => 'format,compress'], $params); | |
} | |
$builder = self::builder(); | |
$url = $builder->createURL($path, $params); | |
return $url; | |
} | |
/** | |
* srcset | |
* | |
* Generates srcset for the provided image with the provided arguments. | |
* | |
* Required args: | |
* - `url` — URL to image including IMGIX domain | |
* - `min` — Minimum size to generate | |
* - `max` — Maximum size to generate | |
* - `ratio` — Aspect ratio of image | |
* | |
* Optional args: | |
* - `quality` — Image compression quality from 0–100. Default 85 | |
* - `tolerance` — Seperation between each image from 0–1. Larger values result in fewer images, lower values result in more. Default 0.08 | |
* | |
* @param array $args Associative array with arguments for srcset generation | |
* @return string String ready to be inserted into `srcset` attribute | |
*/ | |
public static function srcset($args) | |
{ | |
$path = self::path($args['url']); | |
$min_size = $args['min']; | |
$max_size = $args['max']; | |
$ratio = '1:' . $args['ratio']; | |
$quality = $args['quality'] ?? 85; | |
$tolerance = $args['tolerance'] ?? 0.08; | |
$params = [ | |
'auto' => 'format,compress', | |
'fit' => 'crop', | |
'crop' => 'center', | |
'q' => $quality, | |
'ar' => $ratio | |
]; | |
if ($args['params'] ?? false) { | |
$params = array_merge($params, $args['params']); | |
} | |
$opts = [ | |
'start' => $min_size, | |
'stop' => $max_size, | |
'tol' => $tolerance | |
]; | |
$builder = self::builder(); | |
$srcset = $builder->createSrcSet($path, $params, $opts); | |
return $srcset; | |
} | |
/** | |
* builder | |
* | |
* Create instance of Imgix/UrlBuilder with correct settings | |
* | |
* @return UrlBuilder | |
*/ | |
private static function builder() | |
{ | |
return new UrlBuilder(\IMGIX_DOMAIN, true, '', false); | |
} | |
/** | |
* path | |
* | |
* Convert absolute Imgix URL to relative for use with UrlBuilder | |
* | |
* @param string $url Imgix URL including domain | |
* @return string Relative Imgix URL without host | |
*/ | |
private static function path($url) | |
{ | |
$pattern = '/https?:\/\/' . \IMGIX_DOMAIN . '/'; | |
return preg_replace($pattern, '', $url); | |
} | |
public static function preconnect() | |
{ | |
header('Link: <https://' . \IMGIX_DOMAIN . '/>; rel=preconnect'); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<picture class="image"> | |
<source media="(-webkit-min-device-pixel-ratio: 1.5)" | |
srcset=" | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=600 600w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=696 696w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=807 807w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=937 937w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=1086 1086w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=1260 1260w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=45&w=1400 1400w" | |
> | |
<img alt="" class="image__img" height="1200" sizes="100vw" | |
srcset=" | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=85&w=700 700w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=85&w=812 812w, | |
https://daysmart-s8.imgix.net/uploads/2021/06/placeholder-1.jpg?ar=1%3A0.6&auto=format%2Ccompress&crop=center&fit=crop&q=85&w=837 837w" | |
width="2000" | |
> | |
</picture> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment