PDF Portfolio

Our client, Camels & Chocolate, writes for a lot for various magazines and other publications. The challenge was to make a simple portfolio that could showcase some of the articles. The problem is that the publications are PDFs and we wanted it to be as simple to use as possible.

We started with a Custom Post Type for portfolio.

$args = array(
	'labels'          => $labels,
	'description'     => __( 'Portfolio', 'camelsandchocolate' ),
	'has_archive'     => true,
	'public'          => true,
	'supports'        => array(
		'thumbnail',
		'title',
	),
	'menu_icon'       => plugins_url( 'portmenu.png', __FILE__ ),
);
register_post_type( 'portfolio', $args );

Because our post type doesn’t support the editor but we need to handle uploads, we need to add the media buttons to the edit post page in admin. As a note, all this code is coming from a class and the add_action()/add_filter() calls are in __construct().

public function edit_form_advanced() {
	if ( 'portfolio' ==  get_post_type() ) {
		if ( !function_exists('media_buttons') )
			include(ABSPATH . 'wp-admin/includes/media.php');

		echo '<div id="wp-portfolio-media-buttons" class="hide-if-no-js wp-media-buttons">';
		do_action( 'media_buttons', 'portfolio' );
		echo "</div>\n<br />\n";
	}
}
add_action( 'edit_form_advanced', array( $this, 'edit_form_advanced' ) );

Now came the more difficult part. When the client uploaded a PDF we wanted to generate an image from the first page of the PDF and use that as the post thumbnail. To start we need to store the location of the PDF that was just uploaded because unfortunately it’s not available in the wp_generate_attachment_metadata action where we do the actual processing.

/**
 * If this is a PDF, store the file location
 */
public function wp_handle_upload( $data, $type ) {
	if ( 'application/pdf' == $data['type'] )
		$this->_file = $data['file'];
	return $data;
}
add_action( 'wp_handle_upload', array( $this, 'wp_handle_upload' ), null, 2 );

Now that we have the location we can hook into wp_generate_attachment_metadata and perform the actual magic.

/**
 * Generate a thumbnail for PDFs
 */
public function wp_generate_attachment_metadata( $metadata, $attachment_id ) {
	$attachment = get_post( $attachment_id );
	if ( 'portfolio' == get_post_type( $attachment->post_parent ) && $this->_file ) {
		// read page 1
		$this->_im = new imagick( $this->_file.'[0]' );
		$jpg_name = preg_replace( '|\..*$|', '.jpg', $this->_file );
		unset( $this->_file );

		// convert to jpg
		$this->_im->setCompression(Imagick::COMPRESSION_JPEG);
		$this->_im->setCompressionQuality(60);
		$this->_im->setImageFormat('jpeg');

		//write image on server
		$image = wp_tempnam( wp_get_attachment_url( $attachment_id ) );
		$this->_im->writeImage( $image );
		$this->_im->clear();
		$this->_im->destroy();

		// Set variables for storage
		// fix file filename for query strings
		preg_match('/[^\?]+\.(jpg)/', $jpg_name, $matches);
		$file_array['name'] = basename($matches[0]);
		$file_array['tmp_name'] = $image;

		// do the validation and storage stuff
		$image_id = media_handle_sideload( $file_array, $attachment->post_parent );
		set_post_thumbnail( $attachment->post_parent, $image_id );
	}
	return $metadata;
}
add_action( 'wp_generate_attachment_metadata', array( $this, 'wp_generate_attachment_metadata' ), null, 2 );

Basically we pull the first page of the PDF, convert it to an image, sideload it to WordPress, and set it as the featured image of the portfolio item. Since the theme handles all the display using the featured image, everything just works. To the user it’s magic! Upload a PDF and “poof” you have a portfolio item with a thumbnail. No Photoshop required (but it does require ImageMagick on your server). Just a beautiful portfolio.

Leave a Reply

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