0

Here I have written a (pretty safe) shortcode for embedding iFrames in WordPress:

add_shortcode( 'r2o_iframe', 'r2o_display_iframe' );

function r2o_display_iframe($atts) {

    ob_start();

    $src = $atts["src"];
    $width = intval($atts["width"]);
    $height = intval($atts["height"]);
    $name = htmlentities($atts["name"]);
    $noscrolling = (bool) $atts["noscrolling"];
    $seamless = (bool) $atts["seamless"];

    $allowed_origins = r2o_get_option(SET_PREFIX . 'iframe_shortcode_allowed_origins');

    $startswith = function($haystack, $needle) {
        $length = strlen($needle);
        return (substr($haystack, 0, $length) === $needle);
    };

    // if the src is allowed
    if(is_array($allowed_origins)) {
        if(filter_var($src,FILTER_VALIDATE_URL)) {
            $allowed = false;
            foreach($allowed_origins as $origin) {

                // if origin is https, convert src to https and compare
                if($startswith($origin["origin"],"https://")) {
                    if(!$startswith($src,"https://")) {
                        $nsrc = preg_replace("/^http:/i", "https:", $src);
                        if($startswith($nsrc,$origin["origin"])) {
                            $src = $nsrc;
                            $allowed = true;
                            break;
                        }
                    }
                // else allow both
                } else {
                    if($startswith($src,$origin["origin"]) || $startswith($src,preg_replace("/^http:/i", "https:", $origin["origin"]))) {
                        $allowed = true;
                        break;
                    }
                }
            }
            if($allowed) { ?>
                <iframe frameborder="0"  src="<?php echo $src; ?>"
                    <?php echo ($width > 0) ? 'width="'.$width.'"' : '' ?>
                    <?php echo ($height > 0) ? 'height="'.$height.'"' : '' ?>
                    <?php echo ($name != "") ? 'name="'.$name.'"' : '' ?>
                    <?php echo ($seamless) ? 'seamless="seamless"' : '' ?>
                    <?php echo ($noscrolling) ? 'scrolling="no"' : '' ?>
                ></iframe>
                <?php

            } else {
                ?><p class="error"><?php _e('An embedded content is missing here (unknown origin).','r2ocm'); ?></p><?php
            }
        } else {
            ?><p class="error"><?php _e('An embedded content is missing here (origin is not a valid URL).','r2ocm'); ?></p><?php
        }
    } else {
        ?><p class="error"><?php _e('An embedded content is missing here (allowed origins are not defined).','r2ocm'); ?></p><?php
    }

    return ob_get_clean();
}

The problem: WordPress keeps stripping out the width, height and name attribute from the iFrame. I can not see a single good reason why WordPress applies its text sanitizing functions to shortcode outputs.

Tried to solve it like this:

add_filter( 'no_texturize_shortcodes', 'shortcodes_to_exempt_from_wptexturize' );
function shortcodes_to_exempt_from_wptexturize( $shortcodes ) {
    $shortcodes[] = 'r2o_iframe';
    return $shortcodes;
}

However still no result. WordPress removes those required attributes.

Output:

<iframe frameborder="0" src="https://www.example.com/index.html" style="width:100%;height:100px;"  seamless="seamless" scrolling="no"></iframe>

What can I do to prevent this annoying behavior?

5
  • Are you sure it's stripping them out? How did you confirm it's WP doing that and not the conditional in the shortcode failing? Additionally is this being output via the_content() or some other method?
    – Tom J Nowell
    Commented Jul 10, 2018 at 16:23
  • 1
    I tried to replicate your problem by reducing it to the simplest version, and could not replicate it gist.github.com/tomjn/34c30a36e2930a64ac982003092620bb
    – Tom J Nowell
    Commented Jul 10, 2018 at 16:30
  • Adding in just the width part also introduced PHP warnings about undefined offsets, the code in the Q never checks if the attributes are actually defined. Adding the parameter resulted in the desired behaviour with no issues
    – Tom J Nowell
    Commented Jul 10, 2018 at 16:32
  • My guess would be there is a filter on the_content, possibly for responsive image handling, that simply strips any height and width attributes it finds.
    – cjbj
    Commented Jul 10, 2018 at 16:42
  • Thank you for your halp so far. Indeed you are right most probably. This is not default Wordpress behaviour, but caused by a Plugin or Theme added Filter. Hope Iwill fimd it soon, but I guess you can make an answer from what you have found so far.
    – Blackbam
    Commented Jul 11, 2018 at 7:24

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.