Make WordPress Core

Opened 11 years ago

Last modified 7 years ago

#25435 assigned feature request

Introduce alternative to do_shortcode( '[shortcode]' )

Reported by: jdgrimes's profile jdgrimes Owned by: rmccue's profile rmccue
Milestone: Future Release Priority: normal
Severity: normal Version:
Component: Shortcodes Keywords: has-patch has-unit-tests needs-refresh
Focuses: Cc:

Description

There are times when we want to call a shortcode programmatically. Currently, the easiest way to do this is do_shortcode( '[shortcode]' ). But that does lots of unnecessary work. A developer has two alternatives:

  1. Manually search through the source and find the function that handles the shortcode, and call it directly. The only problem is that this doesn't offer a very forward-compatible solution, especially when the shortcode is being offered by a plugin.
  2. Search through $shortcode_tags to find and call the function. That's more forward-compatible, but it kind of seems hacky.

I'd like to request that we offer a core function that does number 2 rather than each developer having to implement it themselves.

Example:

call_shortcode_func( 'shortcode', $atts, $content );

(We can change the name of the function.)

Patch forthcoming.

Attachments (6)

25435.diff (1002 bytes) - added by jdgrimes 11 years ago.
Introduces call_shortcode_func()
25435.2.diff (1.3 KB) - added by rmccue 9 years ago.
Rewritten patch
25435.3.diff (1.2 KB) - added by miqrogroove 9 years ago.
25435.4.diff (1.5 KB) - added by DrewAPicture 9 years ago.
Docs fixes
25435.5.diff (1.5 KB) - added by rmccue 9 years ago.
Add shortcode tag to error message
25435.6.diff (6.0 KB) - added by DrewAPicture 9 years ago.
Translator comments + tests

Download all attachments as: .zip

Change History (40)

@jdgrimes
11 years ago

Introduces call_shortcode_func()

#1 follow-up: @DrewAPicture
11 years ago

  • Milestone Awaiting Review deleted
  • Resolution set to invalid
  • Status changed from new to closed

You can just call the shortcode's callback function directly.

So for instance, the [gallery] shortcode callback is gallery_shortcode(), and you can do:

echo gallery_shortcode( $attr );

#2 in reply to: ↑ 1 @jdgrimes
11 years ago

  • Resolution invalid deleted
  • Status changed from closed to reopened

Replying to DrewAPicture:

You can just call the shortcode's callback function directly.

So for instance, the [gallery] shortcode callback is gallery_shortcode(), and you can do:

echo gallery_shortcode( $attr );

Yes, I know that and mentioned it above, but it becomes a bigger issue when dealing with plugins, which may change the function name without notice. I guess maybe that's an edge case though?

My thinking was that if we make people search through the source looking for the right function to call, they'll just call do_shortcode( '[shortcode]' ) instead. If we can point them to an easy to use core function, they'll probably use it.

I think this is the best solution to the problem, but if you don't think it's a real problem, or isn't big enough to require this solution, I'll respect that.

#3 @wonderboymusic
11 years ago

  • Resolution set to wontfix
  • Status changed from reopened to closed

What Drew said - some wrappers cause too much reflection, like the one you are proposing

#4 @rmccue
11 years ago

+1 in favour of reopening this.

It's certainly possible to call the callback directly if you know it, but that's not necessarily the case. Shortcodes are pretty fluid, and it's possible that a plugin could change the gallery shortcode (e.g.) to its own instead.

The current solutions are either extremely heavy (do_shortcode) or require an obscure way to call them (do_shortcode_tag).

I think we should add something like do_single_shortcode( 'gallery', [ 'a' => 'b' ], 'optional body content' ).

#5 @rmccue
11 years ago

  • Milestone set to Future Release
  • Resolution wontfix deleted
  • Status changed from closed to reopened

Reopening, because rmccue-likes.

#6 follow-up: @nacin
11 years ago

Nested shortcodes pose a bit of a problem here.

#7 in reply to: ↑ 6 @jdgrimes
11 years ago

Replying to nacin:

Nested shortcodes pose a bit of a problem here.

Not sure what you mean by that. If you are using nested shortcodes, then you should be using do_shortcode() instead of this, or calling the nested ones like this before passing the the result in as the $content.

#8 @nacin
11 years ago

#19806 was marked as a duplicate.

#9 @Viper007Bond
11 years ago

I like this.

Nested shortcodes shouldn't be a problem -- they would just call do_shortcode() like you do now. This just allows skipping calling do_shortcode() when you know what the shortcode/content is, unlike a nested shortcode.

#10 @rmccue
11 years ago

I'm still +1 on this. :)

#11 @miqrogroove
9 years ago

  • Summary changed from Intoduce function for use instead of do_shortcode( '[shortcode]' ) to Introduce alternative to do_shortcode( '[shortcode]' )

#12 @nickciske
9 years ago

+1

Since this was in "600 entries in over 270 plugins"* back in 2013 (and is almost certainly worse now) it would seem like a better way forward would be to tweak do_shortcode() to detect the case of a single shortcode being called, and if so, run do_shortcode_tag() directly. That avoids the overhead of scanning the entire $shortcode_tags array without adding a new function or requiring hundreds of plugins to be updated.

I know shortcodes in general are up for a rebuild, but this seems like some very low hanging fruit that could improve performance across hundreds of plugins (especially for sites with large numbers of registered shortcodes) in the meantime.

#13 @wonderboymusic
9 years ago

  • Owner set to rmccue
  • Status changed from reopened to assigned

you seemed jazzed about this

@rmccue
9 years ago

Rewritten patch

#14 follow-up: @rmccue
9 years ago

Rewrote the patch. Since this is intended for internal use, it now returns a WP_Error on invalid arguments. (If you're doing output and would rather ignore stuff, probably best to call do_shortcode still.)

If @nickciske's suggestion sounds OK, we could probably do it, but I think it's more trouble than it's worth. It'd introduce a fair bit of complexity into do_shortcode for an edge case that's better handled by a separate function, IMO.

Testing shows it comes out barely faster than do_shortcode, but calling it is a fair bit nicer for internal use:

$old = do_shortcode( '[gallery columns="2" ids="19,20,21,22"]' );
$new = do_single_shortcode( 'gallery', array( 'columns' => 2, 'ids' => '19,20,21,22' ) );

(Plus, the error returns mean you can actually handle invalid codes rather than just getting back your input string.)

#15 @rmccue
9 years ago

(Also, needs a thumbs up from @miqrogroove I think.)

@miqrogroove
9 years ago

#16 @miqrogroove
9 years ago

Please see 25435.3.diff for style improvements.

Thumbs up.

#17 @rmccue
9 years ago

  • Keywords commit added
  • Milestone changed from Future Release to 4.4

Rock on.

#18 in reply to: ↑ 14 @jdgrimes
9 years ago

  • Keywords commit removed

Replying to rmccue:

Testing shows it comes out barely faster than do_shortcode...

Running 1000 iterations of each, I found do_single_shortcode() ~10% faster, and that it consumed about 52 kb less memory. Perhaps not as big a difference as we might have thought.

#19 @jdgrimes
9 years ago

  • Keywords commit added

@DrewAPicture
9 years ago

Docs fixes

#20 follow-up: @DrewAPicture
9 years ago

  • Keywords commit removed

25435.4.diff fixes up the docs a little bit.

I'm not sure the WP_Error is terribly useful without also citing the shortcode tag that doesn't have a registered callback. Can we add that to the string?

@rmccue
9 years ago

Add shortcode tag to error message

#21 in reply to: ↑ 20 @rmccue
9 years ago

Replying to DrewAPicture:

I'm not sure the WP_Error is terribly useful without also citing the shortcode tag that doesn't have a registered callback. Can we add that to the string?

Good thinking; added to the translated string.

Replying to jdgrimes:

Perhaps not as big a difference as we might have thought.

Indeed, although I think adding this adds a nice API for internal use, and it's a bit cleaner than formatting a string just to call a shortcode.

@DrewAPicture
9 years ago

Translator comments + tests

#22 @DrewAPicture
9 years ago

  • Keywords has-unit-tests added

25435.6.diff adds translator comments to the WP_Error strings, as well as some tests for the new function.

#23 @wonderboymusic
9 years ago

  • Keywords needs-refresh added

do_shortcode() and do_single_shortcode() sound synonymous. New func needs a different name since they do totally different things.

#24 @wonderboymusic
9 years ago

  • Milestone changed from 4.4 to Future Release

This ticket was mentioned in Slack in #core by wonderboymusic. View the logs.


9 years ago

#26 @swissspidy
8 years ago

  • Milestone changed from Future Release to 4.8

Would be nice to get some traction here. Any suggestions for a better function name?

#27 @aaemnnosttv
8 years ago

How about simply call_shortcode( $tag, $atts, $content ) ? I realize this is only slightly different than the original suggestion, but that's what I came up with before I knew about this ticket.

Here's my implementation: https://gist.github.com/aaemnnosttv/0751dea2121db3a859fa

For what it's worth, I think it would be better return an empty string than a WP_Error if the shortcode callback isn't callable since this is basically a template function. get_template_part() doesn't do this, and dealing with a WP_Error in the template just seems gross, as well as potentially causing real errors if it isn't properly checked for: (PHP Catchable fatal error: Object of class WP_Error could not be converted to string in ...). A bit worse than not showing anything IMO.

We already have shortcode_exists(), using a WP_Error here seems a bit unnecessary, although I admit they do check different things. What if shortcode_exists() checked if the callback is callable as well?

I trigger a PHP notice in my implementation, but perhaps an action could be fired instead, similar to a wp_mail() failure?

This ticket was mentioned in Slack in #core by jeffpaul. View the logs.


8 years ago

#29 @jbpaul17
8 years ago

  • Milestone changed from 4.8 to 4.8.1

Per yesterday's bug scrub, we're going to punt this to 4.8.1.

This ticket was mentioned in Slack in #core by jeffpaul. View the logs.


7 years ago

This ticket was mentioned in Slack in #core by jeffpaul. View the logs.


7 years ago

#32 @jbpaul17
7 years ago

  • Milestone changed from 4.8.1 to 4.9

Per today's bug scrub, we'll punt this as the focus for 4.8.1 is regressions only.

This ticket was mentioned in Slack in #core by jeffpaul. View the logs.


7 years ago

#34 @jbpaul17
7 years ago

  • Milestone changed from 4.9 to Future Release

Punting to Future Release per today's 4.9 bug scrub.

Note: See TracTickets for help on using tickets.