Skip to content

Instantly share code, notes, and snippets.

@sophy
Forked from crstauf/class.image-tag.php
Created August 17, 2022 03:48
Show Gist options
  • Select an option

  • Save sophy/9c7043e86324fda0b3ee4b01c23da6d3 to your computer and use it in GitHub Desktop.

Select an option

Save sophy/9c7043e86324fda0b3ee4b01c23da6d3 to your computer and use it in GitHub Desktop.

Revisions

  1. @crstauf crstauf revised this gist Sep 14, 2018. 1 changed file with 307 additions and 149 deletions.
    456 changes: 307 additions & 149 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -6,14 +6,21 @@
    * @link https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f
    */

    if ( !defined( 'ABSPATH' ) || !function_exists( 'add_filter' ) ) {
    header( 'Status: 403 Forbidden' );
    header( 'HTTP/1.1 403 Forbidden' );
    exit;
    }

    /**
    * Abstract object for image tag data.
    *
    * @link https://github.com/aFarkas/lazysizes Preferred lazy loading script.
    * @todo Add image primary color detection and use.
    */
    abstract class image_tag {

    const VERSION = '0.0.7.0';
    const VERSION = '0.0.8';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    /** @var mixed $_source Image source. **/
    @@ -28,6 +35,9 @@ abstract class image_tag {
    /** @var string $_orientation Orientation of the image. **/
    protected $_orientation = 'unknown';

    /** @var float $_ratio Ratio of the image (height divided by width). **/
    protected $_ratio = 0;

    /**
    * @var string $id Image "id" atribute.
    * @var string $alt Image "alt" attribute.
    @@ -68,18 +78,40 @@ abstract class image_tag {
    /** @var image_tag $noscript Noscript image object. */
    var $noscript;

    /**
    * Create.
    *
    * @param mixed $source Image source.
    * @param array $args Image object arguments.
    *
    * @return image_tag
    */
    public static function create( $source, $args = array() ) {
    $cache_key = $source;

    if ( empty( $args['skip_cache'] ) )
    $cache = wp_cache_get( $cache_key, __CLASS__, false, $found );

    if ( !empty( $found ) )
    return $cache;

    $self = new static( $source, $args );

    wp_cache_add( $cache_key, $self, __CLASS__ );

    return $self;
    }

    /**
    * Construct.
    *
    * @param mixed $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    *
    * @uses image_tag::_maybe_create_noscript_object()
    * @uses image_tag::get_attributes()
    * @uses image_tag::set_orientation()
    * @uses image_tag::maybe_set_lazyload_atributes()
    */
    function __construct( $source, $attributes = array(), $args = array() ) {
    protected function __construct( $source, $args = array() ) {
    $this->_source = $this->src = $source;

    array_key_exists( 'noscript', $args ) && $this->_noscript = $args['noscript'];
    @@ -91,25 +123,25 @@ function __construct( $source, $attributes = array(), $args = array() ) {
    )
    $this->_noscript = true;

    if (
    $this->_noscript
    && empty( $this->noscript )
    )
    $this->_create_noscript_object( $source, $attributes, $args );
    $this->_maybe_create_noscript_object( $source, $args );

    foreach ( array_keys( $this->get_attributes() ) as $attribute )
    if (
    array_key_exists( $attribute, $attributes )
    array_key_exists( $attribute, $args )
    && property_exists( $this, $attribute )
    )
    $this->$attribute = $attributes[$attribute];
    $this->$attribute = $args[$attribute];

    if ( array_key_exists( 'data', $attributes ) )
    $this->data = wp_parse_args( $attributes['data'], $this->data );
    if ( array_key_exists( 'data', $args ) )
    $this->data = wp_parse_args( $args['data'], $this->data );
    }

    /**
    * Print the HTML for the `img` tag.
    *
    * @uses image_tag::get_html()
    *
    * @return string
    */
    function __toString() {
    return $this->get_html();
    @@ -120,6 +152,8 @@ function __toString() {
    *
    * @param string $property Property name.
    *
    * @uses image_tag::get_html()
    *
    * @return string
    */
    function get( $property ) {
    @@ -155,23 +189,39 @@ protected function get_attributes() {
    );
    }

    protected function _create_noscript_object( $source, $attributes, $args ) {
    /**
    * Maybe create noscript object.
    *
    * @param string $source Image source.
    * @param array $args Image object arguments.
    *
    * @uses get_image_tag_object()
    */
    protected function _maybe_create_noscript_object( $source, $args ) {
    if (
    !$this->_noscript
    || !empty( $this->noscript )
    )
    return;

    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( $source, $attributes, $args );
    $this->noscript = get_image_tag_object( $source, $args );
    }

    /**
    * Get image tag.
    *
    * @uses image_tag::get_attribtues()
    * @uses image_tag::maybe_get_noscript_html()
    * @uses image_tag::set_orientation()
    * @uses image_tag::maybe_set_lazyload_attributes()
    * @uses image_tag::get_attributes()
    *
    * @return string <img> tag.
    */
    function get_html() {
    $attributes = array();

    $this->set_orientation();
    $this->set_ratio();
    $this->maybe_set_lazyload_attributes();

    foreach ( array_filter( $this->get_attributes() ) as $attribute => $value )
    @@ -182,6 +232,8 @@ function get_html() {

    /**
    * Print image tag.
    *
    * @uses image_tag::get_html()
    */
    function the_html() {
    echo $this->get_html();
    @@ -216,9 +268,34 @@ protected function set_orientation() {
    else if ( $this->width === $this->height ) $this->_orientation = 'square';
    }

    /**
    * Determine and store image ratio (height divided by width).
    */
    protected function set_ratio() {
    $this->_ratio = !empty( $this->width )
    ? $this->height / $this->width
    : 0;
    }

    }


    /*
    ######## ## ## ######## ######## ######## ## ## ### ##
    ## ## ## ## ## ## ## ### ## ## ## ##
    ## ## ## ## ## ## ## #### ## ## ## ##
    ###### ### ## ###### ######## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## #### ######### ##
    ## ## ## ## ## ## ## ## ### ## ## ##
    ######## ## ## ## ######## ## ## ## ## ## ## ########
    */

    /**
    * External image handler.
    */
    class image_tag__external extends image_tag {}


    /*
    ## ## ####### ######## ######## ######## ######## ######## ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    @@ -232,8 +309,9 @@ protected function set_orientation() {
    /**
    * WordPress attachments handler.
    */
    class image_tag_wp_attachment extends image_tag {
    class image_tag__wp_attachment extends image_tag {

    /** @var int $_source_id Attachment object ID. */
    protected $_source_id = null;

    /** @var WP_Post $_post Post object of the attachment. **/
    @@ -242,7 +320,7 @@ class image_tag_wp_attachment extends image_tag {
    /** @var array $sizes List of registered image sizes. **/
    protected $_sizes = array();

    /** @var array $sizes_data Array of _image_tag_wp_attachment_image_size objects. **/
    /** @var array $sizes_data Array of _image_tag__wp_attachment_image_size objects. **/
    protected $_sizes_data = array(
    '__largest' => null,
    '__smallest' => null,
    @@ -252,21 +330,21 @@ class image_tag_wp_attachment extends image_tag {
    * Construct.
    *
    * @param int $source_id Attachment image object ID.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    *
    * @uses image_tag_wp_attachment::_add_size_data()
    * @uses image_tag__wp_attachment::_add_size_data()
    * @uses image_tag::__construct()
    */
    function __construct( $source_id, $attributes = array(), $args = array() ) {
    function __construct( $source_id, $args = array() ) {
    $this->_source_id = $source_id;
    $this->_post = get_post( $source_id );
    $this->_sizes = !empty( $args['image_sizes'] )
    ? $args['image_sizes']

    $this->_sizes = !empty( $args['wordpress']['image_sizes'] )
    ? $args['wordpress']['image_sizes']
    : array_merge( get_intermediate_image_sizes(), array( 'full' ) );

    $this->_sizes_data['__largest'] = new _image_tag_wp_attachment_image_size__largest;
    $this->_sizes_data['__smallest'] = new _image_tag_wp_attachment_image_size__smallest;
    $this->_sizes_data['__largest'] = new _image_tag__wp_attachment_image_size__largest;
    $this->_sizes_data['__smallest'] = new _image_tag__wp_attachment_image_size__smallest;

    foreach ( $this->_sizes as $size )
    $this->_add_size_data( $size );
    @@ -284,23 +362,25 @@ function __construct( $source_id, $attributes = array(), $args = array() ) {
    $this->srcset = implode( ', ', $srcset );
    }

    parent::__construct( $this->_sizes_data['__smallest']->get( 'src' ), $attributes, $args );
    unset( $args['wordpress'] );

    parent::__construct( $this->_sizes_data['__smallest']->get( 'src' ), $args );
    }

    /**
    * Get and store size data.
    *
    * @param string $size Image size name.
    *
    * @see _image_tag_wp_attachment_image_size
    * @see _image_tag__wp_attachment_image_size
    */
    protected function _add_size_data( string $size ) {
    protected function _add_size_data( $size ) {
    static $_class = null;

    if ( is_null( $_class ) )
    $_class = apply_filters( 'image_tag/_image_tag_wp_attachment_image_size', '_image_tag_wp_attachment_image_size' );
    $_class = apply_filters( 'image_tag/_image_tag__wp_attachment_image_size', '_image_tag__wp_attachment_image_size' );

    $this->_sizes_data[$size] = new $_class( $this->_source_id, $size );
    $this->_sizes_data[$size] = new $_class( $this, $size );

    if ( $this->_sizes_data[$size]->get( 'width' ) > $this->_sizes_data['__largest']->get( 'width' ) )
    $this->_sizes_data['__largest'] = $this->_sizes_data[$size];
    @@ -312,25 +392,31 @@ protected function _add_size_data( string $size ) {
    /**
    * Custom sort method to sort sizes by width descending.
    *
    * @param _image_tag_wp_attachment_image_size $a First image size object.
    * @param _image_tag_wp_attachment_image_size $b Second image size object.
    * @param _image_tag__wp_attachment_image_size $a First image size object.
    * @param _image_tag__wp_attachment_image_size $b Second image size object.
    *
    * @uses image_tag::get()
    */
    protected function _sort_sizes_asc( $a, $b ) {
    return $a->get( 'width' ) > $b->get( 'width' );
    }

    protected function _create_noscript_object( $source, $attributes, $args ) {
    error_log( print_r( array( $this->_source, $attributes, $args ), true ) );
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( $this->_source_id, $attributes, $args );
    /**
    * Maybe create noscript object.
    *
    * @param int $source Image attachment object ID.
    * @param array $args Image object arguments.
    *
    * @uses imagee_tag::_maybe_create_noscript_object()
    */
    protected function _maybe_create_noscript_object( $source, $args ) {
    parent::_maybe_create_noscript_object( $this->_source_id, $args );
    }

    /**
    * Get image sizes (except magicals).
    *
    * @return array of _image_tag_wp_attachment_image_size objects.
    * @return array of _image_tag__wp_attachment_image_size objects.
    */
    function get_sizes_data() {
    return array_filter(
    @@ -345,7 +431,7 @@ function ( $k ) {
    /**
    * Get largest image size.
    *
    * @return _image_tag_wp_attachment_image_size__largest
    * @return _image_tag__wp_attachment_image_size__largest
    */
    function get_largest_size() {
    return $this->_sizes_data['__largest'];
    @@ -354,7 +440,7 @@ function get_largest_size() {
    /**
    * Get smallest image size.
    *
    * @return _image_tag_wp_attachment_image_size__smallest
    * @return _image_tag__wp_attachment_image_size__smallest
    */
    function get_smallest_size() {
    return $this->_sizes_data['__smallest'];
    @@ -376,10 +462,10 @@ function has_size( $size ) {
    *
    * @param string $size Image size name.
    *
    * @uses image_tag_wp_attachment::has_size()
    * @uses image_tag_wp_attachment::get_sizes_data()
    * @uses image_tag__wp_attachment::has_size()
    * @uses image_tag__wp_attachment::get_sizes_data()
    *
    * @return _image_tag_wp_attachment_image_size|null
    * @return _image_tag__wp_attachment_image_size|null
    */
    function get_size( $size ) {
    return $this->has_size( $size )
    @@ -391,7 +477,14 @@ function get_size( $size ) {
    * Get image attachment object ID.
    */
    function get_attachment_id() {
    return $this->_source;
    return $this->_source_id;
    }

    /**
    * Get image attachment metdata.
    */
    function get_metadata() {
    return wp_get_attachment_metadata( $this->get_attachment_id() );
    }

    /**
    @@ -407,6 +500,58 @@ function get_html() {
    return parent::get_html();
    }

    /**
    * Check if image has mode color.
    *
    * @uses $this::get_mode_color()
    *
    * @return bool
    */
    function has_mode_color() {
    return !empty( $this->get_mode_color() );
    }

    function get_mode_color() {
    if ( !empty( get_post_meta( $this->get_attachment_id(), '_mode_color', true ) ) )
    return get_post_meta( $this->get_attachment_id(), '_mode_color', true );

    $class_filename = apply_filters( 'image_tag/get_mode_color/filepath', __DIR__ . '/class-get-image-most-common-colors.php' );
    list( $class_name, $function_name ) = apply_filters( 'image_tag/get_mode_color/function', array( 'GetImageMostCommonColors', 'Get_Colors' ) );

    if ( !file_exists( $class_filename ) )
    return false;

    require_once $class_filename;

    if (
    !empty( $class_name )
    && class_exists( $class_name )
    ) {
    $class = new $class_name;

    if ( !is_callable( array( $class, $function_name ) ) )
    return false;

    $callable = array( $class, $function_name );
    } else if ( empty( $class_name ) )
    $callable = $function_name;

    if ( empty( $callable ) )
    return false;

    $colors = call_user_func( $callable, $this->get_largest_size()->get( 'path' ) );

    if ( empty( $colors ) )
    return false;

    $colors = array_keys( $colors );
    $color = '#' . array_shift( $colors );

    add_post_meta( $this->get_attachment_id(), '_mode_color', $color );

    return $color;
    }

    }


    @@ -423,7 +568,7 @@ function get_html() {
    /**
    * Object for WordPress attachment image size.
    */
    class _image_tag_wp_attachment_image_size {
    class _image_tag__wp_attachment_image_size {

    /**
    * @var string $src Image size URI.
    @@ -432,6 +577,7 @@ class _image_tag_wp_attachment_image_size {
    * @var string $orientation Image size orientation.
    */
    protected $src = null,
    $path = null,
    $width = null,
    $height = null,
    $orientation = null;
    @@ -442,8 +588,8 @@ class _image_tag_wp_attachment_image_size {
    * @param int $source_id Source ID.
    * @param string $size Size name.
    */
    function __construct( int $source_id, string $size ) {
    $attachment = wp_get_attachment_image_src( $source_id, $size );
    function __construct( image_tag__wp_attachment &$image, $size ) {
    $attachment = wp_get_attachment_image_src( $image->get_attachment_id(), $size );

    if ( empty( $attachment ) )
    return;
    @@ -455,6 +601,14 @@ function __construct( int $source_id, string $size ) {
    ,
    ) = $attachment;

    $metadata = $image->get_metadata();
    $upload_dir = wp_upload_dir();

    if ( array_key_exists( $size, $metadata['sizes'] ) )
    $this->path = $upload_dir['basedir'] . '/' . trailingslashit( dirname( $metadata['file'] ) ) . $metadata['sizes'][$size]['file'];
    else if ( file_exists( $upload_dir['basedir'] . '/' . $metadata['file'] ) )
    $this->path = $upload_dir['basedir'] . '/' . $metadata['file'];

    if ( $this->width > $this->height )
    $this->orientation = 'landscape';

    @@ -490,15 +644,15 @@ function exists() {
    /**
    * Special class for largest WordPress image size.
    */
    class _image_tag_wp_attachment_image_size__largest extends _image_tag_wp_attachment_image_size {
    class _image_tag__wp_attachment_image_size__largest extends _image_tag__wp_attachment_image_size {
    /** Construct. */
    function __construct() { $this->width = 0; }
    }

    /**
    * Special class for smalleest WordPress image size.
    */
    class _image_tag_wp_attachment_image_size__smallest extends _image_tag_wp_attachment_image_size {
    class _image_tag__wp_attachment_image_size__smallest extends _image_tag__wp_attachment_image_size {
    /** Construct. */
    function __construct() { $this->width = 9999; }
    }
    @@ -518,63 +672,59 @@ function __construct() { $this->width = 9999; }
    * Placeholder.com (formerly placehold.it) handler.
    * @link https://placeholder.com
    */
    class image_tag_placeholder extends image_tag {
    class image_tag__placeholder extends image_tag {

    /**
    * Construct.
    *
    * @param string $source Only 'placeholder'.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param string $source Only 'placeholder'.
    * @param array $args Image object arguments.
    */
    function __construct( $source = 'placeholder', $attributes = array(), $args = array() ) {
    function __construct( $source = 'placeholder', $args = array() ) {
    $source = 'http://via.placeholder.com/';

    !empty( $args['width'] ) && empty( $args['placeholder']['width'] ) && $args['placeholder']['width'] = $args['width'];
    !empty( $args['height'] ) && empty( $args['placeholder']['height'] ) && $args['placeholder']['height'] = $args['height'];

    // add width dimension
    if ( array_key_exists( 'width', $args ) )
    $source .= $args['width'];
    else if ( array_key_exists( 'width', $attributes ) )
    $source .= $attributes['width'];
    $source .= $args['placeholder']['width'];

    // add height dimension
    if ( array_key_exists( 'height', $args ) )
    $source .= 'x' . $args['height'];
    else if ( array_key_exists( 'height', $attributes ) )
    $source .= 'x' . $attributes['height'];
    $source .= 'x' . $args['placeholder']['height'];

    // add background color
    if ( array_key_exists( 'color-bg', $args ) ) {
    $source .= '/' . $args['color-bg'];
    if ( array_key_exists( 'color-bg', $args['placeholder'] ) ) {
    $source .= '/' . $args['placeholder']['color-bg'];

    // add text color (background color must be specified)
    if ( array_key_exists( 'color-text', $args ) )
    $source .= '/' . $args['color-text'];
    if ( array_key_exists( 'color-text', $args['placeholder'] ) )
    $source .= '/' . $args['placeholder']['color-text'];
    }

    // add image format (gif, jpeg, jpg, png)
    if ( array_key_exists( 'format', $args ) )
    $source .= '.' . $args['format'];
    if ( array_key_exists( 'format', $args['placeholder'] ) )
    $source .= '.' . $args['placeholder']['format'];

    // add image text
    if ( array_key_exists( 'text', $args ) )
    $source = add_query_arg( 'text', $args['text'], $source );

    unset(
    $args['width'],
    $args['height'],
    $args['color-bg'],
    $args['color-text'],
    $args['format'],
    $args['text']
    );
    if ( array_key_exists( 'text', $args['placeholder'] ) )
    $source = add_query_arg( 'text', $args['placeholder']['text'], $source );

    unset( $args['placeholder'] );

    parent::__construct( $source, $attributes, $args );
    parent::__construct( $source, $args );

    }

    protected function _create_noscript_object( $source = 'placeholder', $attributes, $args ) {
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( 'placeholder', $attributes, $args );
    /**
    * Maybe create noscript object.
    *
    * @param string $source "Placeholder".
    * @param array $args Image object arguments.
    *
    * @uses imagee_tag::_maybe_create_noscript_object()
    */
    protected function _maybe_create_noscript_object( $source = 'placeholder', $args ) {
    parent::_maybe_create_noscript_object( 'placeholder', $args );
    }

    }
    @@ -594,127 +744,135 @@ protected function _create_noscript_object( $source = 'placeholder', $attributes
    * Picsum.photos handler.
    * @link https://picsum.photos
    */
    class image_tag_picsum extends image_tag {
    class image_tag__picsum extends image_tag {

    public static function create( $source, $args = array() ) {
    static $_random = 1;

    empty( $args['width'] ) && !empty( $args['picsum']['width'] ) && $args['width'] = $args['picsum']['width'];
    empty( $args['height'] ) && !empty( $args['picsum']['height'] ) && $args['height'] = $args['picsum']['height'];

    !empty( $args['width'] ) && empty( $args['picsum']['width'] ) && $args['picsum']['width'] = $args['width'];
    !empty( $args['height'] ) && empty( $args['picsum']['height'] ) && $args['picsum']['height'] = $args['height'];

    if ( empty( $args['picsum']['random'] ) ) {
    $cache_key = md5( serialize( array( $source, $args['picsum'] ) ) );
    $cache = wp_cache_get( $cache_key, __CLASS__, false, $found );

    if ( empty( $args['skip_cache'] ) && $found )
    return $cache;
    } else
    $args['picsum']['random'] = $_random++;

    $self = new static( $source, $args );

    if ( empty( $args['picsum']['random'] ) )
    wp_cache_add( $cache_key, $self, __CLASS__ );

    return $self;
    }

    /**
    * Construct.
    *
    * @param string $source Only 'picsum'.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param string $source Only 'picsum'.
    * @param array $args Image object arguments.
    */
    function __construct( $source, $attributes = array(), $args = array() ) {
    protected function __construct( $source, $args = array() ) {
    $source = 'https://picsum.photos/';

    if ( !empty( $args['gray'] ) )
    if ( !empty( $args['picsum']['gray'] ) )
    $source .= 'g/';

    if ( array_key_exists( 'width', $args ) )
    $source .= $args['width'];
    else if ( array_key_exists( 'width', $attributes ) )
    $source .= $attributes['width'];

    if ( array_key_exists( 'height', $args ) )
    $source .= '/' . $args['height'];
    else if ( array_key_exists( 'height', $args ) )
    $source .= '/' . $attributes['height'];

    if ( !empty( $args['image'] ) )
    $source = add_query_arg( 'image', $args['image'], $source );
    else if ( !empty( $args['random'] ) )
    $source = add_query_arg( 'random', 1, $source );

    if ( !empty( $args['blur'] ) )
    $source = add_query_arg( 'blur', 1, $source );

    if ( !empty( $args['gravity'] ) )
    $source = add_query_arg( 'gravity', $args['gravity'], $source );

    unset(
    $args['gray'],
    $args['width'],
    $args['height'],
    $args['image'],
    $args['blur'],
    $args['gravity']
    );
    $source .= $args['picsum']['width'];
    $source .= '/' . $args['picsum']['height'];

    if ( !empty( $args['picsum']['image'] ) )
    $source = add_query_arg( 'image', $args['picsum']['image'], $source );
    else if ( !empty( $args['picsum']['random'] ) )
    $source = add_query_arg( 'random', $args['picsum']['random'], $source );

    parent::__construct( $source, $attributes, $args );
    !empty( $args['picsum']['blur'] ) && $source = add_query_arg( 'blur', 1, $source );
    !empty( $args['picsum']['gravity'] ) && $source = add_query_arg( 'gravity', $args['picsum']['gravity'], $source );

    unset( $args['picsum'] );

    parent::__construct( $source, $args );

    }

    protected function _create_noscript_object( $source = 'picsum', $attributes, $args ) {
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( 'picsum', $attributes, $args );
    /**
    * Maybe create noscript object.
    *
    * @param int $source "Picsum".
    * @param array $args Image object arguments.
    *
    * @uses imagee_tag::_maybe_create_noscript_object()
    */
    protected function _maybe_create_noscript_object( $source = 'picsum', $args ) {
    parent::_maybe_create_noscript_object( 'picsum', $args );
    }

    }

    /**
    * Get image tag object.
    *
    * @param int|string $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param bool $skip_cache Skip the cached object.
    * @param int|string $source Image source.
    * @param array $args Image object arguments.
    *
    * @return image_tag
    */
    function get_image_tag_object( $source, $attributes = array(), $args = array(), $skip_cache = false ) {
    function get_image_tag_object( $source, $args = array() ) {
    static $_class_names = array();

    $cache_key = md5( serialize( array( $source, $args ) ) );
    $skip_cache || $cache = wp_cache_get( $cache_key, __FUNCTION__, false, $has_cache );

    if ( !empty( $has_cache ) )
    return $cache;
    if ( 'http' === substr( $source, 0, 4 ) )
    $class = 'image_tag__external';

    if (
    else if (
    is_numeric( $source )
    && intval( $source ) == $source
    )
    $class = 'image_tag_wp_attachment';
    $class = 'image_tag__wp_attachment';

    else if ( 'placeholder' === $source )
    $class = 'image_tag_placeholder';
    $class = 'image_tag__placeholder';

    else if ( 'picsum' === $source )
    $class = 'image_tag_picsum';
    $class = 'image_tag__picsum';

    if ( empty( $class ) )
    return;

    if ( !array_key_exists( $class, $_class_names ) )
    $_class_names[$class] = apply_filters( 'image_tag/' . $class, $class );

    $_image_tag = new $_class_names[$class]( $source, $attributes, $args );

    wp_cache_add( $cache_key, $_image_tag, __FUNCTION__ );
    $_image_tag = $_class_names[$class]::create( $source, $args );

    return $_image_tag;
    }

    /**
    * Print image tag.
    *
    * @param int|string $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param bool $skip_cache Skip the cached object.
    * @param int|string $source Image source.
    * @param array $args Image object arguments.
    *
    * @uses get_image_tag_object()
    */
    function image_tag( $source, $attributes = array(), $args = array(), $skip_cache = false ) {
    echo get_image_tag_object( $source, $attributes, $args, $skip_cache );
    function image_tag( $source, $args = array() ) {
    echo get_image_tag_object( $source, $args );
    }

    /**
    * Debug elements for image_tag.
    */
    function image_tag__debug() {
    image_tag( 'placeholder', array( 'width' => 250, 'height' => 150 ), array( 'text' => 'Hello' ) );
    image_tag( 'picsum', array( 'width' => 500, 'height' => 500 ), array( 'random' => 1 ) );
    image_tag( 11, array( 'width' => 300, 'style' => 'width: auto; height: 500px;' ), array( 'image_sizes' => array( 'thumbnail', 'full' ) ) );
    image_tag( 'https://images.unsplash.com/photo-1528485683898-7633212b3db6?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=dffe08428a166a76b5b6527aeae128ce&auto=format&fit=crop&w=4500&q=80', array( 'width' => 400 ) );
    image_tag( 'placeholder', array( 'width' => 250, 'height' => 150, 'placeholder' => array( 'text' => 'Hello' ) ) );
    image_tag( 'picsum', array( 'width' => 500, 'height' => 500, 'picsum' => array( 'random' => 1 ) ) );
    echo ( $wp = get_image_tag_object( 11, array( 'width' => 300, 'style' => 'width: auto; height: 500px;', 'wordpress' => array( 'image_sizes' => array( 'thumbnail', 'full' ) ) ) ) );
    echo $wp->get_mode_color();
    }

    ?>
  2. @crstauf crstauf revised this gist Jun 11, 2018. 1 changed file with 537 additions and 151 deletions.
    688 changes: 537 additions & 151 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -1,13 +1,15 @@
    <?php
    /**
    * Abstract object for image tag data.
    * Classes for image tag elements.
    *
    * @version 0.0.7.0
    * @link https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f
    */

    /**
    * Abstract object for image tag data.
    *
    * @link https://github.com/aFarkas/lazysizes Preferred lazy loading script.
    */
    abstract class image_tag {

    @@ -18,14 +20,33 @@ abstract class image_tag {
    protected $_source;

    /** @var bool $_noscript Switch to enable noscript tag. **/
    protected $_noscript = false;
    protected $_noscript = null;

    /** @var bool $_lazyload Switch to enable lazy load. **/
    protected $_lazyload = true;

    /** @var null|string $_orientation Orientation of the image. **/
    protected $_orientation = null;

    /** @var string $_orientation Orientation of the image. **/
    protected $_orientation = 'unknown';

    /**
    * @var string $id Image "id" atribute.
    * @var string $alt Image "alt" attribute.
    * @var string $src Image "src" attribute.
    * @var string $class Image "class" attribute.
    * @var string $sizes Image "sizes" attribute.
    * @var string $style Image "style" attribute.
    * @var string $title Image "title" attribute.
    * @var int|string $width Image "width" attribute.
    * @var int|string $height Image "height" attribute.
    * @var string $srcet Image "srcset" attribute.
    * @var array $data Image "data" attributes.
    * array(
    * 'src' => string (data-src attribute)
    * 'sizes' => string (data-sizes attribute)
    * 'expand' => string (data-expand attribute)
    * 'srcset' => string (data-srcset attribute)
    * )
    */
    var $id,
    $alt,
    $src,
    @@ -44,71 +65,177 @@ abstract class image_tag {
    'srcset' => null,
    );

    function __construct( $source, array $attributes = array(), array $args = array() ) {
    /** @var image_tag $noscript Noscript image object. */
    var $noscript;

    /**
    * Construct.
    *
    * @param mixed $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    *
    * @uses image_tag::get_attributes()
    * @uses image_tag::set_orientation()
    * @uses image_tag::maybe_set_lazyload_atributes()
    */
    function __construct( $source, $attributes = array(), $args = array() ) {
    $this->_source = $this->src = $source;

    $this->_source = $source;

    array_key_exists( 'noscript', $args ) && $this->_noscript = $args['noscript'];
    array_key_exists( 'lazyload', $args ) && $this->_lazyload = $args['lazyload'];

    foreach ( array( 'id', 'alt', 'src', 'class', 'sizes', 'style', 'title', 'width', 'height', 'srcset' ) as $attribute )
    if ( array_key_exists( $attribute, $attributes ) )

    if (
    is_null( $this->_noscript )
    && $this->_lazyload
    )
    $this->_noscript = true;

    if (
    $this->_noscript
    && empty( $this->noscript )
    )
    $this->_create_noscript_object( $source, $attributes, $args );

    foreach ( array_keys( $this->get_attributes() ) as $attribute )
    if (
    array_key_exists( $attribute, $attributes )
    && property_exists( $this, $attribute )
    )
    $this->$attribute = $attributes[$attribute];

    if ( array_key_exists( 'data', $attributes ) )
    $this->data = wp_parse_args( $attributes['data'], $this->data );

    if ( $attributes['width'] > $attributes['height'] )
    $this->_orientation = 'landscape';

    else if ( $attributes['width'] < $attributes['height'] )
    $this->_orientation = 'portrait';

    else if ( $attribtues['width'] == $attributes['height'] )
    $this->_orientation = 'square';

    }

    /**
    * Print the HTML for the `img` tag.
    */
    function __toString() {
    function __toString() {
    return $this->get_html();
    }

    function get_prop( string $prop ) {
    return property_exists( $this, $prop )
    ? $this->$prop
    }

    /**
    * Get image property.
    *
    * @param string $property Property name.
    *
    * @return string
    */
    function get( $property ) {
    if ( 'html' === $property )
    return $this->get_html();

    return property_exists( $this, $property )
    ? $this->$property
    : null;
    }

    /**
    * Get image attributes.
    *
    * @return array
    */
    protected function get_attributes() {
    return array(
    'id' => $this->id,
    'alt' => $this->alt,
    'src' => $this->src,
    'class' => $this->class,
    'sizes' => $this->sizes,
    'style' => $this->style,
    'title' => $this->title,
    'width' => $this->width,
    'height' => $this->height,
    'srcset' => $this->srcset,
    'data-src' => $this->data['src'],
    'data-sizes' => $this->data['sizes'],
    'data-expand' => $this->data['expand'],
    'data-srcset' => $this->data['srcset'],
    );
    }

    protected function _create_noscript_object( $source, $attributes, $args ) {
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( $source, $attributes, $args );
    }

    /**
    * Get image tag.
    *
    * @uses image_tag::get_attribtues()
    * @uses image_tag::maybe_get_noscript_html()
    *
    * @return string <img> tag.
    */
    function get_html() {
    $output = '<img src="' . $this->_source . '" />';
    $attributes = array();

    $this->set_orientation();
    $this->maybe_set_lazyload_attributes();

    $output .= $this->maybe_get_noscript_html();
    foreach ( array_filter( $this->get_attributes() ) as $attribute => $value )
    $attributes[] = $attribute . '="' . $value . '"';

    return $output;
    return '<img ' . implode( ' ', $attributes ) . ' />' . ( !empty( $this->noscript ) ? '<noscript>' . $this->noscript . '</noscript>' : '' );
    }

    function maybe_get_noscript_html() {
    if ( !$this->_noscript )
    return null;
    /**
    * Print image tag.
    */
    function the_html() {
    echo $this->get_html();
    }

    /**
    * Set attributes if lazyloading.
    */
    protected function maybe_set_lazyload_attributes() {
    if ( !$this->_lazyload )
    return;

    if ( !empty( $this->srcset ) ) {
    $this->data['srcset'] = $this->srcset;
    $this->srcset = null;
    } else
    $this->data['src'] = $this->src;

    $output = '<noscript>';
    if ( empty( $this->sizes ) )
    $this->data['sizes'] = 'auto';

    return $output . '</noscript>';
    $this->src = $this::DATAURI;
    $this->class .= ' lazyload hide-if-no-js';
    }

    /**
    * Determine and store image orientation.
    */
    protected function set_orientation() {
    if ( $this->width > $this->height ) $this->_orientation = 'landscape';
    else if ( $this->width < $this->height ) $this->_orientation = 'portrait';
    else if ( $this->width === $this->height ) $this->_orientation = 'square';
    }

    }


    /*
    ## ## ####### ######## ######## ######## ######## ######## ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ######## ## ## ######## ######## ###### ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ### ### ####### ## ## ######## ## ## ## ######## ###### ######
    */

    /**
    * Image tag for WordPress attachments.
    * WordPress attachments handler.
    */
    class image_tag_wp_attachment extends image_tag {

    /** @var int $_source Attachment object ID. **/
    protected $_source = null;


    protected $_source_id = null;

    /** @var WP_Post $_post Post object of the attachment. **/
    protected $_post = null;

    @@ -121,183 +248,422 @@ class image_tag_wp_attachment extends image_tag {
    '__smallest' => null,
    );

    function __construct( int $source_id, array $attributes = array(), array $args = array() ) {
    parent::__construct( $source_id, $attributes, $args );

    $this->_post = get_post( $source_id );
    $this->_sizes = !empty( $args['image_sizes'] )
    ? $args['image_sizes']
    /**
    * Construct.
    *
    * @param int $source_id Attachment image object ID.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    *
    * @uses image_tag_wp_attachment::_add_size_data()
    * @uses image_tag::__construct()
    */
    function __construct( $source_id, $attributes = array(), $args = array() ) {
    $this->_source_id = $source_id;
    $this->_post = get_post( $source_id );
    $this->_sizes = !empty( $args['image_sizes'] )
    ? $args['image_sizes']
    : array_merge( get_intermediate_image_sizes(), array( 'full' ) );

    $this->_sizes_data['__largest'] = new _image_tag_wp_attachment_image_size__largest;
    $this->_sizes_data['__smallest'] = new _image_tag_wp_attachment_image_size__smallest;

    foreach ( $this->_sizes as $size )
    $this->_add_size_data( $size );

    uasort( $this->_sizes_data, array( &$this, '_sort_sizes_asc' ) );

    if ( 1 === count( $this->_sizes ) )
    $this->src = $this->_sizes_data['__smallest']->get( 'src' );
    else {
    $srcset = array();

    foreach ( $this->_sizes_data as $size )
    $srcset[] = $size->get( 'src' ) . ' ' . $size->get( 'width' ) . 'w';

    $this->srcset = implode( ', ', $srcset );
    }

    parent::__construct( $this->_sizes_data['__smallest']->get( 'src' ), $attributes, $args );
    }

    /**
    * Get and store size data.
    *
    * @param string $size Image size name.
    *
    * @see _image_tag_wp_attachment_image_size
    */
    protected function _add_size_data( string $size ) {
    static $_class = null;

    if ( is_null( $_class ) )
    $_class = apply_filters( 'image_tag/_image_tag_wp_attachment_image_size', '_image_tag_wp_attachment_image_size' );

    if ( is_null( $this->_sizes_data['__largest'] ) ) {
    $this->_sizes_data['__largest'] = new _image_tag_wp_attachment_image_size__largest;
    $this->_sizes_data['__smallest'] = new _image_tag_wp_attachment_image_size__smallest;
    }

    $this->_sizes_data[$size] = new $_class( $this->_source, $size );
    $this->_sizes_data[$size] = new $_class( $this->_source_id, $size );

    if ( $this->_sizes_data[$size]->get( 'width' ) > $this->_sizes_data['__largest']->get( 'width' ) )
    $this->_sizes_data['__largest'] = $this->_sizes_data[$size];

    if ( $this->_sizes_data[$size]->get( 'width' ) < $this->_sizes_data['__smallest']->get( 'width' ) )
    $this->_sizes_data['__smallest'] = $this->_sizes_data[$size];
    }

    /**
    * Custom sort method to sort sizes by width descending.
    *
    * @param _image_tag_wp_attachment_image_size $a First image size object.
    * @param _image_tag_wp_attachment_image_size $b Second image size object.
    *
    * @uses image_tag::get()
    */
    protected function _sort_sizes_asc( $a, $b ) {
    return $a->get( 'width' ) > $b->get( 'width' );
    }

    protected function _create_noscript_object( $source, $attributes, $args ) {
    error_log( print_r( array( $this->_source, $attributes, $args ), true ) );
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( $this->_source_id, $attributes, $args );
    }

    /**
    * Get image sizes (except magicals).
    *
    * @return array of _image_tag_wp_attachment_image_size objects.
    */
    function get_sizes_data() {
    return array_filter(
    $this->_sizes_data,
    function ( $k ) {
    return '__' !== substr( $k, 0, 2 );
    },
    ARRAY_FILTER_USE_KEY
    return array_filter(
    $this->_sizes_data,
    function ( $k ) {
    return '__' !== substr( $k, 0, 2 );
    },
    ARRAY_FILTER_USE_KEY
    );
    }

    function has_size( string $size ) {
    return array_key_exists( $size, $this->get_sizes_data() );
    }
    /**
    * Get largest image size.
    *
    * @return _image_tag_wp_attachment_image_size__largest
    */
    function get_largest_size() {
    return $this->_sizes_data['__largest'];
    }

    /**
    * Get smallest image size.
    *
    * @return _image_tag_wp_attachment_image_size__smallest
    */
    function get_smallest_size() {
    return $this->_sizes_data['__smallest'];
    }

    /**
    * Check if image has size.
    *
    * @param string $size Image size name.
    *
    * @return bool
    */
    function has_size( $size ) {
    return array_key_exists( $size, $this->get_sizes_data() );
    }

    function get_size( string $size ) {
    return $this->has_size( $size )
    ? $this->get_sizes_data()[$size]
    : null;
    }
    /**
    * Get image size object.
    *
    * @param string $size Image size name.
    *
    * @uses image_tag_wp_attachment::has_size()
    * @uses image_tag_wp_attachment::get_sizes_data()
    *
    * @return _image_tag_wp_attachment_image_size|null
    */
    function get_size( $size ) {
    return $this->has_size( $size )
    ? $this->get_sizes_data()[$size]
    : null;
    }

    /**
    * Get image attachment object ID.
    */
    function get_attachment_id() {
    return $this->_source;
    }

    /**
    * Get image tag.
    *
    * @return string <img> tag.
    */
    function get_html() {
    do_action_ref_array( 'image_tag/' . $this->_source . '/before_output', array( &$this ) );
    do_action_ref_array( 'image_tag/before_output', array( $this->_source, &$this ) );
    do_action_ref_array( 'imadge_tag/before_output', array( $this->_source, &$this ) );

    // return parent::get_html();
    $this->src = $this->get_smallest_size()->get( 'src' );

    return '<img src="' . $this->get_size( 'medium_large' )->get( 'src' ) . '" />';
    return parent::get_html();
    }

    }


    /*
    ## ## ######## #### ## ## ### ###### ######## ###### #### ######## ########
    ## ## ## ## ## ## ### ### ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## #### #### ## ## ## ## ## ## ## ##
    ## ## ## ######## ## ## ### ## ## ## ## #### ###### ###### ## ## ######
    ## ## ## ## ## ## ## ######### ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ### ### ## #### ## ## ## ## ###### ######## ###### #### ######## ########
    */

    /**
    * Object for WordPress attachment image size.
    */
    class _image_tag_wp_attachment_image_size {

    protected $src = null;
    protected $width = null;
    protected $height = null;
    protected $orientation = null;

    /**
    * Get the properties of the image size.
    *
    * @param int $source_id Source ID.
    * @param string $size Size name.
    */
    /**
    * @var string $src Image size URI.
    * @var int $width Image size width.
    * @var int $height Image size height.
    * @var string $orientation Image size orientation.
    */
    protected $src = null,
    $width = null,
    $height = null,
    $orientation = null;

    /**
    * Get the properties of the image size.
    *
    * @param int $source_id Source ID.
    * @param string $size Size name.
    */
    function __construct( int $source_id, string $size ) {
    $attachment = wp_get_attachment_image_src( $source_id, $size );

    if ( empty( $attachment ) )
    return;
    if ( empty( $attachment ) )
    return;

    list(
    $this->src,
    $this->width,
    $this->height,
    ,
    ) = $attachment;

    list(
    $this->src,
    $this->width,
    $this->height,
    ,
    ) = $attachment;

    if ( $this->width > $this->height )
    $this->orientation = 'landscape';

    else if ( $this->width < $this->height )
    $this->orientation = 'portrait';

    else if ( $this->width == $this->height )
    $this->orientation = 'square';
    }

    function get( string $prop ) {
    /**
    * Get image size property.
    *
    * @param string $prop Property name.
    *
    * @return string|int
    */
    function get( $prop ) {
    return property_exists( $this, $prop )
    ? $this->$prop
    : null;
    }

    function exists() {
    return !empty( $this->get( 'src' ) );
    }
    /**
    * Check if size has image URI.
    */
    function exists() {
    return !empty( $this->get( 'src' ) );
    }

    }

    class _image_tag_wp_attachment_image_size__largest extends _image_tag_wp_attachment_image_size { protected $width = 0; function __construct() {} }
    class _image_tag_wp_attachment_image_size__smallest extends _image_tag_wp_attachment_image_size { protected $width = 9999; function __construct() {} }
    /**
    * Special class for largest WordPress image size.
    */
    class _image_tag_wp_attachment_image_size__largest extends _image_tag_wp_attachment_image_size {
    /** Construct. */
    function __construct() { $this->width = 0; }
    }

    /**
    * Special class for smalleest WordPress image size.
    */
    class _image_tag_wp_attachment_image_size__smallest extends _image_tag_wp_attachment_image_size {
    /** Construct. */
    function __construct() { $this->width = 9999; }
    }


    /*
    ######## ## ### ###### ######## ## ## ####### ## ######## ######## ########
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ######## ## ## ## ## ###### ######### ## ## ## ## ## ###### ########
    ## ## ######### ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ######## ## ## ###### ######## ## ## ####### ######## ######## ######## ## ##
    */

    /**
    * Placeholder.com (formerly placehold.it) handler.
    * @link https://placeholder.com
    */
    class image_tag_placeholder extends image_tag {

    function __construct( string $source, array $attributes = array(), array $args = array() ) {
    /**
    * Construct.
    *
    * @param string $source Only 'placeholder'.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    */
    function __construct( $source = 'placeholder', $attributes = array(), $args = array() ) {
    $source = 'http://via.placeholder.com/';

    // add width dimension
    if ( array_key_exists( 'width', $args ) )
    $source .= $args['width'];
    else if ( array_key_exists( 'width', $attributes ) )
    $source .= $attributes['width'];

    // add height dimension
    if ( array_key_exists( 'height', $args ) )
    $source .= 'x' . $args['height'];
    else if ( array_key_exists( 'height', $attributes ) )
    $source .= 'x' . $attributes['height'];

    // add background color
    if ( array_key_exists( 'color-bg', $args ) ) {
    $source .= '/' . $args['color-bg'];

    // add text color (background color must be specified)
    if ( array_key_exists( 'color-text', $args ) )
    $source .= '/' . $args['color-text'];
    }

    $details = array(
    'width' => null,
    'height' => null,
    'text' => null,
    // add image format (gif, jpeg, jpg, png)
    if ( array_key_exists( 'format', $args ) )
    $source .= '.' . $args['format'];

    // add image text
    if ( array_key_exists( 'text', $args ) )
    $source = add_query_arg( 'text', $args['text'], $source );

    unset(
    $args['width'],
    $args['height'],
    $args['color-bg'],
    $args['color-text'],
    $args['format'],
    $args['text']
    );

    preg_match( '/^http:\/\/via\.placeholder.com\/([0-9]*)(?:x([0-9]*))?.*(?:\/?\?text=(.*))?$/', $source, $matches );

    if ( empty( $matches ) ) {
    if (
    !empty( $attributes['width'] )
    && !empty( $attributes['height'] )
    ) {
    $source = 'http://via.placeholder.com/' . $attributes['width'] . 'x' . $attributes['height'];
    empty( $attributes['alt'] ) || add_query_arg( 'text', $attributes['alt'], $source );
    empty( $attributes['title'] ) || add_query_arg( 'text', $attributes['title'], $source );
    } else
    return;
    }

    parent::__construct( $source, $attributes, $args );
    parent::__construct( $source, $attributes, $args );

    }

    protected function _create_noscript_object( $source = 'placeholder', $attributes, $args ) {
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( 'placeholder', $attributes, $args );
    }

    }


    /*
    ######## #### ###### ###### ## ## ## ##
    ## ## ## ## ## ## ## ## ## ### ###
    ## ## ## ## ## ## ## #### ####
    ######## ## ## ###### ## ## ## ### ##
    ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ##
    ## #### ###### ###### ####### ## ##
    */

    /**
    * Picsum.photos handler.
    * @link https://picsum.photos
    */
    class image_tag_picsum extends image_tag {

    function __construct( string $source, array $attributes = array(), array $args = array() ) {
    preg_match( '/^https:\/\/picsum.photos\/(?:g\/)?([0-9]*)(?:\/([0-9]*))?.*$/', $source, $matches );

    if ( empty( $matches ) ) {
    if (
    !empty( $attributes['width'] )
    && !empty( $attributes['height'] )
    )
    $source = 'https://picsum.photos/' . $attributes['width'] . '/' . $attributes['height'] . '/?random';
    else
    return;
    }


    /**
    * Construct.
    *
    * @param string $source Only 'picsum'.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    */
    function __construct( $source, $attributes = array(), $args = array() ) {
    $source = 'https://picsum.photos/';

    if ( !empty( $args['gray'] ) )
    $source .= 'g/';

    if ( array_key_exists( 'width', $args ) )
    $source .= $args['width'];
    else if ( array_key_exists( 'width', $attributes ) )
    $source .= $attributes['width'];

    if ( array_key_exists( 'height', $args ) )
    $source .= '/' . $args['height'];
    else if ( array_key_exists( 'height', $args ) )
    $source .= '/' . $attributes['height'];

    if ( !empty( $args['image'] ) )
    $source = add_query_arg( 'image', $args['image'], $source );
    else if ( !empty( $args['random'] ) )
    $source = add_query_arg( 'random', 1, $source );

    if ( !empty( $args['blur'] ) )
    $source = add_query_arg( 'blur', 1, $source );

    if ( !empty( $args['gravity'] ) )
    $source = add_query_arg( 'gravity', $args['gravity'], $source );

    unset(
    $args['gray'],
    $args['width'],
    $args['height'],
    $args['image'],
    $args['blur'],
    $args['gravity']
    );

    parent::__construct( $source, $attributes, $args );


    }

    protected function _create_noscript_object( $source = 'picsum', $attributes, $args ) {
    $args['noscript'] = $args['lazyload'] = false;
    $this->noscript = get_image_tag_object( 'picsum', $attributes, $args );
    }

    }

    function get_image_tag_object( $source, array $args = array(), bool $skip_cache = false ) {
    /**
    * Get image tag object.
    *
    * @param int|string $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param bool $skip_cache Skip the cached object.
    *
    * @return image_tag
    */
    function get_image_tag_object( $source, $attributes = array(), $args = array(), $skip_cache = false ) {
    static $_class_names = array();

    $cache_key = md5( $source . '_' . json_encode( $args ) );
    $cache_key = md5( serialize( array( $source, $args ) ) );
    $skip_cache || $cache = wp_cache_get( $cache_key, __FUNCTION__, false, $has_cache );

    if ( !empty( $has_cache ) )
    @@ -309,26 +675,46 @@ function get_image_tag_object( $source, array $args = array(), bool $skip_cache
    )
    $class = 'image_tag_wp_attachment';

    else if (
    'placeholder' === $source
    || false !== stripos( $source, 'via.placeholder.com' )
    )
    else if ( 'placeholder' === $source )
    $class = 'image_tag_placeholder';

    else if (
    'picsum' === $source
    || false !== stripos( $source, 'picsum.photos' )
    )

    else if ( 'picsum' === $source )
    $class = 'image_tag_picsum';

    if ( empty( $class ) )
    return;

    if ( !array_key_exists( $class, $_class_names ) )
    $_class_names[$class] = apply_filters( 'image_tag/' . $class, $class );

    $_image_tag = new $_class_names[$class]( $source, $args );
    $_image_tag = new $_class_names[$class]( $source, $attributes, $args );

    wp_cache_add( $cache_key, $_image_tag, __FUNCTION__ );
    wp_cache_add( $cache_key, $_image_tag, __FUNCTION__ );

    return $_image_tag;
    return $_image_tag;
    }

    /**
    * Print image tag.
    *
    * @param int|string $source Image source.
    * @param array $attributes Image attributes.
    * @param array $args Image object arguments.
    * @param bool $skip_cache Skip the cached object.
    *
    * @uses get_image_tag_object()
    */
    function image_tag( $source, $attributes = array(), $args = array(), $skip_cache = false ) {
    echo get_image_tag_object( $source, $attributes, $args, $skip_cache );
    }

    /**
    * Debug elements for image_tag.
    */
    function image_tag__debug() {
    image_tag( 'placeholder', array( 'width' => 250, 'height' => 150 ), array( 'text' => 'Hello' ) );
    image_tag( 'picsum', array( 'width' => 500, 'height' => 500 ), array( 'random' => 1 ) );
    image_tag( 11, array( 'width' => 300, 'style' => 'width: auto; height: 500px;' ), array( 'image_sizes' => array( 'thumbnail', 'full' ) ) );
    }

    ?>
  3. @crstauf crstauf revised this gist Apr 8, 2018. 1 changed file with 295 additions and 386 deletions.
    681 changes: 295 additions & 386 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -1,425 +1,334 @@
    <?php

    // !!! ALPHA VERSION !!!
    // !!! ALPHA VERSION !!!
    // !!! ALPHA VERSION !!!
    // !!! NOT FOR PRODUCTION USE !!!
    // !!! USE LATEST STABLE v0.0.3.1:
    // https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f/e671037f46d8262357bbcef53581ac8235044e56

    // https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f

    if (!defined('ABSPATH') || !function_exists('add_filter')) {
    header( 'Status: 403 Forbidden' );
    header( 'HTTP/1.1 403 Forbidden' );
    exit();
    }

    class image_tag {

    const VERSION = '0.0.4-alpha';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    protected $args = array();

    var $attributes = array(
    'id' => '',
    'alt' => '',
    'src' => '',
    'sizes' => '',
    'title' => '',
    'width' => 0,
    'height' => 0,
    'srcset' => array(),
    'class' => array(),
    ),

    $echo = true,
    $noscript = true,
    $lazyload = true,
    $lazypreload = false,
    $noscript_sizes = array();

    protected $files = array(
    '__smallest' => array(
    'width' => 9999999,
    'height' => 9999999,
    'url' => ''
    ),
    '__largest' => array(
    'width' => 0,
    'height' => 0,
    'url' => '',
    ),
    );

    protected $orientation = ''; // portrait|landscape

    function __construct() {
    if ( !is_subclass_of( $this, 'image_tag' ) ) {

    $args = func_get_arg( 0 );
    if ( array_key_exists( 'attachment_id', $args ) )
    $source = $args['attachment_id'];
    else if ( array_key_exists( 'source', $args ) )
    $source = $args['source'];
    else if ( array_key_exists( 'theme_image', $args ) )
    $source = $args['theme_image'];
    else
    return false;

    $args['attributes']['class']['old-generated'] = 'old-generated-image-tag';

    unset(
    $args['attachment_id'],
    $args['source'],
    $args['theme_image']
    );

    if (
    array_key_exists( 'echo', $args )
    && false === $args['echo']
    )
    return image_tag( $source, $args );
    else
    echo image_tag( $source, $args );
    }

    add_filter( 'image-tag/noscript/attributes/glue', array( &$this, 'filter_image_tag_noscript_attributes_glue' ) );

    if ( is_array( $this->args ) && count( $this->args ) )
    foreach ( $this->args as $key => $value )
    if ( isset( $this->$key ) )
    $this->$key = $value;

    $this->attributes['class']['generated'] = 'generated-image-tag';

    $this->gather_files();
    $this->determine_orientation();
    $this->being_lazy();

    }

    /**
    * Abstract object for image tag data.
    *
    * @version 0.0.7.0
    * @link https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f
    */

    /**
    * Abstract object for image tag data.
    */
    abstract class image_tag {

    const VERSION = '0.0.7.0';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    /** @var mixed $_source Image source. **/
    protected $_source;

    /** @var bool $_noscript Switch to enable noscript tag. **/
    protected $_noscript = false;

    /** @var bool $_lazyload Switch to enable lazy load. **/
    protected $_lazyload = true;

    /** @var null|string $_orientation Orientation of the image. **/
    protected $_orientation = null;

    var $id,
    $alt,
    $src,
    $class,
    $sizes,
    $style,
    $title,
    $width,
    $height,
    $srcset,

    $data = array(
    'src' => null,
    'sizes' => null,
    'expand' => null,
    'srcset' => null,
    );

    function __construct( $source, array $attributes = array(), array $args = array() ) {

    $this->_source = $source;

    array_key_exists( 'noscript', $args ) && $this->_noscript = $args['noscript'];
    array_key_exists( 'lazyload', $args ) && $this->_lazyload = $args['lazyload'];

    foreach ( array( 'id', 'alt', 'src', 'class', 'sizes', 'style', 'title', 'width', 'height', 'srcset' ) as $attribute )
    if ( array_key_exists( $attribute, $attributes ) )
    $this->$attribute = $attributes[$attribute];

    if ( array_key_exists( 'data', $attributes ) )
    $this->data = wp_parse_args( $attributes['data'], $this->data );

    if ( $attributes['width'] > $attributes['height'] )
    $this->_orientation = 'landscape';

    else if ( $attributes['width'] < $attributes['height'] )
    $this->_orientation = 'portrait';

    else if ( $attribtues['width'] == $attributes['height'] )
    $this->_orientation = 'square';

    }

    /**
    * Print the HTML for the `img` tag.
    */
    function __toString() {
    if ( !$this->echo )
    return '';

    ksort( $this->attributes );

    $image_output = $this->image_output();

    if ( !$this->noscript )
    return implode( "\n", $image_output );

    $this->noscript_prep();

    return implode( "\n", array_filter( $image_output ) ) . implode( "\n", array_filter( $this->noscript_image_output() ) );
    }

    function image_output() {
    $output = array( 'open' => "\n<img " );

    foreach ( $this->attributes as $attr_name => $attr_value ) {

    $attr_value = apply_filters( 'image-tag/attributes/value', $attr_value, $attr_name, $this );
    $attr_value = apply_filters( 'image-tag/attributes/' . $attr_name . '/value', $attr_value, $this );

    $output[$attr_name] = $this->construct_attribute( $attr_name, $attr_value );

    if ( '' === trim( $output[$attr_name] ) )
    unset( $output[$attr_name] );

    }

    $output['close'] = "/>\n";

    return array_filter( $output );
    }

    function noscript_prep() {

    $this->attributes['class']['noscript'] = 'noscript';
    $this->attributes['class']['post-noscript'] = $this->attributes['class']['post'] . '-noscript';

    if ( !empty( $this->attributes['id'] ) )
    $this->attributes['id'] .= '-noscript';

    if ( array_key_exists( 'data-sizes', $this->attributes ) )
    $this->attributes['sizes'] = $this->attributes['data-sizes'];

    if ( array_key_exists( 'data-src', $this->attributes ) && self::DATAURI !== $this->attributes['data-src'] )
    $this->attributes['src'] = $this->attributes['data-src'];

    if ( 'auto' === $this->attributes['sizes'] ) {

    if ( !empty( $this->noscript_sizes ) && is_array( $this->noscript_sizes ) && count( $this->noscript_sizes ) ) {

    $this->attributes['sizes'] = $this->noscript_sizes;

    if ( array_key_exists( 'data-srcset', $this->attributes ) )
    $this->attributes['srcset'] = $this->attributes['data-srcset'];

    } else {
    $this->attributes['src'] = $this->files['__largest']['url'];
    unset( $this->attributes['sizes'] );
    }

    }

    unset(
    $this->attributes['class']['lazyload'],
    $this->attributes['class']['lazypreload'],
    $this->attribtues['data-src'],
    $this->attributes['data-sizes'],
    $this->attributes['data-srcset']
    );
    }

    function noscript_image_output() {
    $output = array(
    'open_noscript' => '<noscript>',
    'open_img' => "\t<img",
    );

    foreach ( $this->attributes as $attr_name => $attr_value ) {

    $attr_value = apply_filters( 'image-tag/noscript/attributes/value', $attr_value, $attr_name, $this );
    $attr_value = apply_filters( 'image-tag/noscript/attributes/' . $attr_name . '/value', $attr_value, $this );

    $output[$attr_name] = "\t" . $this->construct_attribute( $attr_name, $attr_value, true );

    if ( '' === trim( $output[$attr_name] ) )
    unset( $output[$attr_name] );

    }

    $output['close_img'] = "\n\t/>";
    $output['close_noscript'] = "</noscript>\n";

    return array_filter( $output );
    }

    function construct_attribute( $attr_name, $attr_value, $noscript = false ) {
    if ( !is_array( $attr_value ) ) {
    if ( !empty( $attr_value ) && ( '' !== trim( $attr_value ) || 'alt' === $attr_name ) )
    return "\t" . $attr_name . '="' . esc_attr( $attr_value ) . '" ';
    return false;
    }

    if ( false !== strpos( $attr_name, 'srcset' ) && count( $attr_value ) )
    foreach ( $attr_value as $w => $url )
    $attr_value[$w] = $url . ' ' . $w;

    switch ( $attr_name ) {
    case 'sizes':
    case 'srcset':
    case 'data-srcset':
    $glue = ",\n\t\t";
    break;
    case 'class':
    default:
    $glue = ' ';
    break;
    }

    $glue = apply_filters( 'image-tag/' . ( $noscript ? 'noscript/' : '' ) . 'attributes/glue', $glue, $attr_name, $this );
    $glue = apply_filters( 'image-tag/' . ( $noscript ? 'noscript/' : '' ) . 'attributes/' . $attr_name . '/glue', $glue, $this );

    foreach ( $attr_value as $i => $maybe_array )
    if ( is_array( $maybe_array ) )
    $attr_value[$i] = implode( $glue, $maybe_array );

    return "\t" . $attr_name . '="' . implode( $glue, $attr_value ) . '" ';
    }

    function filter_image_tag_noscript_attributes_glue( $glue ) {
    if ( ' ' === $glue )
    return ' ';
    return $glue . "\t";
    }

    function determine_orientation() {
    $largest = &$this->files['__largest'];

    if ( $largest['width'] > $largest['height'] )
    $this->orientation = 'landscape';
    else if ( $largest['width'] < $largest['height'] )
    $this->orientation = 'portrait';
    else if ( $largest['width'] === $largest['height'] )
    $this->orientation = 'square';
    else
    $this->orientation = false;

    $this->attributes['class']['orientation'] = 'orientation-' .
    ( false === $this->orientation
    ? 'unknown'
    : $this->orientation
    );
    return $this->get_html();
    }

    function get_prop( string $prop ) {
    return property_exists( $this, $prop )
    ? $this->$prop
    : null;
    }

    function gather_files() {}

    function being_lazy() {
    if ( !$this->lazyload && !$this->lazypreload )
    return false;

    if ( $this->lazypreload )
    $this->attributes['class']['lazypreload'] = 'lazypreload';

    if ( !$this->lazyload )
    return false;
    function get_html() {
    $output = '<img src="' . $this->_source . '" />';

    $this->attributes['data-sizes'] = 'auto';
    $output .= $this->maybe_get_noscript_html();

    $this->attributes['class']['lazyload'] = 'lazyload';
    return $output;
    }

    $this->attributes['src'] = self::DATAURI;
    $this->attributes['data-src' . ( count( $this->files ) > 3 ? 'set' : '' )] = $this->attributes['srcset'];
    function maybe_get_noscript_html() {
    if ( !$this->_noscript )
    return null;

    unset( $this->attributes['srcset'] );
    $output = '<noscript>';

    return true;
    }
    return $output . '</noscript>';
    }

    }


    /*
    ## ## ####### ######## ######## ######## ######## ######## ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ######## ## ## ######## ######## ###### ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ### ### ####### ## ## ######## ## ## ## ######## ###### ######
    */

    /**
    * Image tag for WordPress attachments.
    */
    class image_tag_wp_attachment extends image_tag {

    var $id = 0,
    $post = null,
    $image_sizes = array( 'thumbnail', 'medium', 'medium_large', 'large', 'full' );

    function __construct() {
    $this->args = func_get_arg( 0 );

    parent::__construct();

    $this->get_post();

    if (
    false === $this->post
    || is_wp_error( $this->post )
    )
    return;

    $this->attributes['class']['post'] = 'post-' . $this->id;


    /** @var int $_source Attachment object ID. **/
    protected $_source = null;

    /** @var WP_Post $_post Post object of the attachment. **/
    protected $_post = null;

    /** @var array $sizes List of registered image sizes. **/
    protected $_sizes = array();

    /** @var array $sizes_data Array of _image_tag_wp_attachment_image_size objects. **/
    protected $_sizes_data = array(
    '__largest' => null,
    '__smallest' => null,
    );

    function __construct( int $source_id, array $attributes = array(), array $args = array() ) {
    parent::__construct( $source_id, $attributes, $args );

    $this->_post = get_post( $source_id );
    $this->_sizes = !empty( $args['image_sizes'] )
    ? $args['image_sizes']
    : array_merge( get_intermediate_image_sizes(), array( 'full' ) );

    foreach ( $this->_sizes as $size )
    $this->_add_size_data( $size );

    }

    protected function _add_size_data( string $size ) {
    static $_class = null;

    if ( is_null( $_class ) )
    $_class = apply_filters( 'image_tag/_image_tag_wp_attachment_image_size', '_image_tag_wp_attachment_image_size' );

    if ( is_null( $this->_sizes_data['__largest'] ) ) {
    $this->_sizes_data['__largest'] = new _image_tag_wp_attachment_image_size__largest;
    $this->_sizes_data['__smallest'] = new _image_tag_wp_attachment_image_size__smallest;
    }

    $this->_sizes_data[$size] = new $_class( $this->_source, $size );

    if ( $this->_sizes_data[$size]->get( 'width' ) > $this->_sizes_data['__largest']->get( 'width' ) )
    $this->_sizes_data['__largest'] = $this->_sizes_data[$size];

    if ( $this->_sizes_data[$size]->get( 'width' ) < $this->_sizes_data['__smallest']->get( 'width' ) )
    $this->_sizes_data['__smallest'] = $this->_sizes_data[$size];
    }

    function get_sizes_data() {
    return array_filter(
    $this->_sizes_data,
    function ( $k ) {
    return '__' !== substr( $k, 0, 2 );
    },
    ARRAY_FILTER_USE_KEY
    );
    }

    function has_size( string $size ) {
    return array_key_exists( $size, $this->get_sizes_data() );
    }

    function noscript_prep() {
    parent::noscript_prep();

    if ( !empty( $this->attributes['sizes'] ) || !empty( $this->noscript_sizes ) )
    return;

    $largest = $this->files['__largest'];

    foreach ( $this->files as $size => $file ) {
    if ( in_array( $size, array( '__largest', '__smallest' ) ) )
    continue;
    if ( $file['url'] === $largest['url'] ) {
    $this->attributes['class']['WP-size'] = 'size-' . $size;
    break;
    }
    }
    function get_size( string $size ) {
    return $this->has_size( $size )
    ? $this->get_sizes_data()[$size]
    : null;
    }

    function get_post() {
    $this->post = get_post( $this->id );

    if ( '' === $this->attributes['alt'] )
    $this->attributes['alt'] = esc_attr( get_the_title( $this->post ) );

    if ( '' === $this->attributes['title'] )
    $this->attributes['title'] = esc_attr( get_the_title( $this->post ) );
    }

    function gather_files() {

    foreach ( $this->image_sizes as $i => $image_size ) {

    $this->attributes['class']['WP-size'][$image_size] = 'size-' . $image_size;

    $img = wp_get_attachment_image_src( $this->id, $image_size );
    function get_attachment_id() {
    return $this->_source;
    }

    if ( 0 === $i ) {
    $this->attributes['src'] = $img[0];
    $this->attributes['width'] = $img[1];
    $this->attributes['height'] = $img[2];
    }
    function get_html() {
    do_action_ref_array( 'image_tag/' . $this->_source . '/before_output', array( &$this ) );
    do_action_ref_array( 'image_tag/before_output', array( $this->_source, &$this ) );

    $this->files[$image_size] = array(
    'width' => $img[1],
    'height' => $img[2],
    'url' => $img[0],
    );
    // return parent::get_html();

    $this->attributes['srcset'][$img[1] . 'w'] = $img[0];
    return '<img src="' . $this->get_size( 'medium_large' )->get( 'src' ) . '" />';
    }

    if ( $this->files['__largest']['width'] < $img[1] )
    $this->files['__largest'] = &$this->files[$image_size];

    if ( $this->files['__smallest']['width'] > $img[1] )
    $this->files['__smallest'] = &$this->files[$image_size];
    }
    }

    $this->files['__largest']['ratio'] = ( $this->files['__largest']['height'] / $this->files['__largest']['width'] ) * 100;
    /**
    * Object for WordPress attachment image size.
    */
    class _image_tag_wp_attachment_image_size {

    protected $src = null;
    protected $width = null;
    protected $height = null;
    protected $orientation = null;

    /**
    * Get the properties of the image size.
    *
    * @param int $source_id Source ID.
    * @param string $size Size name.
    */
    function __construct( int $source_id, string $size ) {
    $attachment = wp_get_attachment_image_src( $source_id, $size );

    if ( empty( $attachment ) )
    return;

    list(
    $this->src,
    $this->width,
    $this->height,
    ,
    ) = $attachment;

    if ( $this->width > $this->height )
    $this->orientation = 'landscape';

    else if ( $this->width < $this->height )
    $this->orientation = 'portrait';

    else if ( $this->width == $this->height )
    $this->orientation = 'square';
    }

    function get( string $prop ) {
    return property_exists( $this, $prop )
    ? $this->$prop
    : null;
    }

    function exists() {
    return !empty( $this->get( 'src' ) );
    }

    }

    class _image_tag_wp_attachment_image_size__largest extends _image_tag_wp_attachment_image_size { protected $width = 0; function __construct() {} }
    class _image_tag_wp_attachment_image_size__smallest extends _image_tag_wp_attachment_image_size { protected $width = 9999; function __construct() {} }

    class image_tag_placeholder extends image_tag {

    function __construct( string $source, array $attributes = array(), array $args = array() ) {

    $details = array(
    'width' => null,
    'height' => null,
    'text' => null,
    );

    preg_match( '/^http:\/\/via\.placeholder.com\/([0-9]*)(?:x([0-9]*))?.*(?:\/?\?text=(.*))?$/', $source, $matches );

    if ( empty( $matches ) ) {
    if (
    !empty( $attributes['width'] )
    && !empty( $attributes['height'] )
    ) {
    $source = 'http://via.placeholder.com/' . $attributes['width'] . 'x' . $attributes['height'];
    empty( $attributes['alt'] ) || add_query_arg( 'text', $attributes['alt'], $source );
    empty( $attributes['title'] ) || add_query_arg( 'text', $attributes['title'], $source );
    } else
    return;
    }

    parent::__construct( $source, $attributes, $args );

    }

    /*
    ## ## ######## ##
    ## ## ## ## ##
    ## ## ## ## ##
    ## ## ######## ##
    ## ## ## ## ##
    ## ## ## ## ##
    ####### ## ## ########
    */

    class image_tag_uri extends image_tag {
    }

    function __construct() {
    parent::__construct();
    }
    class image_tag_picsum extends image_tag {

    function __construct( string $source, array $attributes = array(), array $args = array() ) {
    preg_match( '/^https:\/\/picsum.photos\/(?:g\/)?([0-9]*)(?:\/([0-9]*))?.*$/', $source, $matches );

    if ( empty( $matches ) ) {
    if (
    !empty( $attributes['width'] )
    && !empty( $attributes['height'] )
    )
    $source = 'https://picsum.photos/' . $attributes['width'] . '/' . $attributes['height'] . '/?random';
    else
    return;
    }

    parent::__construct( $source, $attributes, $args );

    }

    }

    function gather_files() {
    function get_image_tag_object( $source, array $args = array(), bool $skip_cache = false ) {
    static $_class_names = array();

    }
    $cache_key = md5( $source . '_' . json_encode( $args ) );
    $skip_cache || $cache = wp_cache_get( $cache_key, __FUNCTION__, false, $has_cache );

    }
    if ( !empty( $has_cache ) )
    return $cache;

    function image_tag( $source, $args = false ) {
    if ( false === $args )
    $args = array();
    if (
    is_numeric( $source )
    && intval( $source ) == $source
    )
    $class = 'image_tag_wp_attachment';

    if ( is_int( $source ) ) {
    else if (
    'placeholder' === $source
    || false !== stripos( $source, 'via.placeholder.com' )
    )
    $class = 'image_tag_placeholder';

    else if (
    'picsum' === $source
    || false !== stripos( $source, 'picsum.photos' )
    )
    $class = 'image_tag_picsum';

    $args['id'] = $source;
    return new image_tag_wp_attachment( $args );
    if ( !array_key_exists( $class, $_class_names ) )
    $_class_names[$class] = apply_filters( 'image_tag/' . $class, $class );

    } else if (
    false !== stripos( 'http://', $source )
    || false !== stripos( 'https://', $source )
    )
    $args['source'] = $source;
    $_image_tag = new $_class_names[$class]( $source, $args );

    else if ( apply_filters( 'image-tag/enable-theme-images', defined( 'THEME_IMAGES_URI' ) ) )
    $args['source'] = apply_filters( 'image-tag/theme-images-uri', THEME_IMAGES_URI ) . $source;
    wp_cache_add( $cache_key, $_image_tag, __FUNCTION__ );

    return new image_tag_uri( $args );
    return $_image_tag;
    }

    ?>
  4. @crstauf crstauf revised this gist Jan 11, 2017. 1 changed file with 331 additions and 294 deletions.
    625 changes: 331 additions & 294 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,12 @@
    <?php

    // !!! ALPHA VERSION !!!
    // !!! ALPHA VERSION !!!
    // !!! ALPHA VERSION !!!
    // !!! NOT FOR PRODUCTION USE !!!
    // !!! USE LATEST STABLE v0.0.3.1:
    // https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f/e671037f46d8262357bbcef53581ac8235044e56

    // https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f

    if (!defined('ABSPATH') || !function_exists('add_filter')) {
    @@ -9,380 +17,409 @@

    class image_tag {

    const VERSION = '0.0.3.1';
    const VERSION = '0.0.4-alpha';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
    const THEME_IMAGE_DIR_URI = '';

    var $alt = '',
    $width = 0,
    $height = 0,
    $title = '',
    $source = '', // URL of the smallest/original image
    $theme_image = '', // image filename
    $orientation = '', // landscape|portrait
    $classes = array(), // array of classes
    $attributes = array(),

    $lazypreload = false,
    $lazyload = true,
    $srcset = array(),
    $sizes = 'auto',
    protected $args = array();

    var $attributes = array(
    'id' => '',
    'alt' => '',
    'src' => '',
    'sizes' => '',
    'title' => '',
    'width' => 0,
    'height' => 0,
    'srcset' => array(),
    'class' => array(),
    ),

    $echo = true,
    $noscript = true,
    $lazyload = true,
    $lazypreload = false,
    $noscript_sizes = array();

    $noscript_sizes = false,
    $noscript_image_size = 'full',

    $attachment_id = 0,
    $image_sizes = array('thumbnail','medium','medium_large','large','full'),

    $lazyload_class = 'lazyload',
    $lazypreload_class = 'lazypreload';

    private $tag = array();
    private $post = array();
    private $noscript_tag = array();

    private $args = array();
    public $files = array(
    protected $files = array(
    '__smallest' => array(
    'width' => 9999999999,
    'height' => 999999999,
    'url' => '',
    'width' => 9999999,
    'height' => 9999999,
    'url' => ''
    ),
    '__largest' => array(
    'width' => 0,
    'width' => 0,
    'height' => 0,
    'url' => '',
    'url' => '',
    ),
    );

    private $debug = true;
    private $done_output = false;
    private $generating_noscript = false;
    protected $orientation = ''; // portrait|landscape

    function __construct() {
    $args = func_get_args();
    $this->args = $args[0];

    if ($this->is_WP())
    $this->args = apply_filters('image-tag/args',$this->args);

    if (!count($this->args))
    return false;
    if ( !is_subclass_of( $this, 'image_tag' ) ) {

    $args = func_get_arg( 0 );
    if ( array_key_exists( 'attachment_id', $args ) )
    $source = $args['attachment_id'];
    else if ( array_key_exists( 'source', $args ) )
    $source = $args['source'];
    else if ( array_key_exists( 'theme_image', $args ) )
    $source = $args['theme_image'];
    else
    return false;

    foreach ($this->args as $key => $value)
    if (isset($this->$key)) {
    $this->$key = $value;
    unset($this->args[$key]);
    }
    $args['attributes']['class']['old-generated'] = 'old-generated-image-tag';

    if ($this->is_AMP() || $this->is_FBIA())
    $this->noscript = false;
    unset(
    $args['attachment_id'],
    $args['source'],
    $args['theme_image']
    );

    if (!$this->get_image()) {
    if (
    $this->debug
    || ($this->is_WP() && defined('WP_DEBUG') && WP_DEBUG)
    array_key_exists( 'echo', $args )
    && false === $args['echo']
    )
    throw new Exception('No image source provided.');
    return false;
    return image_tag( $source, $args );
    else
    echo image_tag( $source, $args );
    }

    $this->collect_files();
    $this->tag = $this->generate();
    if ($this->noscript && !$this->is_AMP() && !$this->is_FBIA()) {
    $this->generating_noscript = true;
    $this->noscript_tag = $this->generate();
    $this->generating_noscript = false;
    }
    }
    add_filter( 'image-tag/noscript/attributes/glue', array( &$this, 'filter_image_tag_noscript_attributes_glue' ) );

    function __destruct() {
    if (true === $this->done_output) return;
    if (true === $this->echo) $this->display();
    }
    if ( is_array( $this->args ) && count( $this->args ) )
    foreach ( $this->args as $key => $value )
    if ( isset( $this->$key ) )
    $this->$key = $value;

    function display() {
    $this->done_output = true;
    echo $this->output();
    }
    $this->attributes['class']['generated'] = 'generated-image-tag';

    function output( $classes = array() ) {
    $output = '';
    do {
    $tag = $this->generating_noscript ? $this->noscript_tag : $this->tag;
    $this->gather_files();
    $this->determine_orientation();
    $this->being_lazy();

    if (count($classes))
    $tag['class'] = array_merge($tag['class'],$classes);
    }

    if ($this->generating_noscript)
    $output .= '<noscript>';
    function __toString() {
    if ( !$this->echo )
    return '';

    $esc = $this->is_WP() ? 'esc_attr' : 'htmlentities';
    ksort( $this->attributes );

    if ($this->is_AMP())
    $output .= '<amp-img';
    else if ($this->is_FBIA())
    $output .= '<figure><img';
    else
    $output .= '<img';
    $image_output = $this->image_output();

    foreach ($tag as $attr => $value)
    if (false !== $value)
    $output .= ' ' . $esc($attr) . '="' . (is_array($value) ? $esc($this->output_array($attr,$value)) : $esc($value)) . '"';
    if ( !$this->noscript )
    return implode( "\n", $image_output );

    $output .= ' />';
    if ($this->is_FBIA())
    $output .= '<figcaption>' . $this->tag['title'] . '</figcaption></figure>';
    $this->noscript_prep();

    if ($this->generating_noscript)
    $output .= '</noscript>';
    return implode( "\n", array_filter( $image_output ) ) . implode( "\n", array_filter( $this->noscript_image_output() ) );
    }

    if ($this->noscript && !$this->generating_noscript)
    $this->generating_noscript = true;
    else
    break;
    } while (1);
    function image_output() {
    $output = array( 'open' => "\n<img " );

    return $output;
    }
    foreach ( $this->attributes as $attr_name => $attr_value ) {

    function output_array($attr,$array) {
    $glue = in_array($attr,array('data-srcset','srcset')) ? ', ' : ' ';
    return implode($glue,$array);
    }
    $attr_value = apply_filters( 'image-tag/attributes/value', $attr_value, $attr_name, $this );
    $attr_value = apply_filters( 'image-tag/attributes/' . $attr_name . '/value', $attr_value, $this );

    function get_image() {
    if (!empty($this->theme_image))
    $this->source = self::THEME_IMAGE_DIR_URI . $this->theme_image;
    $output[$attr_name] = $this->construct_attribute( $attr_name, $attr_value );

    if ($this->is_attachment()) {
    if ( '' === trim( $output[$attr_name] ) )
    unset( $output[$attr_name] );

    if (
    !$this->is_WP()
    || 'attachment' !== get_post_type($this->attachment_id)
    || false === stripos(get_post_mime_type($this->attachment_id),'image')
    )
    return false;
    }

    $this->post = get_post($this->attachment_id);
    list($this->source,$this->width,$this->height) = wp_get_attachment_image_src($this->attachment_id,'full');
    $output['close'] = "/>\n";

    } else if (!empty($this->source)) {
    list($this->width,$this->height) = @getimagesize($this->source);
    return array_filter( $output );
    }

    if ($this->width > $this->height)
    $this->orientation = 'landscape';
    else if ($this->height > $this->width)
    $this->orientation = 'portrait';
    else if ($this->height === $this->width)
    $this->orientation = 'square';
    else
    $this->orientation = 'unknown';

    if ( is_array( $this->image_sizes ) ) {
    if (
    array_key_exists( 'landscape', $this->image_sizes )
    && in_array( $this->orientation, array( 'landscape', 'square', 'unknown' ) )
    )
    $this->image_sizes = $this->image_sizes['landscape'];
    else if (
    array_key_exists( 'portrait', $this->image_sizes )
    && 'portrait' === $this->orientation
    )
    $this->image_sizes = $this->image_sizes['portrait'];
    }

    $this->classes[] = 'orientation-' . $this->orientation;
    function noscript_prep() {

    return true;
    }
    $this->attributes['class']['noscript'] = 'noscript';
    $this->attributes['class']['post-noscript'] = $this->attributes['class']['post'] . '-noscript';

    if ( !empty( $this->attributes['id'] ) )
    $this->attributes['id'] .= '-noscript';

    if ( array_key_exists( 'data-sizes', $this->attributes ) )
    $this->attributes['sizes'] = $this->attributes['data-sizes'];

    if ( array_key_exists( 'data-src', $this->attributes ) && self::DATAURI !== $this->attributes['data-src'] )
    $this->attributes['src'] = $this->attributes['data-src'];

    function collect_files() {
    if (!$this->is_attachment()) {
    if ( 'auto' === $this->attributes['sizes'] ) {

    $this->files['original']['url'] = $this->source;
    $this->files['original']['width'] = $this->width;
    $this->files['original']['height'] = $this->height;
    if ( !empty( $this->noscript_sizes ) && is_array( $this->noscript_sizes ) && count( $this->noscript_sizes ) ) {

    $this->check_dimensions($this->files['original']);
    $this->attributes['sizes'] = $this->noscript_sizes;

    if (false !== $this->srcset) {
    $i = 0;
    foreach ($this->srcset as $url) {
    $this->files[$i]['url'] = $url;
    list(
    $this->files[$i]['width'],
    $this->files[$i]['height']) = @getimagesize($url);
    $this->check_dimensions($this->files[$i]);
    $i++;
    if ( array_key_exists( 'data-srcset', $this->attributes ) )
    $this->attributes['srcset'] = $this->attributes['data-srcset'];

    } else {
    $this->attributes['src'] = $this->files['__largest']['url'];
    unset( $this->attributes['sizes'] );
    }

    }

    } else {
    unset(
    $this->attributes['class']['lazyload'],
    $this->attributes['class']['lazypreload'],
    $this->attribtues['data-src'],
    $this->attributes['data-sizes'],
    $this->attributes['data-srcset']
    );
    }

    function noscript_image_output() {
    $output = array(
    'open_noscript' => '<noscript>',
    'open_img' => "\t<img",
    );

    foreach ( $this->attributes as $attr_name => $attr_value ) {

    $attr_value = apply_filters( 'image-tag/noscript/attributes/value', $attr_value, $attr_name, $this );
    $attr_value = apply_filters( 'image-tag/noscript/attributes/' . $attr_name . '/value', $attr_value, $this );

    $output[$attr_name] = "\t" . $this->construct_attribute( $attr_name, $attr_value, true );

    foreach ($this->image_sizes as $size) {
    list(
    $this->files[$size]['url'],
    $this->files[$size]['width'],
    $this->files[$size]['height']) = wp_get_attachment_image_src($this->attachment_id,$size);
    if ( '' === trim( $output[$attr_name] ) )
    unset( $output[$attr_name] );

    $this->check_dimensions($this->files[$size]);
    }

    $output['close_img'] = "\n\t/>";
    $output['close_noscript'] = "</noscript>\n";

    return array_filter( $output );
    }

    function construct_attribute( $attr_name, $attr_value, $noscript = false ) {
    if ( !is_array( $attr_value ) ) {
    if ( !empty( $attr_value ) && ( '' !== trim( $attr_value ) || 'alt' === $attr_name ) )
    return "\t" . $attr_name . '="' . esc_attr( $attr_value ) . '" ';
    return false;
    }

    if ( false !== strpos( $attr_name, 'srcset' ) && count( $attr_value ) )
    foreach ( $attr_value as $w => $url )
    $attr_value[$w] = $url . ' ' . $w;

    switch ( $attr_name ) {
    case 'sizes':
    case 'srcset':
    case 'data-srcset':
    $glue = ",\n\t\t";
    break;
    case 'class':
    default:
    $glue = ' ';
    break;
    }

    $glue = apply_filters( 'image-tag/' . ( $noscript ? 'noscript/' : '' ) . 'attributes/glue', $glue, $attr_name, $this );
    $glue = apply_filters( 'image-tag/' . ( $noscript ? 'noscript/' : '' ) . 'attributes/' . $attr_name . '/glue', $glue, $this );

    foreach ( $attr_value as $i => $maybe_array )
    if ( is_array( $maybe_array ) )
    $attr_value[$i] = implode( $glue, $maybe_array );

    return "\t" . $attr_name . '="' . implode( $glue, $attr_value ) . '" ';
    }

    function filter_image_tag_noscript_attributes_glue( $glue ) {
    if ( ' ' === $glue )
    return ' ';
    return $glue . "\t";
    }

    function determine_orientation() {
    $largest = &$this->files['__largest'];

    if ( $largest['width'] > $largest['height'] )
    $this->orientation = 'landscape';
    else if ( $largest['width'] < $largest['height'] )
    $this->orientation = 'portrait';
    else if ( $largest['width'] === $largest['height'] )
    $this->orientation = 'square';
    else
    $this->orientation = false;

    $this->attributes['class']['orientation'] = 'orientation-' .
    ( false === $this->orientation
    ? 'unknown'
    : $this->orientation
    );
    }

    function check_dimensions($file) {
    if (
    $file['width'] > $this->files['__largest']['width']
    && $file['height'] > $this->files['__largest']['height']
    )
    $this->files['__largest'] = $file;
    function gather_files() {}

    if (
    $file['width'] < $this->files['__smallest']['width']
    && $file['height'] < $this->files['__smallest']['height']
    )
    $this->files['__smallest'] = $file;
    }
    function being_lazy() {
    if ( !$this->lazyload && !$this->lazypreload )
    return false;

    function remove_smallest_largest_files() {
    $array = $this->files;
    unset($array['__smallest'],$array['__largest']);
    return $array;
    }
    if ( $this->lazypreload )
    $this->attributes['class']['lazypreload'] = 'lazypreload';

    function generate() {
    $tag['src'] = $this->generate_src();
    $tag['width'] = $this->width;
    $tag['height'] = $this->height;
    $tag[$this->lazyload && !$this->generating_noscript && !$this->is_AMP() ? 'data-srcset' : 'srcset'] = $this->generate_srcset();
    $tag[$this->lazyload && !$this->generating_noscript ? 'data-sizes' : 'sizes'] = $this->generating_noscript ? $this->noscript_sizes : $this->sizes;
    $tag['alt'] = !empty($this->tag['alt']) ? $this->tag['alt'] : $this->generate_title();
    $tag['title'] = !empty($this->tag['title']) ? $this->tag['title'] : $this->generate_title();
    $tag['class'] = $this->generate_class();
    if ( !$this->lazyload )
    return false;

    if ($this->is_WP())
    $this->attributes = apply_filters('image-tag/attributes',$this->attributes,get_class_vars(__CLASS__));
    $this->attributes['data-sizes'] = 'auto';

    if (count($this->attributes))
    foreach ($this->attributes as $attr => $value)
    $tag[$attr] = $value;
    $this->attributes['class']['lazyload'] = 'lazyload';

    if ($this->is_AMP())
    $tag['layout'] = 'responsive';
    $this->attributes['src'] = self::DATAURI;
    $this->attributes['data-src' . ( count( $this->files ) > 3 ? 'set' : '' )] = $this->attributes['srcset'];

    if ($this->is_WP())
    foreach ($tag as $attr => $value)
    $tag[$attr] = apply_filters('image-tag/tag/' . str_replace('data-','',$attr),$value,get_class_vars(__CLASS__));
    unset( $this->attributes['srcset'] );

    return $tag;
    return true;
    }

    function generate_src() {
    if ($this->generating_noscript) {
    if ($this->is_attachment()) {
    $noscript_image_size = apply_filters(
    'image-tag/tag/noscript_image_size',
    $this->noscript_image_size,
    get_class_vars(__CLASS__)
    );
    if ( array_key_exists( $noscript_image_size, $this->files ) )
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files[$noscript_image_size]['url'],
    get_class_vars(__CLASS__)
    );
    else
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files['__largest']['url'],
    get_class_vars(__CLASS__)
    );
    } else
    return $this->files['__largest']['url'];
    } else if ($this->lazyload && !$this->generating_noscript && !$this->is_AMP())
    return self::DATAURI;
    else if (1 < count($this->remove_smallest_largest_files()))
    return $this->files['__smallest']['url'];
    else if (!empty($this->source))
    return $this->source;
    }
    }

    function generate_srcset() {
    if ($this->generating_noscript)
    return $this->noscript_sizes;
    else if (count($this->srcset))
    return $this->srcset;
    else if (count($this->remove_smallest_largest_files())) {
    foreach ($this->files as $key => $file)
    if (!in_array($key,array('__smallest','__largest')))
    $this->srcset[] = $file['url'] . ' ' . $file['width'] . 'w';
    } else
    return false;
    return $this->srcset;
    }

    function generate_title() {
    if ($this->is_attachment()) return $this->post->post_title;
    else return basename($this->source);
    }
    /*
    ## ## ####### ######## ######## ######## ######## ######## ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ######## ## ## ######## ######## ###### ###### ######
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ##
    ### ### ####### ## ## ######## ## ## ## ######## ###### ######
    */

    function generate_class() {
    $classes = array('generated-image-tag');
    if ($this->noscript)
    $classes[] = $this->generating_noscript ? 'hide-if-js' : 'hide-if-no-js';
    if ($this->lazyload && !$this->generating_noscript) {
    $classes[] = $this->is_WP() ? apply_filters('image-tag/classes/lazyload',$this->lazyload_class) : $this->lazyload_class;
    if ($this->lazypreload)
    $classes[] = $this->is_WP() ? apply_filters('image-tag/classes/lazypreload',$this->lazypreload_class) : $this->lazypreload_class;
    class image_tag_wp_attachment extends image_tag {

    var $id = 0,
    $post = null,
    $image_sizes = array( 'thumbnail', 'medium', 'medium_large', 'large', 'full' );

    function __construct() {
    $this->args = func_get_arg( 0 );

    parent::__construct();

    $this->get_post();

    if (
    false === $this->post
    || is_wp_error( $this->post )
    )
    return;

    $this->attributes['class']['post'] = 'post-' . $this->id;

    }

    function noscript_prep() {
    parent::noscript_prep();

    if ( !empty( $this->attributes['sizes'] ) || !empty( $this->noscript_sizes ) )
    return;

    $largest = $this->files['__largest'];

    foreach ( $this->files as $size => $file ) {
    if ( in_array( $size, array( '__largest', '__smallest' ) ) )
    continue;
    if ( $file['url'] === $largest['url'] ) {
    $this->attributes['class']['WP-size'] = 'size-' . $size;
    break;
    }
    if ($this->is_attachment()) {
    $classes[] = 'post-' . $this->post->ID;
    if ($this->generating_noscript)
    $classes[] = 'size-' . apply_filters('image-tag/tag/noscript_image_size',$this->noscript_image_size,get_class_vars(__CLASS__));
    else
    $classes = array_merge($classes,array_map(function($size) { return 'size-' . $size; },array_keys($this->remove_smallest_largest_files())));
    }
    }

    function get_post() {
    $this->post = get_post( $this->id );

    if ( '' === $this->attributes['alt'] )
    $this->attributes['alt'] = esc_attr( get_the_title( $this->post ) );

    if ( '' === $this->attributes['title'] )
    $this->attributes['title'] = esc_attr( get_the_title( $this->post ) );
    }

    function gather_files() {

    foreach ( $this->image_sizes as $i => $image_size ) {

    $this->attributes['class']['WP-size'][$image_size] = 'size-' . $image_size;

    $img = wp_get_attachment_image_src( $this->id, $image_size );

    if ( 0 === $i ) {
    $this->attributes['src'] = $img[0];
    $this->attributes['width'] = $img[1];
    $this->attributes['height'] = $img[2];
    }
    return array_unique(array_merge($classes,$this->classes));

    $this->files[$image_size] = array(
    'width' => $img[1],
    'height' => $img[2],
    'url' => $img[0],
    );

    $this->attributes['srcset'][$img[1] . 'w'] = $img[0];

    if ( $this->files['__largest']['width'] < $img[1] )
    $this->files['__largest'] = &$this->files[$image_size];

    if ( $this->files['__smallest']['width'] > $img[1] )
    $this->files['__smallest'] = &$this->files[$image_size];
    }

    function is_attachment() { return 0 !== $this->attachment_id && intval($this->attachment_id) == $this->attachment_id; }
    function is_WP() { return defined('ABSPATH') && function_exists('is_attachment') && function_exists('apply_filters'); }
    $this->files['__largest']['ratio'] = ( $this->files['__largest']['height'] / $this->files['__largest']['width'] ) * 100;

    function is_AMP() { // Google Accelerated Mobile Pages
    $is_AMP = defined('IS_AMP') && IS_AMP;
    if ($this->is_WP())
    $is_AMP = apply_filters('image-tag/test/amp',$is_AMP);
    return $is_AMP;
    }

    function is_FBIA() { // Facebook Instant Articles
    $is_FBIA = defined('IS_FBIA') && IS_FBIA;
    if ($this->is_WP())
    $is_FBIA = apply_filters('image-tag/test/fbia',$is_FBIA);
    return $is_FBIA;
    }


    /*
    ## ## ######## ##
    ## ## ## ## ##
    ## ## ## ## ##
    ## ## ######## ##
    ## ## ## ## ##
    ## ## ## ## ##
    ####### ## ## ########
    */

    class image_tag_uri extends image_tag {

    function __construct() {
    parent::__construct();
    }

    function debug($var) {
    if ((
    !$this->is_WP()
    && false === $this->debug
    ) || (
    !defined('WP_DEBUG')
    || !WP_DEBUG
    )
    )
    return false;
    else if (is_string($var)) echo $var . '<br />' . "\n";
    else if (is_array($var)) echo print_r($var,true) . '<br />' . "\n";
    else if (is_object($var)) echo print_r(get_object_var($var),true) . '<br />' . "\n";
    function gather_files() {

    }

    }

    ?>
    function image_tag( $source, $args = false ) {
    if ( false === $args )
    $args = array();

    if ( is_int( $source ) ) {

    $args['id'] = $source;
    return new image_tag_wp_attachment( $args );

    } else if (
    false !== stripos( 'http://', $source )
    || false !== stripos( 'https://', $source )
    )
    $args['source'] = $source;

    else if ( apply_filters( 'image-tag/enable-theme-images', defined( 'THEME_IMAGES_URI' ) ) )
    $args['source'] = apply_filters( 'image-tag/theme-images-uri', THEME_IMAGES_URI ) . $source;

    return new image_tag_uri( $args );
    }
  5. @crstauf crstauf revised this gist Jan 11, 2017. No changes.
  6. @crstauf crstauf revised this gist Dec 23, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,7 @@ class image_tag {

    const VERSION = '0.0.3.1';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
    const THEME_IMAGE_DIR_URI = MONQ_THEME_IMG_DIR_URI;
    const THEME_IMAGE_DIR_URI = '';

    var $alt = '',
    $width = 0,
  7. @crstauf crstauf revised this gist Dec 23, 2016. 1 changed file with 44 additions and 15 deletions.
    59 changes: 44 additions & 15 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    <?php
    // https://gist.github.com/crstauf/030df6bd6c436620e96cb92a44c9772f

    if (!defined('ABSPATH') || !function_exists('add_filter')) {
    header( 'Status: 403 Forbidden' );
    @@ -7,16 +8,17 @@
    }

    class image_tag {

    const VERSION = '0.0.3';

    const VERSION = '0.0.3.1';
    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
    const THEME_IMAGE_DIR_URI = MONQ_THEME_IMG_DIR_URI;

    var $alt = '',
    $width = 0,
    $height = 0,
    $title = '',
    $source = '', // URL of the smallest/original image
    $theme_image = '', // image filename
    $orientation = '', // landscape|portrait
    $classes = array(), // array of classes
    $attributes = array(),
    @@ -43,7 +45,7 @@ class image_tag {
    private $noscript_tag = array();

    private $args = array();
    private $files = array(
    public $files = array(
    '__smallest' => array(
    'width' => 9999999999,
    'height' => 999999999,
    @@ -107,11 +109,14 @@ function display() {
    echo $this->output();
    }

    function output() {
    function output( $classes = array() ) {
    $output = '';
    do {
    $tag = $this->generating_noscript ? $this->noscript_tag : $this->tag;

    if (count($classes))
    $tag['class'] = array_merge($tag['class'],$classes);

    if ($this->generating_noscript)
    $output .= '<noscript>';

    @@ -150,6 +155,9 @@ function output_array($attr,$array) {
    }

    function get_image() {
    if (!empty($this->theme_image))
    $this->source = self::THEME_IMAGE_DIR_URI . $this->theme_image;

    if ($this->is_attachment()) {

    if (
    @@ -175,6 +183,19 @@ function get_image() {
    else
    $this->orientation = 'unknown';

    if ( is_array( $this->image_sizes ) ) {
    if (
    array_key_exists( 'landscape', $this->image_sizes )
    && in_array( $this->orientation, array( 'landscape', 'square', 'unknown' ) )
    )
    $this->image_sizes = $this->image_sizes['landscape'];
    else if (
    array_key_exists( 'portrait', $this->image_sizes )
    && 'portrait' === $this->orientation
    )
    $this->image_sizes = $this->image_sizes['portrait'];
    }

    $this->classes[] = 'orientation-' . $this->orientation;

    return true;
    @@ -264,17 +285,25 @@ function generate() {

    function generate_src() {
    if ($this->generating_noscript) {
    if ($this->is_attachment())
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files[apply_filters(
    'image-tag/tag/noscript_image_size',
    $this->noscript_image_size,
    get_class_vars(__CLASS__)
    )]['url'],
    get_class_vars(__CLASS__)
    );
    else
    if ($this->is_attachment()) {
    $noscript_image_size = apply_filters(
    'image-tag/tag/noscript_image_size',
    $this->noscript_image_size,
    get_class_vars(__CLASS__)
    );
    if ( array_key_exists( $noscript_image_size, $this->files ) )
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files[$noscript_image_size]['url'],
    get_class_vars(__CLASS__)
    );
    else
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files['__largest']['url'],
    get_class_vars(__CLASS__)
    );
    } else
    return $this->files['__largest']['url'];
    } else if ($this->lazyload && !$this->generating_noscript && !$this->is_AMP())
    return self::DATAURI;
  8. @crstauf crstauf revised this gist Aug 27, 2016. No changes.
  9. @crstauf crstauf revised this gist Aug 27, 2016. 2 changed files with 359 additions and 324 deletions.
    359 changes: 359 additions & 0 deletions class.image-tag.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,359 @@
    <?php

    if (!defined('ABSPATH') || !function_exists('add_filter')) {
    header( 'Status: 403 Forbidden' );
    header( 'HTTP/1.1 403 Forbidden' );
    exit();
    }

    class image_tag {

    const VERSION = '0.0.3';

    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    var $alt = '',
    $width = 0,
    $height = 0,
    $title = '',
    $source = '', // URL of the smallest/original image
    $orientation = '', // landscape|portrait
    $classes = array(), // array of classes
    $attributes = array(),

    $lazypreload = false,
    $lazyload = true,
    $srcset = array(),
    $sizes = 'auto',

    $echo = true,
    $noscript = true,

    $noscript_sizes = false,
    $noscript_image_size = 'full',

    $attachment_id = 0,
    $image_sizes = array('thumbnail','medium','medium_large','large','full'),

    $lazyload_class = 'lazyload',
    $lazypreload_class = 'lazypreload';

    private $tag = array();
    private $post = array();
    private $noscript_tag = array();

    private $args = array();
    private $files = array(
    '__smallest' => array(
    'width' => 9999999999,
    'height' => 999999999,
    'url' => '',
    ),
    '__largest' => array(
    'width' => 0,
    'height' => 0,
    'url' => '',
    ),
    );

    private $debug = true;
    private $done_output = false;
    private $generating_noscript = false;

    function __construct() {
    $args = func_get_args();
    $this->args = $args[0];

    if ($this->is_WP())
    $this->args = apply_filters('image-tag/args',$this->args);

    if (!count($this->args))
    return false;

    foreach ($this->args as $key => $value)
    if (isset($this->$key)) {
    $this->$key = $value;
    unset($this->args[$key]);
    }

    if ($this->is_AMP() || $this->is_FBIA())
    $this->noscript = false;

    if (!$this->get_image()) {
    if (
    $this->debug
    || ($this->is_WP() && defined('WP_DEBUG') && WP_DEBUG)
    )
    throw new Exception('No image source provided.');
    return false;
    }

    $this->collect_files();
    $this->tag = $this->generate();
    if ($this->noscript && !$this->is_AMP() && !$this->is_FBIA()) {
    $this->generating_noscript = true;
    $this->noscript_tag = $this->generate();
    $this->generating_noscript = false;
    }
    }

    function __destruct() {
    if (true === $this->done_output) return;
    if (true === $this->echo) $this->display();
    }

    function display() {
    $this->done_output = true;
    echo $this->output();
    }

    function output() {
    $output = '';
    do {
    $tag = $this->generating_noscript ? $this->noscript_tag : $this->tag;

    if ($this->generating_noscript)
    $output .= '<noscript>';

    $esc = $this->is_WP() ? 'esc_attr' : 'htmlentities';

    if ($this->is_AMP())
    $output .= '<amp-img';
    else if ($this->is_FBIA())
    $output .= '<figure><img';
    else
    $output .= '<img';

    foreach ($tag as $attr => $value)
    if (false !== $value)
    $output .= ' ' . $esc($attr) . '="' . (is_array($value) ? $esc($this->output_array($attr,$value)) : $esc($value)) . '"';

    $output .= ' />';
    if ($this->is_FBIA())
    $output .= '<figcaption>' . $this->tag['title'] . '</figcaption></figure>';

    if ($this->generating_noscript)
    $output .= '</noscript>';

    if ($this->noscript && !$this->generating_noscript)
    $this->generating_noscript = true;
    else
    break;
    } while (1);

    return $output;
    }

    function output_array($attr,$array) {
    $glue = in_array($attr,array('data-srcset','srcset')) ? ', ' : ' ';
    return implode($glue,$array);
    }

    function get_image() {
    if ($this->is_attachment()) {

    if (
    !$this->is_WP()
    || 'attachment' !== get_post_type($this->attachment_id)
    || false === stripos(get_post_mime_type($this->attachment_id),'image')
    )
    return false;

    $this->post = get_post($this->attachment_id);
    list($this->source,$this->width,$this->height) = wp_get_attachment_image_src($this->attachment_id,'full');

    } else if (!empty($this->source)) {
    list($this->width,$this->height) = @getimagesize($this->source);
    }

    if ($this->width > $this->height)
    $this->orientation = 'landscape';
    else if ($this->height > $this->width)
    $this->orientation = 'portrait';
    else if ($this->height === $this->width)
    $this->orientation = 'square';
    else
    $this->orientation = 'unknown';

    $this->classes[] = 'orientation-' . $this->orientation;

    return true;
    }

    function collect_files() {
    if (!$this->is_attachment()) {

    $this->files['original']['url'] = $this->source;
    $this->files['original']['width'] = $this->width;
    $this->files['original']['height'] = $this->height;

    $this->check_dimensions($this->files['original']);

    if (false !== $this->srcset) {
    $i = 0;
    foreach ($this->srcset as $url) {
    $this->files[$i]['url'] = $url;
    list(
    $this->files[$i]['width'],
    $this->files[$i]['height']) = @getimagesize($url);
    $this->check_dimensions($this->files[$i]);
    $i++;
    }
    }

    } else {

    foreach ($this->image_sizes as $size) {
    list(
    $this->files[$size]['url'],
    $this->files[$size]['width'],
    $this->files[$size]['height']) = wp_get_attachment_image_src($this->attachment_id,$size);

    $this->check_dimensions($this->files[$size]);
    }

    }
    }

    function check_dimensions($file) {
    if (
    $file['width'] > $this->files['__largest']['width']
    && $file['height'] > $this->files['__largest']['height']
    )
    $this->files['__largest'] = $file;

    if (
    $file['width'] < $this->files['__smallest']['width']
    && $file['height'] < $this->files['__smallest']['height']
    )
    $this->files['__smallest'] = $file;
    }

    function remove_smallest_largest_files() {
    $array = $this->files;
    unset($array['__smallest'],$array['__largest']);
    return $array;
    }

    function generate() {
    $tag['src'] = $this->generate_src();
    $tag['width'] = $this->width;
    $tag['height'] = $this->height;
    $tag[$this->lazyload && !$this->generating_noscript && !$this->is_AMP() ? 'data-srcset' : 'srcset'] = $this->generate_srcset();
    $tag[$this->lazyload && !$this->generating_noscript ? 'data-sizes' : 'sizes'] = $this->generating_noscript ? $this->noscript_sizes : $this->sizes;
    $tag['alt'] = !empty($this->tag['alt']) ? $this->tag['alt'] : $this->generate_title();
    $tag['title'] = !empty($this->tag['title']) ? $this->tag['title'] : $this->generate_title();
    $tag['class'] = $this->generate_class();

    if ($this->is_WP())
    $this->attributes = apply_filters('image-tag/attributes',$this->attributes,get_class_vars(__CLASS__));

    if (count($this->attributes))
    foreach ($this->attributes as $attr => $value)
    $tag[$attr] = $value;

    if ($this->is_AMP())
    $tag['layout'] = 'responsive';

    if ($this->is_WP())
    foreach ($tag as $attr => $value)
    $tag[$attr] = apply_filters('image-tag/tag/' . str_replace('data-','',$attr),$value,get_class_vars(__CLASS__));

    return $tag;
    }

    function generate_src() {
    if ($this->generating_noscript) {
    if ($this->is_attachment())
    return apply_filters(
    'image-tag/tag/noscript_src',
    $this->files[apply_filters(
    'image-tag/tag/noscript_image_size',
    $this->noscript_image_size,
    get_class_vars(__CLASS__)
    )]['url'],
    get_class_vars(__CLASS__)
    );
    else
    return $this->files['__largest']['url'];
    } else if ($this->lazyload && !$this->generating_noscript && !$this->is_AMP())
    return self::DATAURI;
    else if (1 < count($this->remove_smallest_largest_files()))
    return $this->files['__smallest']['url'];
    else if (!empty($this->source))
    return $this->source;
    }

    function generate_srcset() {
    if ($this->generating_noscript)
    return $this->noscript_sizes;
    else if (count($this->srcset))
    return $this->srcset;
    else if (count($this->remove_smallest_largest_files())) {
    foreach ($this->files as $key => $file)
    if (!in_array($key,array('__smallest','__largest')))
    $this->srcset[] = $file['url'] . ' ' . $file['width'] . 'w';
    } else
    return false;
    return $this->srcset;
    }

    function generate_title() {
    if ($this->is_attachment()) return $this->post->post_title;
    else return basename($this->source);
    }

    function generate_class() {
    $classes = array('generated-image-tag');
    if ($this->noscript)
    $classes[] = $this->generating_noscript ? 'hide-if-js' : 'hide-if-no-js';
    if ($this->lazyload && !$this->generating_noscript) {
    $classes[] = $this->is_WP() ? apply_filters('image-tag/classes/lazyload',$this->lazyload_class) : $this->lazyload_class;
    if ($this->lazypreload)
    $classes[] = $this->is_WP() ? apply_filters('image-tag/classes/lazypreload',$this->lazypreload_class) : $this->lazypreload_class;
    }
    if ($this->is_attachment()) {
    $classes[] = 'post-' . $this->post->ID;
    if ($this->generating_noscript)
    $classes[] = 'size-' . apply_filters('image-tag/tag/noscript_image_size',$this->noscript_image_size,get_class_vars(__CLASS__));
    else
    $classes = array_merge($classes,array_map(function($size) { return 'size-' . $size; },array_keys($this->remove_smallest_largest_files())));
    }
    return array_unique(array_merge($classes,$this->classes));
    }

    function is_attachment() { return 0 !== $this->attachment_id && intval($this->attachment_id) == $this->attachment_id; }
    function is_WP() { return defined('ABSPATH') && function_exists('is_attachment') && function_exists('apply_filters'); }

    function is_AMP() { // Google Accelerated Mobile Pages
    $is_AMP = defined('IS_AMP') && IS_AMP;
    if ($this->is_WP())
    $is_AMP = apply_filters('image-tag/test/amp',$is_AMP);
    return $is_AMP;
    }

    function is_FBIA() { // Facebook Instant Articles
    $is_FBIA = defined('IS_FBIA') && IS_FBIA;
    if ($this->is_WP())
    $is_FBIA = apply_filters('image-tag/test/fbia',$is_FBIA);
    return $is_FBIA;
    }

    function debug($var) {
    if ((
    !$this->is_WP()
    && false === $this->debug
    ) || (
    !defined('WP_DEBUG')
    || !WP_DEBUG
    )
    )
    return false;
    else if (is_string($var)) echo $var . '<br />' . "\n";
    else if (is_array($var)) echo print_r($var,true) . '<br />' . "\n";
    else if (is_object($var)) echo print_r(get_object_var($var),true) . '<br />' . "\n";
    }

    }

    ?>
    324 changes: 0 additions & 324 deletions class.img_tag.php
    Original file line number Diff line number Diff line change
    @@ -1,324 +0,0 @@
    <?php

    class img_tag {

    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    var $url = false,
    $image = false,
    $image_id = false,

    $alt = false,
    $title = false,
    $width = false,
    $height = false,
    $preload = false,

    $sizes = 'auto',
    $output = '',

    $echo = true,
    $lazy = true,
    $noscript = true,

    $first = array(),
    $classes = array(),
    $attributes = array(),
    $image_sizes = array(),
    $image_hires_sizes = array();

    private $tag = array();
    private $files = array();
    private $done_output = false;
    private $doing_noscript = false; // generating noscript image tag

    function __construct($args) {
    if (array_key_exists('theme_image',$args))
    $args['url'] = get_stylesheet_directory_uri() . '/img/' . $args['theme_image'];

    if (array_key_exists('url',$args))
    $this->url = $args['url'];
    else if (
    array_key_exists('image_id',$args) &&
    is_numeric($args['image_id'])
    )
    $this->image_id = $args['image_id'];
    else
    return false;

    foreach ($args as $k => $v)
    $this->$k = $v;
    }

    function __destruct() {
    if (true === $this->done_output) return;
    if (true === $this->echo) $this->display();
    }

    function output() {
    if (false !== $this->image_id)
    $generated = $noscript = $this->generate_from_id();
    else
    $generated = $noscript = $this->generate_from_url();

    $generated['class'][] = $noscript['class'][] = 'generated-img-tag';

    if (
    array_key_exists('srcset',$generated) // multiple sizes of image available
    && (
    $this->lazy || // loading image lazily
    'auto' === $this->sizes // 'sizes' attribute is being set dynamically
    )
    ) {
    $generated['data-sizes'] = $generated['sizes'];
    $generated['data-srcset'] = $generated['data-srcset-hires'] = $generated['srcset'];
    unset($generated['sizes'],$generated['srcset']);
    }

    if (array_key_exists('srcset-hires',$generated)) {
    $generated['data-srcset-hires'] = $generated['srcset-hires'];
    $generated['class'][] = 'srcset-hires';
    unset($generated['srcset-hires']);
    }

    if (true === $this->lazy) {
    if (!array_key_exists('data-srcset',$generated))
    $generated['data-src'] = $generated['src'];
    $generated['src'] = self::DATAURI;
    }

    if (true === $this->noscript) {
    $generated['class'][] = 'hide-if-no-js';

    if ('auto' === $this->sizes)
    unset($noscript['sizes'],$noscript['srcset']);

    if (array_key_exists('id',$noscript))
    $noscript['id'] .= '-noscript';
    }

    if (
    array_key_exists('data-src',$generated) ||
    array_key_exists('data-sizes',$generated)
    )
    $generated['class'][] = 'lazyload';

    if (true === $this->preload)
    $generated['class'][] = 'lazypreload';

    $output = $this->generate_output($generated);

    if (false !== $this->image_id)
    $noscript['src'] = $this->files['__largest']['src'];

    foreach ($noscript['class'] as $i => $class)
    if (
    (
    'size-' === substr($class,0,5) &&
    substr($class,5) !== $this->files['__largest']['name']
    ) ||
    'attachment-' === substr($class,0,11)
    )
    unset($noscript['class'][$i]);

    if (false !== $this->image_id)
    $noscript['class'][] = 'attachment-' . $this->files['__largest']['name'];

    if (true === $this->noscript) $output .= '<noscript>' . $this->generate_output($noscript,true) . '</noscript>' . "\n";

    return $output;
    }

    function generate_output($attributes,$noscript = false) {
    $output[] = '<img';
    $output[] = 'src="' . $attributes['src'] . '"';
    unset($attributes['src']);

    if (array_key_exists('data-src',$attributes)) {
    $output[] = 'data-src="' . $attributes['data-src'] . '"';
    unset($attributes['data-src']);
    }

    $output[] = (array_key_exists('id',$attributes) ? 'id="' . $attributes['id'] . '" ' : '') .
    'title="' . $attributes['title'] . '" ' .
    'alt="' . $attributes['alt'] . '"';
    unset($attributes['title'],$attributes['alt']);

    $output[] = 'class="' . implode(' ',$attributes['class']) . '"';
    unset($attributes['class']);

    $output[] = 'width="' . $attributes['width'] . '" height="' . $attributes['height'] . '"' .
    (array_key_exists('data-sizes',$attributes) && 'auto' === $attributes['data-sizes'] ? ' data-sizes="' . $attributes['data-sizes'] . '"' : '');
    unset($attributes['width'],$attributes['height']);

    if (array_key_exists('data-sizes',$attributes) && 'auto' === $attributes['data-sizes'])
    unset($attributes['data-sizes']);

    $sep = ", \n\t\t" . (true === $noscript ? "\t" : '');
    foreach (array(
    'data-srcset-hires',
    'data-srcset',
    'data-sizes',
    'srcset',
    'sizes'
    ) as $var)
    if (array_key_exists($var,$attributes)) {
    $output[] = $var . '="' . implode($sep,$attributes[$var]) . '"';
    unset($attributes[$var]);
    }

    foreach ($attributes as $attrib => $value) {
    $output[] = $attrib . '="' . (is_array($value) ? implode(' ',$value) : $value) . '"';
    unset($attributes[$attrib]);
    }

    $sep = " \n\t" . (true === $noscript ? "\t" : '');
    return "\n" . (true === $noscript ? "\t" : '') . implode($sep,$output) . " \n" . (true === $noscript ? "\t" : '') . '/>' . "\n";
    }

    function display() { echo $this->output(); }

    function generate_from_id() {
    if (false === $this->image)
    $this->image = get_post($this->image_id);

    if (false === $this->image_sizes)
    $this->image_sizes = array('full');
    else if (!is_array($this->image_sizes))
    $this->image_sizes = (array) $this->image_sizes;

    if (is_array($this->image_sizes) && 0 === count($this->image_sizes))
    $this->image_sizes = array('medium','medium_large','large','full');

    if (0 === count($this->first)) {
    $this->first = wp_get_attachment_image_src($this->image_id,$this->image_sizes[0]);
    $this->width = $this->first[1];
    $this->height = $this->first[2];
    }

    if (false === $this->url)
    $this->url = $this->first[0];

    $attributes = array(
    'src' => $this->first[0],
    'title' => false === $this->title ? get_the_title($this->image) : $this->title,
    'alt' => false === $this->alt ? $this->image->post_content : $this->alt,
    'width' => $this->first[1],
    'height' => $this->first[2],
    'class' => array(
    'attachment-' . $this->image_id,
    'attachment-' . $this->image_sizes[0],
    )
    );
    if (false === $this->alt)
    $attributes['alt'] = ('' === $this->image->post_content ? $attributes['title'] : apply_filters('get_the_content',strip_tags($this->image->post_content)));

    if (
    1 < count($this->image_sizes) // multiple image sizes for 'srcset'
    && (
    false === $this->doing_noscript || // not creating noscript image tag
    'auto' !== $this->sizes // creating noscript image tag, but 'sizes' tag is not dynamic
    )
    ) {

    $this->files['__largest'] = array(
    'width' => 0,
    'src' => self::DATAURI,
    );

    $this->files['__smallest'] = array(
    'width' => 9999999,
    'src' => self::DATAURI,
    );

    if (true === $this->image_hires_sizes)
    $this->image_hires_sizes = array('medium','medium_large','large','full');

    foreach (array(
    'srcset' => 'image_sizes',
    'srcset-hires' => 'image_hires_sizes',
    ) as $attribute => $var)
    if (is_array($this->{$var}) && count($this->{$var}))
    foreach ($this->{$var} as $k => $size) {
    if ('full' !== $size && false === image_get_intermediate_size($this->image_id,$size)) {
    unset($this->{$var}[$k]);
    continue;
    }

    $attributes['class'][] = 'size-' . $size;

    if (array_key_exists($size,$this->files)) {
    $this_size = $this->files[$size];
    $mq = $k;
    if (!is_string($k)) {
    $mq = $this_size[1];
    if ('srcset-hires' === $attribute)
    $mq = round($mq / 2);
    $mq .= 'w';
    }
    $attributes[$attribute][$this_size[1] . 'x' . $this_size[2]] = $this_size[0] . ' ' . $mq;
    unset($this_size);
    continue;
    }

    $src = $this->files[$size] = wp_get_attachment_image_src($this->image_id,$size);
    $mq = $k;
    if (!is_string($k)) {
    $mq = $src[1];
    if ('srcset-hires' === $attribute)
    $mq = round($mq / 2);
    $mq .= 'w';
    }
    $attributes[$attribute][$src[1] . 'x' . $src[2]] = $src[0] . ' ' . $mq;

    if (intval($src[1]) > $this->files['__largest']['width'])
    $this->files['__largest'] = array(
    'width' => intval($src[1]),
    'name' => $size,
    'src' => $src[0],
    );

    if (intval($src[1]) < $this->files['__smallest']['width'])
    $this->files['__smallest'] = array(
    'width' => intval($src[1]),
    'name' => $size,
    'src' => $src[0],
    );
    }

    if (array_key_exists('srcset',$attributes))
    $attributes['sizes'] = $this->sizes;

    }

    $attributes['class'] = array_unique(array_merge($attributes['class'],$this->classes));

    if (is_array($this->attributes) && count($this->attributes)) // merge passed attributes into tag
    $attributes = array_merge($attributes,$this->attributes);

    return $this->tag = $attributes;

    }

    function generate_from_url() {
    if (false === $this->image)
    $this->image = @getimagesize($this->url);

    $attributes = array(
    'src' => $this->url,
    'title' => false !== $this->title ? $this->title : '',
    'alt' => false !== $this->alt ? $this->alt : '',
    'width' => false !== $this->width ? $this->width : (false !== $this->image ? $this->image[0] : false),
    'height' => false !== $this->height ? $this->height : (false !== $this->image ? $this->image[1] : false),
    'class' => $this->classes,
    );

    if (is_array($this->attributes) && count($this->attributes)) // merge passed attributes into tag
    $attributes = array_merge($attributes,$this->attributes);

    return $attributes;
    }

    }

    ?>
  10. @crstauf crstauf revised this gist Jun 2, 2016. No changes.
  11. @crstauf crstauf created this gist Jun 2, 2016.
    324 changes: 324 additions & 0 deletions class.img_tag.php
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,324 @@
    <?php

    class img_tag {

    const DATAURI = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';

    var $url = false,
    $image = false,
    $image_id = false,

    $alt = false,
    $title = false,
    $width = false,
    $height = false,
    $preload = false,

    $sizes = 'auto',
    $output = '',

    $echo = true,
    $lazy = true,
    $noscript = true,

    $first = array(),
    $classes = array(),
    $attributes = array(),
    $image_sizes = array(),
    $image_hires_sizes = array();

    private $tag = array();
    private $files = array();
    private $done_output = false;
    private $doing_noscript = false; // generating noscript image tag

    function __construct($args) {
    if (array_key_exists('theme_image',$args))
    $args['url'] = get_stylesheet_directory_uri() . '/img/' . $args['theme_image'];

    if (array_key_exists('url',$args))
    $this->url = $args['url'];
    else if (
    array_key_exists('image_id',$args) &&
    is_numeric($args['image_id'])
    )
    $this->image_id = $args['image_id'];
    else
    return false;

    foreach ($args as $k => $v)
    $this->$k = $v;
    }

    function __destruct() {
    if (true === $this->done_output) return;
    if (true === $this->echo) $this->display();
    }

    function output() {
    if (false !== $this->image_id)
    $generated = $noscript = $this->generate_from_id();
    else
    $generated = $noscript = $this->generate_from_url();

    $generated['class'][] = $noscript['class'][] = 'generated-img-tag';

    if (
    array_key_exists('srcset',$generated) // multiple sizes of image available
    && (
    $this->lazy || // loading image lazily
    'auto' === $this->sizes // 'sizes' attribute is being set dynamically
    )
    ) {
    $generated['data-sizes'] = $generated['sizes'];
    $generated['data-srcset'] = $generated['data-srcset-hires'] = $generated['srcset'];
    unset($generated['sizes'],$generated['srcset']);
    }

    if (array_key_exists('srcset-hires',$generated)) {
    $generated['data-srcset-hires'] = $generated['srcset-hires'];
    $generated['class'][] = 'srcset-hires';
    unset($generated['srcset-hires']);
    }

    if (true === $this->lazy) {
    if (!array_key_exists('data-srcset',$generated))
    $generated['data-src'] = $generated['src'];
    $generated['src'] = self::DATAURI;
    }

    if (true === $this->noscript) {
    $generated['class'][] = 'hide-if-no-js';

    if ('auto' === $this->sizes)
    unset($noscript['sizes'],$noscript['srcset']);

    if (array_key_exists('id',$noscript))
    $noscript['id'] .= '-noscript';
    }

    if (
    array_key_exists('data-src',$generated) ||
    array_key_exists('data-sizes',$generated)
    )
    $generated['class'][] = 'lazyload';

    if (true === $this->preload)
    $generated['class'][] = 'lazypreload';

    $output = $this->generate_output($generated);

    if (false !== $this->image_id)
    $noscript['src'] = $this->files['__largest']['src'];

    foreach ($noscript['class'] as $i => $class)
    if (
    (
    'size-' === substr($class,0,5) &&
    substr($class,5) !== $this->files['__largest']['name']
    ) ||
    'attachment-' === substr($class,0,11)
    )
    unset($noscript['class'][$i]);

    if (false !== $this->image_id)
    $noscript['class'][] = 'attachment-' . $this->files['__largest']['name'];

    if (true === $this->noscript) $output .= '<noscript>' . $this->generate_output($noscript,true) . '</noscript>' . "\n";

    return $output;
    }

    function generate_output($attributes,$noscript = false) {
    $output[] = '<img';
    $output[] = 'src="' . $attributes['src'] . '"';
    unset($attributes['src']);

    if (array_key_exists('data-src',$attributes)) {
    $output[] = 'data-src="' . $attributes['data-src'] . '"';
    unset($attributes['data-src']);
    }

    $output[] = (array_key_exists('id',$attributes) ? 'id="' . $attributes['id'] . '" ' : '') .
    'title="' . $attributes['title'] . '" ' .
    'alt="' . $attributes['alt'] . '"';
    unset($attributes['title'],$attributes['alt']);

    $output[] = 'class="' . implode(' ',$attributes['class']) . '"';
    unset($attributes['class']);

    $output[] = 'width="' . $attributes['width'] . '" height="' . $attributes['height'] . '"' .
    (array_key_exists('data-sizes',$attributes) && 'auto' === $attributes['data-sizes'] ? ' data-sizes="' . $attributes['data-sizes'] . '"' : '');
    unset($attributes['width'],$attributes['height']);

    if (array_key_exists('data-sizes',$attributes) && 'auto' === $attributes['data-sizes'])
    unset($attributes['data-sizes']);

    $sep = ", \n\t\t" . (true === $noscript ? "\t" : '');
    foreach (array(
    'data-srcset-hires',
    'data-srcset',
    'data-sizes',
    'srcset',
    'sizes'
    ) as $var)
    if (array_key_exists($var,$attributes)) {
    $output[] = $var . '="' . implode($sep,$attributes[$var]) . '"';
    unset($attributes[$var]);
    }

    foreach ($attributes as $attrib => $value) {
    $output[] = $attrib . '="' . (is_array($value) ? implode(' ',$value) : $value) . '"';
    unset($attributes[$attrib]);
    }

    $sep = " \n\t" . (true === $noscript ? "\t" : '');
    return "\n" . (true === $noscript ? "\t" : '') . implode($sep,$output) . " \n" . (true === $noscript ? "\t" : '') . '/>' . "\n";
    }

    function display() { echo $this->output(); }

    function generate_from_id() {
    if (false === $this->image)
    $this->image = get_post($this->image_id);

    if (false === $this->image_sizes)
    $this->image_sizes = array('full');
    else if (!is_array($this->image_sizes))
    $this->image_sizes = (array) $this->image_sizes;

    if (is_array($this->image_sizes) && 0 === count($this->image_sizes))
    $this->image_sizes = array('medium','medium_large','large','full');

    if (0 === count($this->first)) {
    $this->first = wp_get_attachment_image_src($this->image_id,$this->image_sizes[0]);
    $this->width = $this->first[1];
    $this->height = $this->first[2];
    }

    if (false === $this->url)
    $this->url = $this->first[0];

    $attributes = array(
    'src' => $this->first[0],
    'title' => false === $this->title ? get_the_title($this->image) : $this->title,
    'alt' => false === $this->alt ? $this->image->post_content : $this->alt,
    'width' => $this->first[1],
    'height' => $this->first[2],
    'class' => array(
    'attachment-' . $this->image_id,
    'attachment-' . $this->image_sizes[0],
    )
    );
    if (false === $this->alt)
    $attributes['alt'] = ('' === $this->image->post_content ? $attributes['title'] : apply_filters('get_the_content',strip_tags($this->image->post_content)));

    if (
    1 < count($this->image_sizes) // multiple image sizes for 'srcset'
    && (
    false === $this->doing_noscript || // not creating noscript image tag
    'auto' !== $this->sizes // creating noscript image tag, but 'sizes' tag is not dynamic
    )
    ) {

    $this->files['__largest'] = array(
    'width' => 0,
    'src' => self::DATAURI,
    );

    $this->files['__smallest'] = array(
    'width' => 9999999,
    'src' => self::DATAURI,
    );

    if (true === $this->image_hires_sizes)
    $this->image_hires_sizes = array('medium','medium_large','large','full');

    foreach (array(
    'srcset' => 'image_sizes',
    'srcset-hires' => 'image_hires_sizes',
    ) as $attribute => $var)
    if (is_array($this->{$var}) && count($this->{$var}))
    foreach ($this->{$var} as $k => $size) {
    if ('full' !== $size && false === image_get_intermediate_size($this->image_id,$size)) {
    unset($this->{$var}[$k]);
    continue;
    }

    $attributes['class'][] = 'size-' . $size;

    if (array_key_exists($size,$this->files)) {
    $this_size = $this->files[$size];
    $mq = $k;
    if (!is_string($k)) {
    $mq = $this_size[1];
    if ('srcset-hires' === $attribute)
    $mq = round($mq / 2);
    $mq .= 'w';
    }
    $attributes[$attribute][$this_size[1] . 'x' . $this_size[2]] = $this_size[0] . ' ' . $mq;
    unset($this_size);
    continue;
    }

    $src = $this->files[$size] = wp_get_attachment_image_src($this->image_id,$size);
    $mq = $k;
    if (!is_string($k)) {
    $mq = $src[1];
    if ('srcset-hires' === $attribute)
    $mq = round($mq / 2);
    $mq .= 'w';
    }
    $attributes[$attribute][$src[1] . 'x' . $src[2]] = $src[0] . ' ' . $mq;

    if (intval($src[1]) > $this->files['__largest']['width'])
    $this->files['__largest'] = array(
    'width' => intval($src[1]),
    'name' => $size,
    'src' => $src[0],
    );

    if (intval($src[1]) < $this->files['__smallest']['width'])
    $this->files['__smallest'] = array(
    'width' => intval($src[1]),
    'name' => $size,
    'src' => $src[0],
    );
    }

    if (array_key_exists('srcset',$attributes))
    $attributes['sizes'] = $this->sizes;

    }

    $attributes['class'] = array_unique(array_merge($attributes['class'],$this->classes));

    if (is_array($this->attributes) && count($this->attributes)) // merge passed attributes into tag
    $attributes = array_merge($attributes,$this->attributes);

    return $this->tag = $attributes;

    }

    function generate_from_url() {
    if (false === $this->image)
    $this->image = @getimagesize($this->url);

    $attributes = array(
    'src' => $this->url,
    'title' => false !== $this->title ? $this->title : '',
    'alt' => false !== $this->alt ? $this->alt : '',
    'width' => false !== $this->width ? $this->width : (false !== $this->image ? $this->image[0] : false),
    'height' => false !== $this->height ? $this->height : (false !== $this->image ? $this->image[1] : false),
    'class' => $this->classes,
    );

    if (is_array($this->attributes) && count($this->attributes)) // merge passed attributes into tag
    $attributes = array_merge($attributes,$this->attributes);

    return $attributes;
    }

    }

    ?>