Shortcode empty attribute

Is there a way of creating an empty attribute for a shortcode?

Example:

Read More
function paragraph_shortcode( $atts, $content = null ) {

   return '<p class="super-p">' . do_shortcode($content) . '</p>';
}

add_shortcode('paragraph', 'paragraph_shortcode'); 

User types

[paragraph] something [/paragraph]

and it shows

<p class="super-p"> something </p>

How to add an empty attribute functionality to my first code? So when user types

[paragraph last] something
[/paragraph]

It will output:

<p class="super-p last"> something </p>

I believe adding a:

extract( shortcode_atts( array(
            'last' => '',
        ), $atts ) );

is a good start, but how to check if user used the “last” attribute while it doesn’t have a value?

Related posts

Leave a Reply

6 comments

  1. There could be a couple ways to do this. Unfortunately, I don’t think any will result in exactly what you’re going for. ( [paragraph last] )

    1. You could just create separate shortcodes for [paragraph_first] [paragraph_last] [paragraph_foobar] that handle $content without needing any attributes

    2. You could set the default value for last to false instead of '', then require users to do [paragraph last=""]content[/paragraph]

    3. You could add a more meaningful attribute such as position which could then be used like [paragraph position="first"] or [paragraph position="last"]

    Because of the fact that WordPress discards any atts not given defaults, and the fact that an att without an ="value" is given the default value same as if it’s not listed at all, I don’t see any way to achieve [paragraph last]

    Hopefully one of my 3 workaround will prove useful. Good luck!

  2. WordPress does not discard attributes without values as is suggested by SethMerrick, but it does not handle it as you would expect. In your example, you would not be able to check isset($atts['last']), but “last” is passed as a value to an unnamed attribute. In this case, this would result in TRUE: ($atts[0] == 'last'). So, you could do a foreach loop to check for any attribute with a value of “last”.

  3. When [example attr1="value1" attr2 attr3="value3" attr4] is parsed, the $atts parameter yields:

    $atts = array (
        'attr1' => 'value1',
              0 => 'attr2',
        'attr3' => 'value3',
              1 => 'attr4'
    );
    

    You can normalize this like so, then you can call shortcode_atts on it.

    if (!function_exists('normalize_empty_atts')) {
        function normalize_empty_atts ($atts) {
            foreach ($atts as $attribute => $value) {
                if (is_int($attribute)) {
                    $atts[strtolower($value)] = true;
                    unset($atts[$attribute]);
                }
            }
            return $atts;
        }
    }
    
    function paragraph_shortcode ($atts, $content = null) {
        extract(shortcode_atts(
            array (
                'last' => ''
            ),
            normalize_empty_atts($atts)
        ));
    
        return '<p class="super-p'
            .($last ? ' last' : '')
            .'">'
            .do_shortcode($content)
            .'</p>';
    }
    
    add_shortcode('paragraph', 'paragraph_shortcode');
    

    Other notes:

    • [paragraph last] would make $last = true. [paragraph last="1"] would make $last = '1'.
    • Attributes are case-insensitive, so [paragraph LAST] is equivalent to [paragraph last].
    • Attributes cannot be purely numeric, so the foreach loop I created is safe against integer-indexed attributes.
  4. I know this is old, but I didn’t feel any of the answers were complete, compact answers. Many people are suggesting running the $atts array through a foreach to find if your value exists. In reality, I don’t feel it needs to be that complicated; array_search could be used instead to simplify things.

    In the case of your example, you could use this:

    [paragraph last] something [/paragraph]

    then to determine if the empty attribute is provided, use a basic conditional to check and see if the key returned null or as an integer (including zero):

    // Returns the array key, if empty attribute is found
    $last_key = array_search('last', $atts);
    
    // Determine if the key is an integer, zero or greater
    // (In the event you're passing multiple empty attributes)
    if(is_int($last_key)) {
      // Do something, your attribute is set
    }
    
  5. The accepted answer here is both wrong and right. The phrase:

    “WordPress discards any atts not given defaults”

    is only true only of the shortcode_atts function and not the WP shortcode functionality as a whole.

    If you look at the code below:

    add_shortcode( 'paragraph', 'custom_shortcode_paragraph' );
    function custom_shortcode_paragraph( $atts ) {
        // Attribute Defaults Function 
        $atts = shortcode_atts(
            array(
                'last' => false,
            ),
            $atts
        );
        $isLast = $atts['last'] !== false;
    }
    

    A shortcode usage like [paragraph last] something [/paragraph] will always have a value of false for the $isLast var.

    The issue is that when the shortcode_atts function runs it does discard the attributes without values. However, they are absolutely in the $atts array before that point though. A var_dump of $atts as the first line of the custom_shortcode_paragraph function would produce:

    array(1) {
      [0]=>
      string(4) "last"
    }
    

    So the 0th item in the array is a string of the attribute name forced to lowercase.

    Let’s change the code to the following instead:

    add_shortcode( 'paragraph', 'custom_shortcode_paragraph' );
    function custom_shortcode_paragraph( $atts ) {
        // look for the existance of the string 'last' in the array
        $last = in_array('last', $atts); // $last is now a boolean
        // Attribute Defaults Function 
        $atts = shortcode_atts(
            array(
                'last' => $last, // default to true if the attribute existed valueless
            ),
            $atts
        );
        $isLast = $atts['last'] !== false;
    }
    

    You now have $atts['last'] === true && $isLast === true for the shortcode:

    [paragraph last] something [/paragraph]
    

    if you do end up adding a value then the shortcode:

    [paragraph last="any value at all"] something [/paragraph]
    

    would yeild $atts['last'] === "any value at all" && $isLast === true. $last would be false because the $atts array in the beginning has the contents:

    array(1) {
      ["last"]=>
      string(16) "any value at all"
    }
    

    So the value of the array item is no longer the attribute name and in_array('last', $atts) === false so the default value is shortcode_atts is false. but that is just a default that gets overwritten by the actual value of any value at all and then $atts['last'] !== false is true because "any value at all" !== false.

    All said, I think this does what you want and is resilient to user error.