Automattic / pym-shortcode

A WordPress solution to embed iframes that are responsive horizontally and vertically using the NPR Visuals Team's https://blog.apps.npr.org/pym.js/
https://wordpress.org/plugins/pym-shortcode/
GNU General Public License v2.0
14 stars 7 forks source link

Because shortcodes and blocks are processed at different times, a shortcode can be output without necessary dependencies on the page #35

Closed benlk closed 5 years ago

benlk commented 5 years ago

Originally reported in #34, the ticket for adding Gutenberg support to the plugin.

With the following post_content:

<!-- wp:shortcode -->
[pym src="https://f.benlk.com/graphics/heartbeat-abortion-bills/child.html"]
<!-- /wp:shortcode -->

<!-- wp:paragraph -->
<p>the preceding is a shortcode block.</p>
<!-- /wp:paragraph -->

<!-- wp:paragraph -->
<p>The following is the Pym Embed:</p>
<!-- /wp:paragraph -->

<!-- wp:pym-shortcode/pym {"src":"http://blog.apps.npr.org/pym.js/examples/table/child.html","align":"full"} /-->

The following output:

<div id="pym_1" class="pym  "></div>
<script>var pym_1 = new pym.Parent('pym_1', 'https://f.benlk.com/graphics/heartbeat-abortion-bills/child.html', {})</script>
<p>the preceding is a shortcode block.</p>
<p>The following is the Pym Embed:</p>
<div id="pym_0" class="pym alignfull "></div>
<script src="http://pym-shortcode.test/wp-content/plugins/pym-shortcode/js/pym.v1.min.js"></script><script>var pym_0 = new pym.Parent('pym_0', 'http://blog.apps.npr.org/pym.js/examples/table/child.html', {})</script>

After dumping the filters hooked on 'the_content' with global $wp_filter; var_dump( $wp_filter['the_content'], true );, I found that the block rendering filter do_blocks runs before the shortcode renderer do_shortcode.

Thus, in a post with one block and one shortcode, the first block gets the id pym_0 and the first shortcode gets the id pym_1.

Because the current behavior of the function pym_shortcode() — which is used for the shortcode and the block output — is to output the Pym.js-loading tag <script src="http://pym-shortcode.test/wp-content/plugins/pym-shortcode/js/pym.v1.min.js"></script> only during the first call, for pym_0, the later call to pym_shortcode() earlier in the post_content doesn't output the script tag, which means that pym_1's new pym.Parent call doesn't work, because pym is not yet defined.

benlk commented 5 years ago

The following things must be ensured:

Here are the solutions that I can think of:

string matching and global variables and filters to put the pymsrc script tag at the start of the_content()

  1. Add a filter to the_content that checks for the presence of the string 'pym', and if it is there, sets a global "maybe" variable to true
  2. In the pym renderer, if it is called, if the tag doesn't have its own pymsrc, set a global definitely variable to true. If pymsrc is set, then instead output the pymsrc's tag
  3. In a filter running on the_content that runs at a very late priority, like 100, if $maybe and $definitely, prepend the_content with a script tag that registers the appropriate pymsrc.

Enqueue the new pym.Parent in the footer

  1. Everytime we would output a <script>var pym_1 = new pym.Parent('pym_1', 'https://f.benlk.com/graphics/heartbeat-abortion-bills/child.html', {})</script> , instead of outputting it then, add it to the footer with a generated callback function that has the correct variables inserted into its call.

This doesn't move the location of the pymsrc tag starting Pym, but it also does not prevent addressing #33 by enqueuing the pymsrc tag in the wp_footer as long as the function outputting that tag is enqueued at a higher priority.

benlk commented 5 years ago

I asked in #wordpress on freenode IRC, and received feedback to the effect that the best place to put those script tags is in <head> or at the end of <body> with wp_footer.

benlk commented 5 years ago

My worry is that someone using this plugin is going to be using WordPress in a way that powers a non-main-website content presentation, and their content presentation is going to render the_content() as HTML with scripts and stuff, but without any of the dependency-satisfying code from wp_footer.

benlk commented 5 years ago

Feedback in #wordpress on newsnerdery.org Slack from several people also recommends wp_footer.