How To Create An Embeddable Content Plugin For WordPress

About The Author

Sameer Borate is a freelance web developer, working primarily in PHP and MySQL. He blogs about his various interests and web topics at www.codediesel.com. When … More about Sameer ↬

Email Newsletter

Weekly tips on front-end & UX.
Trusted by 200,000+ folks.

WordPress is one of the most deployed content management systems around. One of the main reasons is the number of plugins available and the ease with which we can use the system. It is not uncommon to find websites using tens of plugins to accomplish various tasks and functions. Wouldn’t it be nice if you could share your site content with other websites?

You may have a need to share advertisements, product information or, if you are a designer, your photo gallery. Whatever the reason, this article will show you a way to create an embeddable content plugin to share your WordPress content with other websites.

There are various ways with which one can share content across websites: RSS and Atom feeds, APIs and embeddable widgets. RSS feeds on WordPress are usually restricted to posts, while APIs are not easy to integrate on other websites without adding some extra code. This leaves us with embeddable widgets, like the ones used by Google AdSense to display advertisements on websites or Facebook “Share” and “Like” buttons — all of these rely on embeddable JavaScript code to display specific content on a website.

The idea mentioned in this article is certainly not new, but in the context of WordPress it opens up many possibilities. The advantages of the technique mentioned here compared with others is that it will enable you to share almost any content, even content from other plugins on your blog, with other websites.

Our goal in this article is to create widget code that a user could insert in their website to display a list of recent posts from the parent website. Of course, this can also be easily accomplished using RSS, but this is just an example to show the technique. In reality, you would use it for more interesting purposes, like sharing popular product images if you are running a WordPress e-commerce website.

The Widget Code

The embeddable code will look something like the following. This is the code the user will insert into their webpage, which will allow them to display the content from the parent website. The crucial element of this widget is the wp-widget.js file, which calls the remote WordPress website, gets the content and embeds it as an iframe in the calling page.

<script type="text/javascript">
  var widget_embed = 'posts';
</script>
<script src="https://www.example.com/widget/wp-widget.js"
type="text/javascript">
</script>
<div id="embed-widget-container"></div>

Adding this block of code to any website page will display the list of recent posts from example.com. The content can be anything besides posts — images, comments, tags, data from other plugins — anything you as a WordPress website owner would like to share with other people. For this example, I’ve limited the content to a simple posts list, as this is a common denominator across all WordPress websites and will be easy to start with. Of course, you will need to add some extra code to share other content, but the base plugin skeleton will remain the same.

Creating The Plugin

The fist step in creating an embeddable widget is to design a small WordPress plugin that will intercept the widget calls from another website and return the required data. You may be thinking that this will be a knotty job, but nothing could be easier. Just a few lines of code and our plugin is ready. The complete code for the plugin is shown below. I’ll explain how this works as we proceed along.

To get the content from the plugin, we will need to pass a query parameter of what content we would like from the remote server in the em_embed variable. This query parameter will then be intercepted by the plugin and the corresponding content returned. We will also pass along implicitly the domain URL of the calling page, so we can later use it for analytics purposes or for restricting the websites which can embed our widget.

For example, to get the list of recent posts, we need to send a GET query to the main WordPress website as shown below. Of course this query will be created by our JavaScript widget, wp-widget.js.

https://www.example.com/?em_embed=posts

The complete code for the plugin is given below.

<?php

/**
 * Plugin Name: WordPress Widget Embed
 * Description: Allow people to embed WordPress content in an iframe on other websites
 * Version: 1.0
 * Author: Sameer Borate
 * Author URI: https://www.codediesel.com
 */

class WPWidgetEmbed  
{
    public function __construct()
    {
        add_action('template_redirect', array($this, 'catch_widget_query'));
        add_action('init', array($this, 'widget_add_vars'));
    }

    /**
     * Adds our widget query variable to WordPress $vars
     */
    public function widget_add_vars() 
    { 
        global $wp; 
        $wp->add_query_var('em_embed'); 
        $wp->add_query_var('em_domain'); 
    }

    private function export_posts()
    {
        $outstring  = '<html>';
        $outstring .= '<head><style>';
        $outstring .= 'ul {
                padding:0;
                margin:0;
              }
              li {
                 list-style-type:none;
               }';
        $outstring .= '</style></head><body>';

        /* Here we get recent posts for the blog */
        $args = array(
            'numberposts' => 6,
            'offset' => 0,
            'category' => 0,
            'orderby' => 'post_date',
            'order' => 'DESC',
            'post_type' => 'post',
            'post_status' => 'publish',
            'suppress_filters' => true
        );

        $recent_posts = wp_get_recent_posts($args);

        $outstring .= '<div class="widget-posts"><ul>';
        foreach($recent_posts as $recent)
        {
            $outstring .= '<li><a target="_blank" href="' . get_permalink($recent["ID"]) . '">' . $recent["post_title"]. '</a></li>';
        }

        $outstring .= '</ul></div>';
        $outstring .= '</body></html>';

        return $outstring;
    }

    /**
     * Catches our query variable. If it’s there, we’ll stop the
     * rest of WordPress from loading and do our thing, whatever 
     * that may be.

     */
    public function catch_widget_query()
    {
        /* If no 'embed' parameter found, return */
        if(!get_query_var('em_embed')) return;

        /* 'embed' variable is set, export any content you like */

        if(get_query_var('em_embed') == 'posts')
        { 
            $data_to_embed = $this->export_posts();
            echo $data_to_embed;
        }

        exit();
    }
}

$widget = new WPWidgetEmbed();

?>

To successfully intercept calls from another website, we need to first add the em_embed and em_domain parameters to our WordPress query_var variable. This will be used later to see what kind of data needs to be sent to the remote website. This is done by the following function.

public function widget_add_vars() 
{ 
    global $wp; 
    $wp->add_query_var('em_embed'); 
    $wp->add_query_var('em_domain');
}

Next, we will need to catch the query variable on the template_redirect hook and process any data if the em_embed variable is set in the global variable.

public function catch_widget_query()
{
    /* If no 'embed' parameter found, return */
    if(!get_query_var('em_embed')) return;

    /* 'embed' variable is set, export any content you like */

    if(get_query_var('em_embed') == 'posts')
    { 
        $data_to_embed = $this->export_posts();
        echo $data_to_embed;
    }

    exit();
}

In our example, we will be exporting a list of recent post titles, so our export_posts function will look like below.

private function export_posts()
{
    $outstring  = '<html>';
    $outstring .= '<head><style>';
    $outstring .= 'ul {
             padding-left:10px;
             margin:0;
          }

          li > a {
             text-decoration: none;
             font-family: Arial, Helvetica, Sans-serif;
             font-size:12px;

          }

          li {
             border-bottom: 1px solid #c0c0c0;
             padding: 3px 0 3px 0;
          }

          .widget-posts {
             width: 250px;
             border: 1px solid #c0c0c0;
             padding: 12px;
             margin-left: 3px;
          }';
    $outstring .= '</style></head><body>';

    /* Here we get recent posts for the blog */
    $args = array(
        'numberposts' => 6,
        'offset' => 0,
        'category' => 0,
        'orderby' => 'post_date',
        'order' => 'DESC',
        'post_type' => 'post',
        'post_status' => 'publish',
        'suppress_filters' => true
    );

    $recent_posts = wp_get_recent_posts($args);

    $outstring .= '<div id="widget-posts"><ul>';
    foreach($recent_posts as $recent)
    {
        $outstring .= '<li><a target="_blank" href="' . get_permalink($recent["ID"]) . '">' . $recent["post_title"]. '</a></li>';
    }

    $outstring .= '</ul></div>';
    $outstring .= '</body></html>';

    return $outstring;
}

This is all there is to the plugin. If you need to export any other data, you will need to replace the code for getting posts with code for getting the data you like.

Writing The Embeddable Widget Code

We have now completed only the part for the WordPress plugin. We still have to write the JavaScript embed code which will remotely access our website and insert the appropriate content into the calling page. The easiest way to display content from another website into your Web page is by using an iframe. The code needed to embed the content on a website is shown below.

<script type="text/javascript">
  var widget_embed = 'posts';
</script>
<script src="https://www.example.com/widget/wp-widget.js"
type="text/javascript">
</script>
<div id="embed-widget-container"></div>

If you are going to use the widget for returning only a single type of data,you can do away with the widget_embed variable. So you will have something like the following.

<script src="https://www.example.com/widget/wp-widget.js"
type="text/javascript">
</script>
<div id="embed-widget-container"></div>

wp-widget.js is the JavaScript that does all the work of calling the remote WordPress website and adding the content to the iframe. You need to place the wp-widget.js file in a subdirectory on your WordPress website; the exact name and location does not matter.

The complete code for the wp-widget.js is shown below, and is self-explanatory.

/**
  * wp-widget.js
  *
  * Inserts an iframe into the DOM and calls the remote embed plugin
  * via a get parameter:
  * e.g https://www.example.com/?embed=posts
  * This is intercepted by the remote 'WordPress Widget Embed' plugin
  *
  */

(function() {

// Localize jQuery variable
var jQuery;

/* Load jQuery if not present */
if (window.jQuery === undefined || window.jQuery.fn.jquery !== '1.7.2') 
{
    var script_tag = document.createElement('script');
    script_tag.setAttribute("type","text/javascript");
    script_tag.setAttribute("src",
        "https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js");
    if (script_tag.readyState) 
    {
      script_tag.onreadystatechange = function () 
      { // For old versions of IE
          if (this.readyState == 'complete' || this.readyState == 'loaded') 
          {
              scriptLoadHandler();
          }
      };
    } 
    else 
    {
      script_tag.onload = scriptLoadHandler;
    }

    (document.getElementsByTagName("head")[0] || document.documentElement).appendChild(script_tag);
} 
else 
{
    // The jQuery version on the window is the one we want to use
    jQuery = window.jQuery;
    main();
}

/* Called once jQuery has loaded */
function scriptLoadHandler() 
{
    jQuery = window.jQuery.noConflict(true);
    main(); 
}

/* Our Start function */
function main() 
{ 
    jQuery(document).ready(function($) 
    { 
        /* Get 'embed' parameter from the query */
        var widget = window.widget_embed;
        var domain = encodeURIComponent(window.document.location);

        /* Set 'height' and 'width' according to the content type */
        var iframeContent = '<iframe style="overflow-y: hidden;" 
                             height="550" width="400" frameborder="0" 
                             border="0" cellspacing="0" scrolling="no" 
                             src="https://www.example.com/?em_embed=' + widget + '&em_domain=' + domain + '"></iframe>';

        $("#embed-widget-container").html(iframeContent);
    });
}

})();

The task of inserting the iframe and the WordPress content in the DOM is accomplished by the main() function. The iframe size needs to be changed depending on your requirements or created dynamically by letting the user pass additional parameters along with the widget_embed variable in the main widget code.

Adding Custom CSS To The Content

You can also add custom CSS to the displayed content through the plugin. Sample CSS to go with the above plugin is given below. You can also specify a style sheet URL if needed.

private function export_posts()
{
    $outstring  = '<html>';
    $outstring .= '<head><style>';
    $outstring .= 'ul {
             padding-left:10px;
             margin:0;
          }

          li > a {
             text-decoration: none;
             font-family: Arial, Helvetica, Sans-serif;
             font-size:12px;
          }

          li {
             border-bottom: 1px solid #c0c0c0;
             padding: 3px 0 3px 0;
          }

          .widget-posts {
             width: 250px;
             border: 1px solid #c0c0c0;
             padding: 12px;
             margin-left: 3px;
          }';
    $outstring .= '</style></head><body>';
    .
    .

The type of CSS you add to the content will depend on what content you are displaying. With a little creative coding, you can also allow the user to add certain display options to the widget with which they can control the display style of the embedded widget.

Restricting Display To Certain Domains

You may want to allow only certain domains to be able to display your content using the widget. This can easily be made possible, as we already have the calling website’s url in the em_domain variable. All we have to do is check the domain and selectively allow the content to be displayed.

public function catch_widget_query()
{
    /* If no 'embed' parameter found, return */
    if(!get_query_var('em_embed')) return;

    /* 'embed' variable is set, export any content you like */

    if(get_query_var('em_embed') == 'posts')
    { 
        $allowed_domains = array('site1.com',
                                 'site2.com',
                                 'site3.com');

        $calling_host = parse_url(get_query_var('em_domain'));

        /* Check if the calling domain is in the allowed domains list */
        if(in_array($calling_host['host'], $allowed_domains))
        {
            $data_to_embed = $this->export_posts();
            echo $data_to_embed;
        }
        else
        {
            echo "Domain not registered!";
        }
    }

    exit();
}

Performance Concerns

Allowing other websites to access your content via widgets means additional load on your servers. A few hundred websites using your widget could easily slow down your server, so take this factor into consideration when promoting widgets. However, plugins like WP Super Cache can be used to cache widget data and reduce server load. If you are not using WP Super Cache or any other cache plugin, you can try using the WordPress Transients API to save the results into the database.

The WordPress Transients API offers a simple and standardized way of storing cached data in the database temporarily by giving it a custom name and a time frame, after which it will expire and be deleted. The catch_widget_query() function after adding the WP Transient API code is shown below.

public function catch_widget_query()
{
    /* If no 'embed' parameter found, return */
    if(!get_query_var('em_embed')) return;

    /* 'embed' variable is set, export any content you like */

    if(get_query_var('em_embed') == 'posts')
    { 
        /* Here we are now using the 'WP Transient API'.

           See if we have any saved data for the 'ewidget' key.
         */
        $cached = get_transient('ewidget');

        /* Oops!, the cache is empty */
        if(empty($cached))
        {
            /* Get some fresh data */
            $data_to_embed = $this->export_posts();

            /* Save it using the 'WP Transient API' using the 'ewidget' key,
               set it to expire after 12 hours.
             */
            set_transient('ewidget', $data_to_embed, 60 * 60 * 12);
            echo $data_to_embed;
        }
        /* Yes we found some, so we return that to the user */
        else
        {
            echo $cached;
        }
    }

    exit();
}

In Conclusion

Sharing your content across different websites is a nice way to market your services and create brand awareness. With millions of WordPress websites around, there is a huge amount of content out there that can be profitably shared among users. Not just text, but also images, videos, advertisements, etc. This article is just a simple implementation of an embeddable widget. You can customize it in various ways to include security, analytics code to track widget usage and other functionality.

Further Reading

Smashing Editorial (cp, il, mrn)