get attributes/part of the gallery shortcode

I’m trying to grab all image id’s that are associated with the shortcode that are listed as exclude. For example: if my post has I’d like to get a variable that would echo like this echo $excludes; result 1,2,3 thank you for any help you can offer.

Related posts

Leave a Reply

3 comments

  1. The task

    It’s not as easy, as it looks at a first glance. The main problem is, that you can define your own [gallery] shortcode and simply override the default. Actually that’s what some themes are doing (blame you ThemeForest authors!). In this case, simply hooking into post_gallery won’t work in every case.

    Drawbacks for post_gallery

    The problem is that both the shortcode, as well as the core callback can be overridden and therefore every callback will simply be knocked out.

    Drawbacks for the_content

    If you’re switching to another filter and take the raw output, then you’ll have to deal (another time) with the Regex. This is slow and mostly won’t be simple.

    So what to do now? Easy. Interact with the global $shortcode_tags. It holds the callback as second argument, so it’s actually not too hard to determine in which case we are. Then we can simply switch on demand. This way we have a fine balance between reliability and performance.

    Build a base plugin

    Here’s a plugin that defines an abstract class (one that must get extended in order to work). There’re three things that need definition in the child class:

    • $part – the part you want to retrieve
    • $type – the type of match you need. Valid are digit/alphanumeric/alpha
    • process_atts() – the method that processes your output – whatever you want to do with the result

    Just upload this via (S)FTP into your plugins folder and activate.

    <?php
    /** Plugin Name: (#70451) »kaiser« Get Gallery attributes (Base) */
    if ( ! class_exists( 'wpse70451_extract_gallery_atts' ) )
    {
    
    abstract class wpse70451_extract_gallery_atts
    {
        public $atts  = array();
    
        public $error;
    
        // Must get defined in extending class
        public $part;
        public $type;
    
        public static function init()
        {
            is_null( self :: $instance ) AND self :: $instance = new self;
            return self :: $instance;
        }
    
        public function __construct()
        {
            ! isset( $this->part ) AND new WP_Error();
    
            add_action( 'loop_start', array( $this, 'error_handler' ) );
    
            // The value of the array is the callback fn name
            // If it's the default, then we're on the safe side,
            // as the core fn is no pluggable and can't get overridden.
            if ( 'gallery_shortcode' === $GLOBALS['shortcode_tags'] )
            {
                add_filter( 'post_gallery', array( $this, 'get_gallery_atts' ), 0, 2 );
            }
            // Else we have to go with a slower regex
            else
            {
                add_filter( 'the_content', array( $this, 'get_gallery_ids' ), 0 );
            }
        }
    
        public function error_handler()
        {
            if (
                ! in_array(
                     $this->type
                    ,array(
                         'digit'
                        ,'alphanumeric'
                        ,'alpha'
                     )
                )
                OR ! empty( $this->type )
            )
                return new WP_Error( 
                     'invalid_type'
                    ,__( 'Invalid type set.', 'wpse70451_textdomain' )
                    ,__FILE__
                );
        }
    
        public function __toString()
        {
            $is_error = $this->error;
    
            if ( ! is_wp_error( $is_error ) )
                return;
    
            // No error message for Guests or Subscribers
            // Assuming that no one has activated caching plugins when debugging
            // and not set WP_DEBUG to TRUE on a live site
            if ( 
                ! is_user_logged_in()
                AND ! current_user_can( 'edit_posts' ) 
                AND ( ! defined( 'WP_DEBUG' ) OR ! WP_DEBUG )
            )
                return '';
    
            // Error output for development
            return "{$is_error->get_error_message( 'invalid_type' )}: {$is_error->get_error_data()}";
        }
    
        public function get_gallery_ids( $content )
        {
            $pattern = get_shortcode_regex( $content );
            preg_match_all( "/{$pattern}/s", $content, $matches );
            $atts = explode( " ", array_shift( $matches[3] ) );
            foreach ( $atts as $att )
            {
                if ( strstr( $att, $this->part ) )
                    break;
            }
            preg_match_all( $this->get_regex( $this->type ), trim( $att ), $atts );
            $this->atts = array_filter( $atts );
    
            return $content;
        }
    
        // Build pattern
        public function get_regex( $type )
        {
            switch ( $type )
            {
                case 'digit' :
                    $pattern_atts = '/(d*)/';
                    break;
    
                case 'alphanumeric' :
                    $pattern_atts = '/([A-Za-z0-9]*)/';
                    break;
    
                case 'alpha' :
                    $pattern_atts = '/([A-Za-z]*)/';
                    break;
    
                default :
                    // Add a method name `get_pattern()` to the extending class
                    // to work with a custom regex pattern.
                    if (  method_exists( $this, 'get_pattern' ) )
                    {
                        $pattern_atts = $this->get_pattern();
                        break;
                    }
                    $pattern_atts = $this->get_regex( 'alphanumeric' );
                    break;
            }
    
            return $pattern_atts;
        }
    
        public function get_gallery_atts( $content, $atts )
        {
            $this->atts = $atts[ $this->part ];
    
            // Allow overrides to trigger
            // at this point we already got what we need
            return $content;
        }
    
        // Must get defined in extending class
        public abstract function process_atts() {}
    } // END Class
    
    } // endif;
    

    Handle a task, get a child

    Here you see the actual processing plugin. First it hooks itself statically to the init hook and then runs the parents __construct() method to retrieve the attributes.

    Then you need to define what attributes you want to retrieve (see the classes properties $part and $type, which already default to what you asked for).

    The last two decisions you need to make are

    1. What do I want to do with my result? See process_atts()
    2. When do you want to output the result. See __construct() and where process_atts() is hooked in.

    It’s as easy as that.

    If you need a custom regex, just add a method named get_regex() to your extending class and return your custom pattern. Then set the $type to and empty string '' and you’re ready to go.

    <?php
    /** Plugin Name: (#70451) »kaiser« Get Gallery excludes */
    
    if ( ! class_exists( 'wpse70451_extract_gallery_excludes' ) )
    {
        add_action( 'init', array( 'wpse70451_extract_gallery_excludes', 'init' ) );
    
    final class wpse70451_extract_gallery_excludes extends wpse70451_extract_gallery_atts
    {
        public static $instance;
    
        public $part = 'exclude';
    
        public $type = 'digit';
    
        public static function init()
        {
            is_null( self :: $instance ) AND self :: $instance = new self;
            return self :: $instance;
        }
    
        public function __construct()
        {
            parent :: __construct();
    
            // Example hook: `loop_end`
            add_action( 'loop_end', array( $this, 'process_atts' ) );
        }
    
        public function process_atts()
        {
            $markup = '';
            // Do something with $this->atts;
            return print $markup;
        }
    } // END Class
    
    } // endif;
    

    Alter what you need and then again: Just upload this via (S)FTP into your plugins folder and activate.

  2. If you also need to display the content on the same page, what about using the post_gallery filter? You won’t need any regex then

    add_filter('post_gallery', 'gallery_shortcode_excludes', 10, 2);
    function gallery_shortcode_excludes($content, $attr) {
        $excludes = $attr['excludes'];
        // maybe also save it in some global/class/static variable
    
        //  return empty string to let wordpress continue to the shortcode output
        return '';
    }
    
  3. It took me a while to find a solution that worked for me, but since all I was looking for was the delimited list of attachment id’s associated with a certain attribute like exclude or hide, this worked for me:

    # Grab the list of "hide" attribute
    $regex_pattern = get_shortcode_regex();
    preg_match ('/'.$regex_pattern.'/s', $post->post_content, $regex_matches);
        if ($regex_matches[2] == 'gallery') :
         $attribureStr = str_replace (" ", "&", trim ($regex_matches[3]));
         $attribureStr = str_replace ('"', '', $attribureStr);
         //  Parse the attributes
          $defaults = array (
          'hide' => '1',
         );
        $attributes = wp_parse_args ($attribureStr, $defaults);
         if (isset ($attributes["hide"])) :
          $excludeID = get_post_thumbnail_id() . ',' . $attributes["hide"];
         else :
          $excludeID = get_post_thumbnail_id();
       endif;
    endif;