Zero to Mojolicious, Part 3: Using External Content from WP-API

Tags:

Last time, we created a site_design template for Mojolicious which built on a basic layout template for Zurb Foundation. On top of this we can use our content-specific templates, with the two lower templates nested below.

Here's an example that uses content from a WordPress™ Post. The simplest way to retrieve the actual content of just a post from WordPress is to use the rather new WP-API. This was to be part of WP core in their version 4.1, and although its appearance in core has been delayed, can be installed as the "WP REST API" plugin from the WP repository.

Once the WP-API plugin is enabled, we can request a URI like one on this site as:

http://blog.wlindley.com/wp-json/wp/posts/1265

That will return a JSON result with the rendered HTML (WordPress stores post and page content in the database with newline breaks instead of paragraph tags, and an assortment of other changes we do not want to deal with here) as well as a variety of metadata about the post. Unfortunately the current WP-API plugin does not let us request by post name, only by internal ID. One hopes the API will be more complete when it is fully released. Also beware the URI and request schema may differ in a final release.

We can use Mojo::UserAgent to retrieve the remote content and parse its JSON.

In a new file lib/MyApp/Controller/ then we add a controller. We use the rendered HTML versions for the content, title, and excerpt, while copying the other values with unmodified keys all to the stash, which we can then reference in our template. The two templates notfound and nopage (not shown here) are used when things go wrong.

package MyApp::Controller::Blogpage;
use Mojo::Base 'Mojolicious::Controller';

use Data::Dumper;
use Mojo::UserAgent;

# This action will render a template
sub retrieve {
  my $self = shift;

  my $ua = Mojo::UserAgent->new;

  my $id = $self->param('id');

  if (defined $id) {
      $id =~ s/\D//g; # remove all non-digits
  }
  if (!$id) {
      $self->redirect_to('notfound');
      return;
  }

  my $tx = $ua->get("http://blog.wlindley.com/wp-json/wp/posts/${id}");

  if ($tx->success) {
      my $value = $tx->res->json;

      # Render template "blogpage/retrieve.html.ep" with
      # values from WP-API
      $self->render((map { $_ => $value->{$_}->{rendered} }
                           qw/content title excerpt/) ,
                    (map { my $vname = $_;
                           $vname =~ s/^format\Z/wp_format/;
                           $vname => $value->{$_} }
                           qw/date type format comment_status id modified
                                ping_status featured_image author sticky
                                excerpt slug guid link/) );
  } else {
      $self->redirect_to('nopage');
  }  
}

1;

and create a template in templates/blogpage/retrieve.html.ep. Note how we are using the site_layout template from last time:

% layout 'site_layout';
% title "$title";
<h1><%= $title =%></h1>

<blockquote>Published on <%= $date %></blockquote>
%== $content

Of course you can use any of the metadata tags which we copy in the controller (featured_image might be an interesting one).

Then in our MyApp.pm we add this into the startup subroutine:

$r->get('/blog')->to('blogpage#retrieve');

Now we can visit http://localhost:3000/blog?id=1265 and you should see the content of the WordPress post, dropped into the content section that you made in the Foundation style theme from last time.

Next time, we still plan to access a database.