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.