Create A WordPress Bookshelf Plugin

Advertisement

This tutorial explains how to create a WordPress bookshelf plugin that displays books on a shelf like Smashing Magazine’s eBook page. Some key WordPress functionality will be showcased throughout the tutorial that could benefit your own project.

The article covers how to create post types, shortcodes and meta fields using WordPress’ functionality and how to combine them to make a fully configurable plugin. To begin, we’ll explain how to register the plugin, develop the back-end functionality and then create the front-end display using shortcodes.

Setting Up The Plugin

The standard method of registering a plugin in WordPress is to add some information to the header of the file. Create a file named sm_books.php, and add the information below to it. Note that the information being registered is “Plugin Name,” “Author,” “Version,” etc. This information will be used to tell WordPress about the plugin so that the plugin can be activated and displayed in the plugin management screen.

<?php 
/*
Plugin Name: SM Books
Plugin URI: http://b4ucode.com
Description: Displays Books and books
Author: B4uCode
Version: 1.0.0
Author URI: http://b4ucode.com
*/

Book Plugin

To learn more about creating a plugin, check out “WordPress Essentials: How to Create a WordPress Plugin.”

Register The Post’s Type

In order to add the new book system, we will register a new custom post type using the register_post_type function. To access this function, we will trigger it using the add_action function. Add the following to the sm_books.php file:

//Register Book Post Type 
add_action( 'init', 'create_sm_book_type' );
function create_sm_book_type() {
   register_post_type( 'sm_books',
      array(
         'labels' => array(
            'name' => __( 'Books' ),
            'singular_name' => __( 'Book' )
         ),
      'public' => true,
      'has_archive' => true,
      'supports' => array('title','editor','thumbnail')
      )
   );
}

This snippet is a basic way to create a post type. The register_post_type( $post_type, $args ) function takes two parameters: $post_type and $args. The first parameter is a 20-character string that will be used for the name of the new type. The default post types in WordPress are “Post,” “Page,” “Attachment,” “Revisions” and “Navigation Menus.” These default names cannot be used when creating a custom type, so we will use sm_books. The second parameter is an optional array that stores a multitude of options for the post type. The array accepts “labels” that will be used and seen while using sm_books, as well as options available for the post type, such as exclude_from_search, show_ui and much more.

Add Books Category

For this tutorial, we will add a custom set of categories for the books. This set is referred to as a “taxonomy,” and we will create it with the register_taxonomy function, which we will call sm_book_category. The categories enable us to assign our entries to different categories for displaying on the screen. Just as with our previous snippet in the file, we will use add_action to trigger our function. Also, register_taxonomy($taxonomy, $object_type, $args) is very similar to the register_post_type function, with its three parameters:

  1. $taxonomy
    A string with no capital letters or spaces.
  2. $object_type
    Defines the post type that this new taxonomy will be attached to.
  3. $args
    An optional array that holds options and labels similar to what we see in the register_post_type function.
//Add Book Categories
add_action( 'init', 'sm_book_taxonomies', 0 );
function sm_book_taxonomies(){
   register_taxonomy('sm_book_category', 'sm_books', array(
      'hierarchical'=>true,
      'label'=>'Categories'
      )
   );
}

Add Meta Fields

Meta Data Fields

As you may have noticed, each book has different attributes, consisting of prices and links. We will add these attributes as custom meta data fields using the add_meta_boxes action in WordPress. At the moment, we will also add the save_post action to save these fields. Once we’ve triggered our function, the add_meta_box( $id, $title, $callback, $post_type, $context, $priority, $callback_args ) function will establish the “ID,” “Name” and “Description” of the meta box area. The other $post_type parameter determines what post types the meta box should appear in; and for the $callback, we will use the sm_bk_info_box function, which will render the HTML output of form fields.

add_action( 'add_meta_boxes', 'sm_book_extra_box' );
add_action( 'save_post', 'sm_books_save_postdata' );

function sm_book_extra_box() {
   add_meta_box(
      'sm_bk_info_box',
      __( 'Book Information', 'sm_bk_info_box' ), 
      'sm_bk_info_box',
      'sm_books',
      'side'
   );
}

/* Prints the box content */
function sm_bk_info_box( $post ) {

   $price = get_post_meta( $post->ID, 'price', true );
   $sale_price =  get_post_meta( $post->ID, 'sale_price', true );
   $link_amazon =  get_post_meta( $post->ID, 'link_amazon', true );
   $link_google =  get_post_meta( $post->ID, 'link_google', true );
   $link_apple =  get_post_meta( $post->ID, 'link_apple', true );

   // Use nonce for verification
   wp_nonce_field( plugin_basename( __FILE__ ), 'sm_book_noncename' );
?>

<p>
  <label for="price">Price
  <input type="text" name="price"
   id="price" size="10" value="<?php echo $price; ?>" />
  </label>
</p>
<p>
  <label for="sale_price">Sale Price
  <input type="text" name="sale_price"
   id="sale_price" size="10" value="<?php echo $sale_price; ?>" />
  </label>
</p>
<p>
  <label for="link_amazon">Amazon Link
  <input type="text" name="link_amazon"
   id="link_amazon" size="25" value="<?php echo $link_amazon; ?>" />
  </label>
</p>
<p>
  <label for="link_google">Google Link
  <input type="text" name="link_google"
   id="link_google" size="25" value="<?php echo $link_google; ?>" />
  </label for="myplugin_new_field">
</p>
<p>
  <label for="link_apple">Apple Link
  <input type="text" name="link_apple"
   id="link_apple" size="25" value="<?php echo $link_apple; ?>" />
  </label>
</p>
<?php
}

To save the meta data fields that we created previously, we will create the sm_books_save_postdata function that we defined in our save_post action. Within this function, we will check for submitted post data and update the post meta data using the update_post_meta function. Add the following snippet to the sm_books.php file to give the plugin an update-able set of custom fields:

function sm_books_save_postdata($post_id){
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
   return;

   if ( !wp_verify_nonce( $_POST['sm_book_noncename'],
   plugin_basename( __FILE__ ) ) )
    return;

    if ( !current_user_can( 'edit_post', $post_id ) )
    return;

    if( isset( $_POST['price'] ) ){
      update_post_meta( $post_id,'price', 
      esc_attr( $_POST['price'] ) );
   }
     if( isset( $_POST['sale_price'] ) ){
      update_post_meta( $post_id,'sale_price', 
           esc_attr( $_POST['sale_price'] ) );
   }
   if( isset( $_POST['link_amazon'] ) ){
      update_post_meta( $post_id,'link_amazon', 
           esc_attr( $_POST['link_amazon'] ) );
   }
   if( isset( $_POST['link_google'] ) ){
      update_post_meta( $post_id,'link_google', 
           esc_attr( $_POST['link_google'] ) );
   }
   if( isset( $_POST['link_apple'] ) ){
      update_post_meta( $post_id,'link_apple', 
           esc_attr( $_POST['link_apple'] ) );
   }
}

The update_post_meta takes the post’s ID as the first argument, the key to update as the second argument and the value to be saved as the third argument.

Add Featured Post

For our custom book system, we will add an option for a thumbnail, which will be used to show the book cover on our shelf. We will use the featured post’s thumbnail to accomplish this, and we’ll set the image size that we intend to use with the add_image_size function.

//Enable Thumbnail
if ( function_exists( 'add_theme_support' ) ) {
   add_theme_support( 'post-thumbnails' );
      set_post_thumbnail_size( 150, 150 );
      add_image_size( 'book-thumb', 84, 107, true );
}

The name of the thumb that we will be referencing is book-thumb, and the size that we will try to resize to is 84 × 107 pixels. These are optional, but based on what we’re going for, the numbers suit our needs.

Add Shortcode

Now that we’ve created the administrative side of the plugin, we will create the front-end design. For this tutorial, we will use a WordPress shortcode to add our book listing to the page. Our shortcode will look like the following on any page:

[sm_books category="coding"]

The shortcode above will be used to display the list of books in the category of “coding.” Note that “coding” is the slug of the custom taxonomy that we created. In the end, the plugin will be able to list all of the books if we leave out the category attribute of the shortcode.

Now, let’s move on to making the shortcode work. Add the following code to the sm_books.php file:

function sm_display($atts) {
   extract( shortcode_atts( array('category' => ''), $atts ) );
   $args = array('post_type'=>'sm_books', 'sm_book_category'=>$category);
   $posts = new WP_Query( $args );
   $html = '<div class="sm_holder"><div class="shelf"><div class="innerDiv" id="sm_book_1">';

   // Book Loop 
   if ( $posts->have_posts() ) : while ( $posts->have_posts() ) : $posts->the_post();
      $book_cover = get_the_post_thumbnail(
         get_the_ID(),'book-thumb', 
         $attr=array("alt"=>get_the_title())
      );
   $html .= '<a href="'.get_permalink().'" class="books">'.$book_cover.'</a>';
   endwhile; endif;

   $html.='</div></div><table class="sm_book_tbl" cellspacing="0" cellpadding="0">';

   // The Loop 
   if ( $posts->have_posts() ) : while ( $posts->have_posts() ) : $posts->the_post();

      $price =  get_post_meta( get_the_ID(), 'price', true );
      $sale_price = get_post_meta( get_the_ID(), 'sale_price', true );
      $link_amazon = get_post_meta( get_the_ID(), 'link_amazon', true );
      $link_google = get_post_meta( get_the_ID(), 'link_google', true );
      $link_apple = get_post_meta( get_the_ID(), 'link_apple', true );
      $html.='<tr><td class="title"><a href="'.get_permalink().'">'.get_the_title().'</a><br>';
      if ($link_amazon): 
         $html .= '<small><a style="color:#999" href="'.$link_amazon.'">Amazon</a>';
      if ($link_google || link_apple):   
         $html .=' | ';  
      endif;
      endif;
      if($link_google): 
         $html .='<a style="color:#999" href="'.$link_google.'">Google</a></small>';
      if($link_apple):    
         $html .=' | '; 
      endif;
      endif;
      if($link_apple):
         $html .='<a style="color:#999" href="'.$link_apple.'">Apple</a></small>';
      endif;
      $html .= '</td><td>'; 

      if ($sale_price && $price) { 
         $html .= $sale_price.'<br />';
         $html .= '<span class="old_price">'.$price.'</span>';
      } elseif ($price) {
         $html .= $price;
      } else {
         $html .= '';
      }
      $html .= '</td>
      <td class="cart">
         <a style="margin:0px" class="sm_cart_button" href="'.get_permalink().'">Add to Cart</a>
      </td>
      </tr>';

   endwhile; endif;

   $html .= '</table>';
   $html .= '</div>';
   return $html;
}

In the snippet above, we have created a couple of loops that will be rendered when the shortcode is entered. By instantiating the WP_Query class, we are creating a couple of loops to display the books. The arguments that we will use are post_type of sm_books; then, we will use the argument of sm_book_category, which is querying a taxonomy. The value we add will be derived from the shortcode.

The first loop renders the book’s cover in a div where the shelf image will be displayed. The second loop places a set of rows below the shelf and outputs some information about each book. The template tags are used as follows:

  • get_permalink()
    Fetches the permalink.
  • get_the_ID()
    Fetches the post’s ID, which is combined with get_post_meta to get the meta fields.
  • get_the_title()
    Fetches the title.

The final bit for the shortcode is the action that actually registers the shortcode. The first argument is the string that will be written to call the shortcode. The second is the function that will be executed. Add the following below your function:

add_shortcode( 'sm_books', 'sm_display' );

Styling Our Listing

Looking at what we have so far, you can imagine how out of place everything looks. Therefore, at this stage, we will add some CSS to style our output. Create a folder named sm_books. Then, create a file named style.css, and add the following code:

.sm_holder {
   padding: 0px;
   border-bottom: 5px solid #41B7D8;
   width: 630px;
}
div.shelf {
   background-image: url(shelf_bg.jpg);
   display: block;
}
.shelf div.innerDiv {
   padding: 0px 34px;
   width: 100%;
}
.shelf .books img {
   margin-right: 10px;
   padding-top: 15px;
   margin-bottom: 11px;
}
span.old_price {
   color: #E53B2C;
   text-decoration: line-through;
}
.sm_book_tbl {
   margin: 0px 20px 0px 0px !important;
   width: 100%;
   background-color: #f3f3f3;
   border: 1px solid #e5e5e5
}
.sm_book_tbl td.title {
   height: 60px;
   width: 70%;
   padding-left: 20px;
   padding-right: 20px;
   color: #999
}
.sm_book_tbl td.cart {
   padding: 10px 20px;
   color: #999;
}

In our style sheet, we have added a background image to our shelf div, as seen in the declaration for the div.shelf class. This image will be located in the sm_books folder. Attached to this tutorial is the source file; add the shelf_bg.jpg file to that folder.

Once completed, we will attach the style sheet to our plugin. Add the following snippet to the bottom of the sm_books.php file. Using some WordPress functions, we will register the style sheet from our folder with the WordPress system.

function sm_add_styles() {
   wp_register_style( 'sm_add_styles',
   plugins_url('sm_books/style.css', __FILE__) );
   wp_enqueue_style( 'sm_add_styles' );
}
add_action( 'wp_enqueue_scripts', 'sm_add_styles' );

Book Preview

Download the plugin

You can download the B4uCode Smashing Books plugin, which contains everything covered in this tutorial.

Conclusion

Having done this tutorial, you should be able to create a nice shelving plugin for your books. The plugin might serve your needs if you need an online book archive or library. The options aren’t limited to books either; you could create a similar system for CDs, DVDs and records, and you could tweak it to show videos. The possibilities are endless.

Resources From the WordPress Codex

(al)

↑ Back to top

Kailan Wyatt is a Web Developer that focuses on Opensource technology. With a love for WordPress and Joomla, he spends his time developing Web Applications on each platform. He has begun sharing his knowledge at B4uCOde, his venture site.

  1. 1

    Konstantin Kovshenin

    July 24, 2012 9:28 pm

    Hi Kailan, great article! Here are some comments :)

    It looks like you’re using the esc_attr function in the wrong context. The function is used to escape an HTML attribute, not sanitize or filter data before storing it to post meta — there are other functions to do that. You should use esc_attr in sm_bk_info_box, and you should also escape the output in sm_display, probably not with esc_attr, because they’re not attributes. Use esc_html for prices, because they’re in the HTML context, and esc_url for URLs because they’re .. URLs! If you choose to use esc_url outside the “output” context (like when storing in the db, or firing an HTTP call) use esc_url_raw instead.

    You can use the sanitize_text_field function when saving your post meta, however I’d rather validate with type casting and/or regular expressions, but in any case, when your user input is escaped properly during output, it’s not such a big deal anymore.

    In sm_books_save_postdata you attempt to verify a nonce in the $_POST array without checking for the key existence first, which causes an undefined index on new posts. You also use the plugin_basename as the nonce action, which is silly and confusing. Use a string and have a clear action name, like “sm_book_save_post_meta” also consider prefixing with the post id. Further down sm_books_save_postdata you’re using current_user_can with the “edit_post” capability. The registered post type can easily be mapped to other capabilities, so a user with the “edit_post” meta cap, can’t necessarily, say, “edit_book”.

    Just like with writing functions, actions and filters, you should prefix your post meta too, call them sm_book_price, and so on. You can further prefix them with an underscore to hide from the custom fields editor, if one is available for your post type.

    I downloaded the plugin file too. You published a guide to the WordPress coding standards earlier this month, yet the plugin file looks nowhere near coding standards. You’re using a whole mix of tabs and spaces, indentation is all different throughout the whole plugin file, as well as a bunch of unnecessary line breaks and spaces, that makes your code look much more confusing than it already is.

    Also, making your plugin translation-ready means loading a textdomain and actually using it. Simply wrapping (half of your) strings in a __() function won’t work (unless you’re Core).

    Thanks and have a good day!
    ~ Konstantin

    7
    • 2

      As do I, My younger sietsr is somewhere around 260 and I am terribly concerned for her health. She eats about the same amount I do, yet her weight is much more out of control. I know that some people don’t know when to push the plate away, but many people have legitimate hormonal issues that make it more difficult for them to maintain a healthy weight. I wish she would consider something, cause she seems to add another 10lbs a year. She is 25 with High blood pressure. Its worrisome.

      0
  2. 3

    Thanks for this article.

    I just started a plugin for having players bio directory and your explanations will help me a lot.

    1
  3. 4

    I was really looking forward to trying this feature and downloaded the plugin, installed it through WordPress Admin all normal, but I couldn’t get it to activate in WordPress 3.4.1 – Error message “Plugin file does not exist.” I checked the plugin directory and the folder and files are in there.

    Any advice would be welcomed?

    4
  4. 5

    Clinton Steadwell

    September 2, 2012 4:32 pm

    This is an excellent tutorial, Kailan. Apparently, somebody else thought so too and decided to repost the text and images almost verbatim without proper citation or a link back:

    http://designwebsiteblog.com/wordpress/techniques-wordpress/create-a-wordpress-bookshelf-plugin.html

    People still do this and think they can get away with it?

    0
  5. 6

    Hi, I installed the plugin on WP 3.4.2 and it said “Plugin file does not exist.”

    Any solution

    0
    • 7

      You need to extract the “b4ucode-smashing-bookshelf” folder from the .zip that you downloaded here.

      After you extract it, you need to re-zip it to a .zip (not a .rar). Winrar (free) can easily do that for you.

      Let me know if that fixed your problem. Cheers!

      1
  6. 8

    Hi Kailan,
    I’m trying out your bookshelf plugin.
    With the shortcode

    [sm_books category="xyz"]

    I always get all the books and not the category “xyz”.
    I haven’t changed anything of your plugin files. I just set up 3 categories and 3 books.
    What is the problem here?

    Greetings, Susanne

    0
    • 9

      … I just found the mistake myself. I gave in the shortcode in the visuell editor which was wrong!!! Have to use the html editor.

      0
  7. 10

    Rachel Sykes-Marut

    February 7, 2013 7:03 am

    This looks awesome! As a novice, I am afraid to go through installing it if it will not do what I am looking for. Can anyone advise me?
    I would like to have a bookshelf with clickable book icons that are really PDF files. I want to click a book and have the PDF file (1 page to 200 pages) open in a new window.
    Is this plug in what I’m looking for? If not, does this exist? Thank you in advance…

    0
  8. 11

    Your plugin is very good. I have activated it but when I entered the short code [sm_books category="coding"] or [sm_books] still there is no display.Please can you guide me as to how the categories should be added and which could should be used to display the shelf

    Thanks

    1
  9. 12

    Laurent Samuel (@association1901)

    February 25, 2013 3:04 pm

    Hi there

    Nice plugin. I was looking for such thing for a while.
    Working great by me except The “add to cart” link which gets the permalink. When I clik on it, it doesn’t lead me to the post but to an error 404. I can(t understand why because in the navigator, the URL shows properly

    Any ideas ?
    Thanks in advance

    The plugin in function is to see here : http://association1901.fr/blog/test/

    1
  10. 13

    How can I change the order in which books are displayed on the shelf?

    -1
  11. 14

    This is a really good plug in is there a way that this could be modified to allow me to have all my weekly pdf newspapers or books on a book shelf with no add to basket just to allow users to click on the free PDF paper or newsletter and it will automatically allow instant down load I offer a free pdf newsletter weekly for download to all users.

    0
  12. 15

    So I tried adding this to my site, but I don’t know how to actually make it functional. I put all the code in and added the php and css. How do I add books and make the bookshelf actually show up on a page or post on my website?

    0
  13. 16

    Nguyen Dang Khoa

    January 8, 2014 7:57 am

    Hi, thanks for your tutorial, but I got a problem:
    I actived plugin and I can add some new books, but how I can show it in a page for someone?

    0

Leave a Comment

Yay! You've decided to leave a comment. That's fantastic! Please keep in mind that comments are moderated and rel="nofollow" is in use. So, please do not use a spammy keyword or a domain as your name, or else it will be deleted. Let's have a personal and meaningful conversation instead. Thanks for dropping by!

↑ Back to top