Shortcode Creation using the Goodreads API

In the process of creating a “Now” page for myself  I wanted to include a section for what I’m currently reading. I wanted to bring in the info I have on Goodreads dynamically (similar to the Jetpack widget) but with customizable options and the ability to drop it anywhere, not just within a sidebar. Time to create a shortcode!

Admittedly, the Goodreads API is not the best. I wouldn’t recommend it if this is your first time playing with APIs as their documentation isn’t too expansive if you’re not familiar with the process.

Typically to use an API, you’ll need a developer key. This is a unique ID that is tied to your account. It can be banned if abused so it’s important to read the terms of use. You will also want to read the documentation to make sure you can access the necessary information.

Note: I added a control to my theme customizer to store and retrieve my API key as I didn’t want it hard-coded for security reasons which is referenced below for the variable $key

Initial Setup

  1. Log into your account and get a Goodreads developer key.
  2. Figure out your user ID on Goodreads by going to your profile page and getting the number visible within the URL.
  3. Create a basic shell for your new shortcode function.

I set up my shortcode with 4 attribute defaults: the user, the shelf I want to pull books from, the number of books to list, and how I would like them sorted. I set the default user to my own ID because my use case would only be for my own books.

$attributes = shortcode_atts( array(
     'user'         => 'YOUR_USER_ID',
     'shelf'        => 'read',
     'num_of_books' => '4',
     'sort'         => 'date_read',
), $passed_values );

The $books_path variable is where we take the attributes passed to our shortcode and insert them with into a URL. It’s important that this URL formatting matches the examples given from the docs.

Comparison of XML data next to new object of data organizationally

The next part was a new venture for me. wp_remote_fopen will pull in the XML information from Goodreads. I wanted to better organize that data for ease of use so I then created a new Simple XML Element which made it a bit more pleasant.

Both of these were new to me; if you know of a more efficient way to get to the same finish line, let me know!

Now that we are returning some data, we create a foreach loop to go over the (very) nested data with $books_get_json->reviews->review.

Something else I discovered is that not all book covers are available because of copyright issues. That is what $image_url_check = $book->book->image_url; prepares for: the conditional that uses different markup in those scenarios.

Final Shortcode Snippet

function goodreads_api( $passed_values ) {

     // If API value doesn't exist within customizer, forget about it.
     if ( ! get_theme_mod( 'gr_api_key' ) ) {
          return false;
     }

     $key = get_theme_mod( 'gr_api_key' );

     $attributes = shortcode_atts( array(
          'user'         => 'YOUR_USER_ID',
          'shelf'        => 'read',
          'num_of_books' => '4',
          'sort'         => 'date_read',
     ), $passed_values );

     $books_path = 'http://www.goodreads.com/review/list/' . $attributes['user'] . '.xml?key=' . $key . '&v=2&shelf=' . $attributes['shelf'] . '&sort=' . $attributes['sort'] . '&order=d&page=1&per_page=' . $attributes['num_of_books'];

     $books_get_xml = wp_remote_fopen( $books_path );
     $books_get_json = new SimpleXMLElement( $books_get_xml );

     foreach ( $books_get_json->reviews->review as $book ) {
          $image_url_check = $book->book->image_url;

          if ( 0 === strpos( $image_url_check, 'http://s.gr-assets.com/assets/nophoto' ) ) {
               $imagecover = '<div class="temp-cover"><h4 class="title">' . $book->book->title . '</h4>';
          } else {
               $imagecover = 'book->image_url . '"/ alt="' . $book->book->title . '">';
          }

     $value .= '<li class="bookshelf-book">';

     foreach ( $book->shelves->children() as $bookshelf ) {
          $value .= 'category-' . $bookshelf['name'] . ' ';
     }
          $value .= '">' . $imagecover . '';
     }
          $value .= '</ul>';

return $value;

} add_shortcode( 'gr-books', 'goodreads_api' );

Shortcode Usage:

[ gr-books user="USER-ID" shelf="DESIRED SHELF" num_of_books="HOW MANY BOOKS" sort="DESIRED SHELF ORDER" ]

And, depending on your CSS, the result might look a little something like:

  • Call Me By Your Name (Call Me By Your Name, #1)
  • The Girl in the Woods (Waterman and Stark, #1)
  • Red, White & Royal Blue
  • A Room Swept White (Spilling CID, #5)
Additional Resources

Leave a Reply

Your email address will not be published. Required fields are marked *