The standard Lorem Ipsum passage, used since the 1500s

“Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.”

Section 1.10.32 of “de Finibus Bonorum et Malorum”, written by Cicero in 45 BC

“Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?”


How to use media library images as normal posts

If you want to make a portfolio website in WordPress you have to look for portfolio themes and image gallery plugins to display and categorize your portfolio images. The default WordPress themes don’t provide that functionality. Or does it?

Normal blog posts have categories and tags to sort, label and filter posts. Why not treat images as blog posts?

There are some differences and similarities:


  • A normal post and a saved image are both saved in the ‘post’ table and content is available via get_post(s).
  • Both use the same columns like: ‘post_ID’ , ‘post_title’ , ‘post_content’ , ‘post_type’, etc.


  1. Normal posts can have categories and tags, images don’t.
  2. Images are stored as attachments in ‘post’->‘post_type’ column, normal posts are stored as post in ‘post’->‘post_type’ column.
  3. Image caption is stored in column ‘post’->‘post_excerpt’, normal posts store the excerpt there.
  4. Image url is stored in column guid, normal post store the featured image in the ‘post_meta’ -> ‘meta_key’ as _thumbnail_id which links to the image attachment post.
  5. PS: Images in a normal post content are stored in the ‘post’->‘post_content’.

Make images behave like normal posts

First we add the default WordPress category and tag functionality to the media library. Add the following two code snippets to your functions.php

1. Add categories to images

 * add categories to images (post_type = attachment)
function add_categories_to_attachments() {
  register_taxonomy_for_object_type( 'category', 'attachment' );
add_action( 'init' , 'add_categories_to_attachments' );

2. Add tags to images

 * add tags to images (post_type = attachment)
function add_tags_to_attachments() {
  register_taxonomy_for_object_type( 'post_tag', 'attachment' );
add_action( 'init' , 'add_tags_to_attachments' );

3. Display images (attachments posts) between normal posts

Now we need to add the attachment posts to the get_posts() query. We will use the pre_get_posts filter.

 * Add attachments to posts query 
function include_attachments_post_types($query) {
   // Ensure you only alter your desired query
   // Make sure we don't use this in the admin section
   if ($query->is_main_query() && !is_admin()) {
      // for testing purposes
      //$query->set('post_type', 'any'); 
      // Get the current post types in the query
      $post_types = $query->get('post_type');    
      // Check that the current posts types are stored as an array
      if(!is_array($post_types) && !empty($post_types)) {  
         $post_types = explode(',', $post_types);
      // Check for empty post types
      if(empty($post_types)) {  
         // Declare array for post types
         $post_types = array();                       
         // If there are no post types defined, be sure to include posts so that they are not ignored
         // NOTE: WordPress normally adds 'post' to post_type if empty    
         $post_types[] = 'post';         
         // Add desired post type
     	 $post_types[] = 'attachment';                         
      // Trim every element, just in case
      $post_types = array_map('trim', $post_types);       
      // Remove any empty elements, just in case
      $post_types = array_filter($post_types);            
      // Add the updated list of post types to your query
      $query->set('post_type', $post_types);              
      // Add post_status inherit which is used by attachments so they are displayed
      $query->set('post_status', array('publish','inherit')); 
      return $query;
add_action( 'pre_get_posts', 'include_attachments_post_types' );

The next step is to make WordPress display images of both ‘post_type’ = post and ‘post_type’ = attachment in the same way.

  • the_post_thumbnail or get_the_post_thumbnail are used to display images in normal posts and if you dig in deeper you see that this function runs wp_get_attachment_image() and uses the _thumbnail_id from ‘post_meta’ -> ‘meta_key’.
  • wp_get_attachment_image() is also used to get the attachment post image but uses the $attachment_id which actually is the $post_id from the attachment post

There are several ways you can go to get both images with the_post_thumbnail or get_the_post_thumbnail

3. Edit post_thumbnail_html via add_filter(‘post_thumbnail_html’)

Since we can edit the html the_post_thumbnail generates before it is displayed we can make sure it also grabs the attachment image.

 * Since we treat attachment posts as normal posts we need to correct the default the_post_thumbnail function output.
 * The image for a normal post is found via the $post_thumbnail_id.
 * The image for an attachment post is found via the $post_id.
function modify_post_thumbnail_html($html, $post_id, $post_thumbnail_id, $size, $attr) {
   // The post_thumbnail $html returns empty if post_type = "attachment"
   // Check for empty $html and post_type
   if(empty($html) && 'attachment' == get_post_type($post_id)){
      // Get the image with the post_id of the attachment
      $full_image_url = wp_get_attachment_image_url($post_id, 'full');
   return $html;
add_filter('post_thumbnail_html', 'modify_post_thumbnail_html', 99, 5);

This works, but not in all scenarios. WordPress sometimes checks if a post_thumbnail exists via the function has_post_thumbnail() before running the_post_thumbnail. So we are unable to edit the post thumbnail html! We need to be earlier in the process!

4. Edit get_post_thumbnail_id() to get $post_thumbnail_id or $attachment_id

The get_post_thumbnail_id() function retrieves the _thumbnail_id from ‘post_meta’ -> ‘meta_key’. If we were able to edit this function via a filter so it would retrieve the $attachment_id in case of ‘post_type’ = attachment then solution 3 would work. Unfortunately we cannot filter that function. There is an open WordPress Core Trac Ticket with this request. You can support if if you like.

5. Add meta_key with _thumbnail_id to attachment post so the_post_thumbnail() retrieves that image

Since the attachment post that holds the image is technically a normal post, we can also give it the ‘post_meta’ -> ‘meta_key’ with _thumbnail_id and populate it with the $post_id of the attachment post.

We can hook into the image save and update process so we can add the ‘meta_key’ which holds the $post_id.

// Automatically set the the post_ID as post_thumbnail_id so post-attachment is treated as post-image
function update_attachment_image_thumbnail_id( $post_ID ) {
   // Check if uploaded file is an image and we are working with attachment posts
   if (wp_attachment_is_image($post_ID) && 'attachment' == get_post_type($post_ID)) {
      // Check if _thumbnail_id is not already populated
         // Save the post_ID as post_thumbnail_id so post-attachment is treated as post-image		
         update_post_meta( $post_ID, '_thumbnail_id', $post_ID );
add_action( 'attachment_updated', 'update_attachment_image_thumbnail_id' );
add_action( 'add_attachment', 'update_attachment_image_thumbnail_id' );

Advantages and disadvantages

There are some advantages and disadvantages to this approach. The main advantage is that the media images are treated as normal posts. You can use standard functionality to retrieve the, for example the Gutenberg Latest Posts block which can show the latest images.

There is one thing you need to make sure of: categorize all your images so you can filter them and keep them separate from normal posts.

One disadvantage is that we “pollute” the WordPress database. If there are malcoded plugins they could wrongly display images.

Leave a Reply