Drilling a Hole in the Universe with WP_Query in a Shortcode

To condense a long prologue into a thesis statement, it is quite possible to output the results of a WordPress “query loop” via Shortcode, but doing so risks drilling a hole in spacetime: Placing a post whose content would include a version of the post itself (containing a version of the post itself, and so on) produces an overload and site crash. ((ERR_CONNECTION_RESET))

I first encountered this danger by accident, and initially wondered if the problem had something to do with specific query “arguments” or with shortcodes or the WordPress main “Loop” as such. In short, it’s just another example of the usual “infinite” regress error. I’ve also realized that under prior versions of the plug-in I’ve been working on, an inadvertent site-crash via infinite-looping was always a danger, presuming the right wrong move by some user.

To solve this problem or avoid this possible danger in the future, I’ve added a short sub-routine that excludes any offending post, or any offending post content, from whatever loop-within-a-loop the plug-in happens to output.

SIMPLE SOLUTION

The easiest and simplest solution seems to just to exclude all posts containing the shortcode from the loop-within-the-loop. Inserting the following within the new query loop or loop-within-the-loop (after $my_query->the_post() ; ), assuming a shortcode “tag” of “add_loopy_table,” suffices:

//$post was already available for other purposes, but anyway we need it
  global $post ;

  if ( has_shortcode( $post->post_content, 'add_loopy_table' ) ) {

      continue ;

  }

The above – or a slightly augmented version of it including “Excerpts” – for sites in which Shortcodes in Excerpts are allowed – is the solution I’m at this point intending to apply, for reasons I’ll get to, despite some limitations.

ALTERNATIVES

Another alternative is to allow inclusion of potentially infinitely offensive posts in whatever loop-within-a-loop, but to modify their content prior to display.

WordPress does include a strip_shortcodes() function that allows us to write a function like the following one, also employing has_shortcode(), but called when the loopy table actually gets to post content within its query:

/***
 *AVOID INFINITE LOOPS BY STRIPPING
 *Strips shortcodes from potentially infinitely loopy posts
 *With message indicating deed has been done
***/
function ck_vs_infinity( $content ) {

    if ( has_shortcode( $content, 'add_loopy_table' ) ) {

         $content = 
            '<p>Shortcodes removed to avoid danger of site crash.</p>' . 
            strip_shortcodes( $content ) ;

    }

    return $content ;

 }

The reason that in this approach we don’t remove the known-dangerous shortcode and leave any others alone is that strip_shortcodes() doesn’t accept parameters narrowing its strip. It’s full shortcode-Monty or nothing as far as strip_shortcodes() is concerned. That also seems to mean that oEmbedded tweets and videos will be ruined, apparently because they rely on an internalized shortcode functionality. 

To target the specific shortcode “Tag” (and variations) precisely, we’d need to parse the content, perhaps using some variation on WordPress’s own Regex, and a probably very reliable version could be written for the specific Tag (with or without arguments), with massaged and messaged content returned. (The function would look like the stripper above, but with a preg_replace() on $content instead of strip_shortcodes().) We could also try supplying and forcing some other alternatives or chain of alternatives whenever the dangerous code appears: Display of excerpt unless also dangerous, whole or partial replacement with animated infinity sign while a “Nearer My God to Thee” audio plays… That kind of thing.

The potential drawback to such solutions, special effects notwithstanding, would involve possible concern over even edgier cases in which a user wanted to include posts containing not-actually-infinitely-loopy tables. To enable these users, I think I’d either have to be able to test whether the potentially infinitely-loopy table was really a bad one, or introduce a settings option, but no practical as well as user-proof way of performing the test occurs to me, and anything requiring the user to follow instructions, or check or uncheck a box, etc., and possibly relying on a new taxonomy or post meta or more, still probably risks accidental inclusions of an actually infinitely-loopy table along with other loose ends, and altogether represents an investment of time and effort on something that may not ever make a difference to anyone.

KEEPING IT USER-PROOF

Maybe someone who has for some reason read this far has a bright and simple additional idea to share. For now, I’m leaning to the first, “has_shortcode/continue” version, because it’s simple and seems most user-proof: Posts that display potentially infinitely loopy tables won’t be displayed, period. ((There is an additional complication, a very minor one in my view, having to do with the way that WP_Query counts iterations: In the presumably very rare cases where the Loop has to be “continued,” the quashed post will still “count” as a post, meaning that a display meant to display 10 posts will in fact display 9, but count 10. The logic required to overcome this rarity, and to explain to users how to avoid it, seems even further beyond the borders of the remotely likely significant.))  As far as my current work goes, I think that’ll be the rule. Users will simply be informed that posts using the shortcode will be excluded from the output, and anyone who contrives some more exotic way of achieving the same effect can be directed to this post.

Until and unless someone (including possibly me) speaks up in favor of special exceptions, I’ll probably leave things that way.

Commenter Ignore Button by CK's Plug-Ins

Leave a Reply

Your email address will not be published. Required fields are marked *

*