Embed External Media in WordPress Posts and Pages with Shortcodes

One of the most powerful and most used WordPress features is the Shortcode API. It gives you an ability to register a special code (shortcode) with the system and assign a custom callback to it for displaying the content each time, when this code appears on post or page.

Embed External Media in WordPress Posts and Pages with Shortcodes

There are various cases when shortcodes are extremely helpful. Today we are going to take a detailed look at one of them - we will learn how to use WordPress shortcodes to embed external content directly into posts or pages.

Embed External Media in WordPress Posts and Pages with Shortcodes

Nowadays the diversity of content distribution channels is extremely wide - there are image and video hosting, services for documents' publishing, music channels and, finally, social networks. The role of website (personal or corporate) transforms into being a hub for various content types, so that it becomes extremely important to have an ability to represent the content from one or another web-service directly on site.

WordPress made a great movement onto this direction with the support of oEmbed format: embedding content became as easy as copying a link. But... there is always a "but". Not all content formats can be embedded this way and sometimes you need an alternative. But even for supported formats we still need the ability to apply styling and make embedded objects look standard and consistent across the site. In the case of WordPress, all these enhancements can be achieved through shortcodes.

What are we going to do? We will construct a single shortcode that will be able to support different providers and insert the proper content based on two parameters: 'source' - the provider identifier and 'src' - the corresponding content URL. Why use a single shortcode instead of several? It helps to have a consistent markup and apply the solid CSS styling.

For example, we can create captions for each media object nearly the same way we do for images, but there is no need to include the markup for captions directly into the post content. Such an approach reduces the number of probable mistakes and makes things easier for end-users. Speaking about markup - let's make it responsive through well-known CSS tricks that creates scalable iframes, videos etc. (more on the subject).

Let's start with embedding documents and then add some other content types like external images, video and presentations.

Embed documents

There are plenty of cases when you have to use some kind of documents (e.g. PDF) to present content that could not be simply republished with HTML:

  • documents aimed to be printed (templates of all types, forms to fill etc.)
  • documents of special formatting that's not intended for web-publishing (e.g.. scientific articles)
  • complementary information with specific details (documentation, manuals, tech-specs etc.)
  • scanned documents that should be published for legal or demo reasons

The simplest solution is to include a download link. But from a UX perspective it could be an unfriendly decision - users cannot preview the content of the file until it's downloaded. Fortunately, we have a way to embed documents directly into webpages with the help of Google Docs Viewer. This service allows you to view documents of different formats (like MS Office, PDF, PSD etc.) directly in the browser. Aimed at Google Docs/Drive users, it is also available as a stand-alone app.

The Viewer has an embed mode so that documents can be display directly inside the website pages. All we have to do is to generate such code ourselves inside out shortcode callback:

add_shortcode('frl_embed', 'frl_embed_screen');

function frl_embed_screen($attrs, $content = '') {
        
        $out = '';
        extract(shortcode_atts(array('source' => '', 'src' => ''), $attrs));
        
        if(empty($src))
                return $out;
        
        $valid_soursces = array('gdocs');
        
        if(!in_array($source, $valid_soursces))
                return $out;    
        
        /* Prepare embed markup */
        if($source == 'gdocs') {
                
                $src = 'http://docs.google.com/viewer?url=".rawurlencode($src).'&embedded=true';
                $embed = '<iframe src='{$src}' width='100%' height='100%' frameborder='0'></iframe>';           
        }
        
        /* Prepare caption */
        $caption = '';
        if(!empty($content)){
                
                $caption = wp_kses_post($content);
                $caption = '<figcaption>{$caption}</figcaption>';                               
        }
        
        /* Final markup */      
        $out = '<figure class='frl-embed'>';
        $out .= '<div class='embed-frame {$source}'>{$embed}</div>';
        $out .= $caption;
        $out .= '</figure>';

        return $out;
}

First, we register the shortcode itself - frl_embed - assuming that the caption content could be placed between open and close shortcode tags. We extract two parameters mentioned above and test them for being accurate (you can create additional tests for URL validity if you are expecting a significant probability of incorrect user inputs).

After that we construct the embed markup in accordance with Google Docs Viewer requirements, caption markup and combine them inside the single figure container. Pay attention to the additional element we created – the div with "embed-frame" CSS class. This div is required by the 'responsive iframe' technique into work. The CSS with some minimal styling should look as following:

.embed-frame {
    width: 100%;
    height: 0;    
    position: relative; }

.embed-frame.gdocs {
    border: 1px solid #ededed;
    padding-bottom: 140%; }

.embed-frame iframe {
    border: none;
    position: absolute;
    width: 100%;
    height: 100%; }
    
.frl-embed {
    width: 100%;
    margin: 2em 0;
    max-width: 800px; }
    
.frl-embed figcaption {
    padding: 0.5em 1.5em;
    color: #666;
    background: #fafafa;
    border: 1px solid #f1f1f1;
    margin: 0.5em 0 0; }

The snippet could be copied directly into your theme's stylesheet or included as a separate file using thewp_enqueue_style.

For example, we are going to embed an infographic as a PDF file. To achieve this we have to upload it first into the media library (or somewhere else on the web) and build the following shortcode inside the post edit area:

[frl_embed source='gdocs' src='https://dl.dropbox.com/u/2580367/PDFInfographic.pdf']
The infographic about the PDF popularity[/frl_embed]

The final result is the responsive area with scrollable PDF and custom caption directly in the post's content.

Responsive Area with Caption

Embed external images

WordPress allows us to insert images not only from the media library but from external sources. The core creates only an image tag that is not enough in most cases to make the image responsive and style it properly. If you are going to create a caption for such image it also should be done manually.

To avoid all this mess and make external images play similar to native ones we will make our shortcode to support them. We only have to add one more parameter to the shortcode's attributes for taking care of the alt text:

add_shortcode('frl_embed', 'frl_embed_screen');

function frl_embed_screen($attrs, $content = '') {
        
        $out = '';
        extract(shortcode_atts(array('source' => '', 'src' => '', 'alt' => ''), $attrs));
        
        if(empty($src))
                return $out;
        
        $valid_soursces = array('gdocs', 'image');
        
        if(!in_array($source, $valid_soursces))
                return $out;    
        
        /* Prepare embed markup */
        if($source == 'gdocs') {
                
                $src = 'http://docs.google.com/viewer?url='.rawurlencode($src).'&embedded=true';
                $embed = '<iframe src='{$src}' width='100%' height='100%' frameborder='0'></iframe>';
                
        } elseif( $source == 'image') {
                
                $src = esc_url($src);
                $alt = esc_attr($alt);
                $embed = '<img src='{$src}' />';                
        }
        
        /* Prepare caption */
        $caption = '';
        if(!empty($content)){
                
                $caption = wp_kses_post($content);
                $caption = '<figcaption>{$caption}</figcaption>';                               
        }
        
        /* Final markup */      
        $out = '<figure class='frl-embed'>';
        $out .= '<div class='embed-frame {$source}'>{$embed}</div>';
        $out .= $caption;
        $out .= '</figure>';

        return $out;
}

We also have to extend our CSS snippet to support responsive images inside the "embed-frame" container.

.embed-frame.image {
    height: auto; }

.embed-frame img {
    max-width: 100%;
    height: auto; }

In post content we can now include external images in the following way:

[frl_embed source='image' src='http://cs410227.userapi.com/v410227780/3a8/RQDxjclNpz4.jpg' alt='Incredible photo']
Incredible photo[/frl_embed]

In the front-end we finally get the responsive image with a nice caption.

Responsive Image with Caption

Embed YouTube videos

As mentioned above, WordPress supports YouTube videos through oEmbed. We are going to benefit from it by using the markup generated with the core in our shortcode.

Unfortunately, it doesn't allow the use of flexible sizes so we are going to use some artificial tricks here - generate markup with known fixed sizes and then change them into percentage values. Our extended shortcode snippet now looks like the following:

add_shortcode('frl_embed', 'frl_embed_screen');

function frl_embed_screen($attrs, $content = '') {
        
        $out = '';
        extract(shortcode_atts(array('source' => '', 'src' => '', 'alt' => ''), $attrs));
        
        if(empty($src))
                return $out;
        
        $valid_soursces = array('gdocs', 'image', 'youtube');
        
        if(!in_array($source, $valid_soursces))
                return $out;    
        
        /* Prepare embed markup */
        if($source == 'gdocs') {
                
                $src = 'http://docs.google.com/viewer?url='.rawurlencode($src).'&embedded=true';
                $embed = '<iframe src='{$src}' width='100%' height='100%' frameborder='0'></iframe>';
                
        } elseif( $source == 'image') {
                
                $src = esc_url($src);
                $alt = esc_attr($alt);
                $embed = '<img src='{$src}' />';
                
        } elseif($source == 'youtube'){
                
                $embed = wp_oembed_get($src, array('width'=>100, 'height' => 75)); 
                $embed = str_replace('100', '100%', $embed);
                $embed = str_replace('75', '100%', $embed);     
        }
        
        /* Prepare caption */
        $caption = '';
        if(!empty($content)){
                
                $caption = wp_kses_post($content);
                $caption = '<figcaption>{$caption}</figcaption>';                               
        }
        
        /* Final markup */      
        $out = '<figure class='frl-embed'>';
        $out .= '<div class='embed-frame {$source}'>{$embed}</div>';
        $out .= $caption;
        $out .= '</figure>';

        return $out;
}

The CSS snippet also should be adjusted to support another content type with a different aspect ratio.

.embed-frame.youtube {
    padding-bottom: 65%; }

In post content we can now include YouTube videos in the following way:

[frl_embed source='youtube' src='http://www.youtube.com/watch?v=l6La38S-yI4']
The incredible video[/frl_embed]

And the final result is a responsive video with a custom caption.

Responsive Video with Caption

Embed Slideshare Presentations

Slideshare allows to embed the presentations in any site through generated code and provides the shortcode for WordPress.com blogs. In our case we'd like to make the final object responsive and be wrapped into standard markup with caption. Once again the oEmbed format is going to help us. Nevertheless, Slideshare is not included as a default oEmbed provider, the service supports the format and that's enough.

WordPress has a built-in discovery mechanism for unlisted oEmbed providers and we can rely on it without any additional movements. The only thing we are going to take care of ourselves is the replacement of fixed sizes by percentage values.

add_shortcode('frl_embed', 'frl_embed_screen');

function frl_embed_screen($attrs, $content = '') {
        
        $out = '';
        extract(shortcode_atts(array('source' => '', 'src' => '', 'alt' => ''), $attrs));
        
        if(empty($src))
                return $out;
        
        $valid_soursces = array('gdocs', 'image', 'youtube', 'slideshare');
        
        if(!in_array($source, $valid_soursces))
                return $out;    
        
        /* Prepare embed markup */
        if($source == 'gdocs') {
                
                $src = 'http://docs.google.com/viewer?url='.rawurlencode($src).'&embedded=true';
                $embed = '<iframe src='{$src}' width='100%' height='100%' frameborder='0'></iframe>';
                
        } elseif( $source == 'image') {
                
                $src = esc_url($src);
                $alt = esc_attr($alt);
                $embed = '<img src='{$src}' />';
                
        } elseif($source == 'youtube'){
                
                $embed = wp_oembed_get($src, array('width'=>100, 'height' => 75)); 
                $embed = str_replace('100', '100%', $embed);
                $embed = str_replace('75', '100%', $embed);
                
        } elseif( $source == 'slideshare') {
                                
                $embed = wp_oembed_get($src, array('width'=> 100, 'height' => 75)); 
                $embed = str_replace('102', '100%', $embed);
                $embed = str_replace('76', '100%', $embed);             
        }
        
        /* Prepare caption */
        $caption = '';
        if(!empty($content)){
                
                $caption = wp_kses_post($content);
                $caption = '<figcaption>{$caption}</figcaption>';                               
        }
        
        /* Final markup */      
        $out = '<figure class='frl-embed'>';
        $out .= '<div class='embed-frame {$source}'>{$embed}</div>';
        $out .= $caption;
        $out .= '</figure>';

        return $out;
}

Once again we have to adjust the CSS snippet to support new aspect ratio. The whole code now looks as follows:

.embed-frame {
    width: 100%;
    height: 0;    
    position: relative; }

.embed-frame.gdocs {
    border: 1px solid #ededed;
    padding-bottom: 140%; }

.embed-frame.image {
    height: auto; }
    
.embed-frame.youtube {
    padding-bottom: 65%; }

.embed-frame.slideshare {
    padding-bottom: 80%;
    border: 1px solid #ccc;
    border-bottom: none;}

.embed-frame iframe {
    border: none;
    position: absolute;
    width: 100%;
    height: 100%; }

.embed-frame img {
    max-width: 100%;
    height: auto; }  

.frl-embed {
    width: 100%;
    margin: 2em 0;
    max-width: 800px; }
    
.frl-embed figcaption {
    padding: 0.5em 1.5em;
    color: #666;
    background: #fafafa;
    border: 1px solid #f1f1f1;
    margin: 0.5em 0 0; }

The in-post shortcode for Slideshare presentation is nearly the same and includes the URL of slides, that could be copied from the browser address bar.

[frl_embed source='slideshare' src='http://www.slideshare.net/photomatt/wordpress-state-of-the-word-2012']
WordPress State of the Word 2012 by <a href='http://www.slideshare.net/photomatt' target='_blank'>photomatt</a>[/frl_embed]

In the front-end we have a responsive presentation with a custom caption.

Responsive Presentation with Caption

So we have demonstrated how the power of WordPress shortcodes help us to have embeddable content of different types on our site with quite simple pieces of code. You can download the whole code as a separate plug-in. The quite basic example has been presented here but you can tune it to your needs by adding more sophisticated styling or JavaScript behaviour.

Conclusion

Undoubtedly, there are plenty of plug-ins that solve similar tasks, for example, Google Doc Embedder or Smart YouTube PRO. But sometimes you just need something simple and flexible.

Our approach is all about consistency - it provides the common markup for different types of embedded objects (which is very convenient). Apart from that, it's user-friendly - there is no need to learn a bunch of different shortcodes, everything is handled through one simple line of code.

Are you going to give this approach a try or do you prefer to rely on some other methods? Let us know in the comments.