Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Add custom fields to Display Posts Shortcode
<?php
/**
* Add custom fields to Display Posts Shortcode
* @author Bill Erickson
* @link http://wordpress.org/extend/plugins/display-posts-shortcode/
* @link http://www.billerickson.net/shortcode-to-display-posts/comment-page-1/#comment-4565
*
* @param $output string, the original markup for an individual post
* @param $atts array, all the attributes passed to the shortcode
* @param $image string, the image part of the output
* @param $title string, the title part of the output
* @param $date string, the date part of the output
* @param $excerpt string, the excerpt part of the output
* @return $output string, the modified markup for an individual post
*/
add_filter( 'display_posts_shortcode_output', 'be_display_posts_custom_fields', 10, 6 );
function be_display_posts_custom_fields( $output, $atts, $image, $title, $date, $excerpt ) {
// Get our custom fields
global $post;
$location = esc_attr( get_post_meta( $post->ID, 'location', true ) );
$type = esc_attr( get_post_meta( $post->ID, 'type', true ) );
$price = esc_attr( get_post_meta( $post->ID, 'price', true ) );
// If there's a value for the custom field, let's wrap them with <span>'s so you can control them with CSS
if( isset( $location ) ) $location = '<span class="location">' . $location . '</span> ';
if( isset( $type ) ) $type = '<span class="type">' . $type . '</span> ';
if( isset( $price ) ) $price = '<span class="price">' . $price . '</span> ';
// Now let's rebuild the output.
$output = '<li>' . $image . $title . $location . $type . $price . $date . $excerpt . '</li>';
// Finally we'll return the modified output
return $output;
}
@replaid

This comment has been minimized.

Copy link

@replaid replaid commented Jun 12, 2014

Here's info on how to make this conditional on shortcode attributes: http://wordpress.org/support/topic/plugin-display-posts-shortcode-custom-fields-clarification

@RonR-WebDesign

This comment has been minimized.

Copy link

@RonR-WebDesign RonR-WebDesign commented Mar 26, 2016

Just found this and have a question. Is this replacing or adding to the actual shortcode? Here I see $title - do I then not have title in the shortcode?

@ReddyRedisson

This comment has been minimized.

Copy link

@ReddyRedisson ReddyRedisson commented Jan 27, 2017

Good day! Maybe you can help me. I did everything as written above, but one of my fields - is the picture and plugin displays html code instead of images.

@wisebydesign

This comment has been minimized.

Copy link

@wisebydesign wisebydesign commented Feb 10, 2017

Hey Reddy, this is what you need to get the featured image of a post type: get_the_post_thumbnail( get_the_ID(), large )
In this example, I display a logo (set as featured image) as an image link, and make it click through to a partner website. This uses a custom post type in which I have a set featured image and a custom field made by ACF (advanced custom fields) for the website. This particular snippet is NOT on the functions page, but on my custom post type file "single-partners.php"
if ( has_post_thumbnail() ){ echo '<a class="partnerlogo" href="' . get_field('partner_website') . '">' . get_the_post_thumbnail( get_the_ID(), large ) . '</a>'; }
The "if has post thumbnail" function means if there is no image set, it won't display (broken info).

  1. The echo '<a class="partnerlogo" href="' is printing the beginning of the a link in html ,
  2. Then the get_field('partner_website') gets the ACF custom field called partner_website, where the user has inputted a url,
  3. then '">' closes the beginning of the tag. When you echo '', anything between the '' is printed as html.
  4. Then the get_the_post_thumbnail( get_the_ID(), large ) gets the featured image and the large sets the size. you can also use thumbnail or medium etc.
  5. The ''; closes the entire a tag. Don't forget your ; at the end of your line, otherwise it breaks the page.
  6. The } closes the function.

If the image is set via an ACF custom field, not as a featured image, you need to create the custom image field in ACF, then in its settings, choose a return value of either array, ID or URL then use ACF advice to determine how to display it: https://www.advancedcustomfields.com/resources/image/

good luck. :O)

@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Sep 18, 2020

This is perfect and with modifications does exactly what I need, thank you. Well, almost. It's rendering out my WYSIWYG fields with visible HTML code and not converting it. Not sure how to get around that.

@billerickson

This comment has been minimized.

Copy link
Owner Author

@billerickson billerickson commented Sep 18, 2020

The esc_attr() function is "Escape Attributes", so it is converting the HTML in your field to escaped entities. If you remove that, you should be good.

For instance, change this: $location = esc_attr( get_post_meta( $post->ID, 'location', true ) );

To this: $location = get_post_meta( $post->ID, 'location', true );

@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Sep 18, 2020

This is perfect and with modifications does exactly what I need, thank you. Well, almost. It's rendering out my WYSIWYG fields with visible HTML code and not converting it. Not sure how to get around that.

A friend gave me some tips and helped me sort it out.

Lets say this was a WYSIWYG field.
$location = esc_attr( get_post_meta( $post->ID, 'location', true ) );
As is, it would spit out unrendered HTML. If you remove the esc_attr and add apply_filters, it works great and renders the HTML like normal.
$location = apply_filters( 'the_content', get_field( 'location', $postID ) );
If there's another, more preferred way to do this, I'm all ears, but hopefully this is helpful for someone! :)

@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Sep 18, 2020

The esc_attr() function is "Escape Attributes", so it is converting the HTML in your field to escaped entities. If you remove that, you should be good.

For instance, change this: $location = esc_attr( get_post_meta( $post->ID, 'location', true ) );

To this: $location = get_post_meta( $post->ID, 'location', true );

Haha! We crossed paths. Thank you for responding so quickly, I didn't expect that. Looks like we came basically to the same conclusion, but yours looks better, so I'll do that. Thank you again!

@Artsen

This comment has been minimized.

Copy link

@Artsen Artsen commented Sep 29, 2020

How would I use this to display an Array? I have a "checkbox" custom field type, and I would like this to display the selected checkboxes, right now when I use it, all that is displayed is "Array".

@billerickson

This comment has been minimized.

Copy link
Owner Author

@billerickson billerickson commented Sep 29, 2020

@Artsen you need to loop through the array.

$items = get_post_meta( $post->ID, 'be_items', true );
foreach( $items as $item ) {
	$output .= $item;
}
@Artsen

This comment has been minimized.

Copy link

@Artsen Artsen commented Sep 30, 2020

Thanks so much! This helped me figure out a nice way to adapt it to my usage.

@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Oct 17, 2020

Hello again! this all worked great for me and I've been able to apply these snippets very well, but I'm getting stuck on $content. Content is a default parameter, so I include_content="true", but nothing happens. So I thought it was because I customized the output to include custom fields, so I added it to my output as $content. Still nothing. So I added it to the function itself next to $excerpt, that made a critical error.

Not sure what I'm doing wrong here, I just want to display the basic content instead of an excerpt. Ideas? Thank you so much for this!

add_filter( 'display_posts_shortcode_output', 'be_display_posts_custom_fields', 10, 6 );
function be_display_posts_custom_fields( $output, $atts, $image, $title, $date, $excerpt ) {

	// Get our custom fields
	global $post;
	$price = get_post_meta( $post->ID, 'item_price', true ) ;


	// If there's a value for the custom field, let's wrap them with <span>'s so you can control them with CSS
	if( isset( $price ) ) $price = '<div class="price">' . $price . '</div> ';

	// Now let's rebuild the output. 
	$output = '<li>' . $title . $price . $content .'</li>';
	//$output = '<li>' . $title . $price . $content .'</li>';

	// Finally we'll return the modified output
	return $output;
}
@billerickson

This comment has been minimized.

Copy link
Owner Author

@billerickson billerickson commented Oct 19, 2020

Your function is missing some of the parameters in the output filter, including the content, which is why it is empty. Try changing it to this:

add_filter( 'display_posts_shortcode_output', 'be_display_posts_custom_fields', 10, 11 );
function be_display_posts_custom_fields( $output, $original_atts, $image, $title, $date, $excerpt, $inner_wrapper, $content, $class, $author, $category_display_text ) {

	// Get our custom fields
	global $post;
	$price = get_post_meta( $post->ID, 'item_price', true ) ;


	// If there's a value for the custom field, let's wrap them with <span>'s so you can control them with CSS
	if( isset( $price ) ) $price = '<div class="price">' . $price . '</div> ';

	// Now let's rebuild the output. 
	$output = '<' . $inner_wrapper . ' class="' . implode( ' ', $class ) . '">' . $image . $title . $price . $date . $author . $category_display_text . $excerpt . $content . '</' . $inner_wrapper . '>';

	// Finally we'll return the modified output
	return $output;
}
@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Oct 19, 2020

AH! Well, I suppose that'll do it. ;-) Thank you so much for looking at this. I'll give it a try, thank you! (Update: I tried and it works great, thank you so much!)

And, at the risk of being a glutton, I was curious - I'm displaying a restaurant menu with this and on items with a particular taxonomy, the client's print menu has a little icon. I figured, 'Oh, no problem, I'll just find where the post calls the tax term and apply css, blah blah...', but alas... I don't see where it's does that, like some entries might. Any thoughts on that? Can I do that somehow with the category_display_text?

@billerickson

This comment has been minimized.

Copy link
Owner Author

@billerickson billerickson commented Oct 20, 2020

You could customize the $category_display_text using the output filter above (it's the last parameter in that filter.

Or you could add a custom class to the listing item using the display_posts_shortcode_post_class filter (examples).

@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Oct 28, 2020

Hi Bill! Thanks so much for this. I was trying to use the display_posts_shortcode_post_class method because handling it in CSS would be so much easier, but I am running into an issue. I tried it just how you had it above, coupled with your additional link to adding the category class, but nothing seems to be working. If I use your snippet exactly as you have it, it causes a critical error on my site. If I remove some things, then it works -- not sure why that is.

/* Add Custom Fields to Display Posts Shortcode */
add_filter( 'display_posts_shortcode_output', 'be_display_posts_custom_fields', 10, 11 );

function be_display_posts_custom_fields( $output, $original_atts, $image, $title, $date, $excerpt, $inner_wrapper, $content, $class, $author, $category_display_text ) {

	// Get our custom fields
	global $post;
	$itemdesc = apply_filters('the_content', get_field('item_description', $postID));
	$itemprice = get_post_meta( $post->ID, 'item_price', true );
	$hhprice = get_post_meta( $post->ID, 'happy_hour_price', true );
	$tuesprice = get_post_meta( $post->ID, 'casual_tuesday_price', true );	
	$winevariety = get_post_meta( $post->ID, 'wine_variety', true );
	$wineyear = get_post_meta( $post->ID, 'wine_year', true );
	$wineregion = get_post_meta( $post->ID, 'wine_region', true );
	$glass = get_post_meta( $post->ID, 'wine_price_glass', true );
	$bottle = get_post_meta( $post->ID, 'wine_price_bottle', true );

	// If there's a value for the custom field, let's wrap them with <span>'s so you can control them with CSS
	if( isset( $itemdesc ) ) $itemdesc = '<span class="itemdesc">' . $itemdesc . '</span> ';
	if( isset( $itemprice ) ) $itemprice = '<span class="itemprice">' . $itemprice . '</span> ';
	if( isset( $hhprice ) ) $hhprice = '<span class="hhprice">' . $hhprice . '</span> ';
	if( isset( $tuesprice ) ) $tuesprice = '<span class="tuesprice">' . $tuesprice . '</span> ';
	
	if( isset( $winevariety ) ) $winevariety = '<span class="variety">' . $winevariety . '</span> ';
	if( isset( $wineyear ) ) $wineyear = '<span class="year">' . $wineyear . '</span> ';
	if( isset( $wineregion ) ) $wineregion = '<span class="region">' . $wineregion . '</span> ';
	if( isset( $glass ) ) $glass = '<span class="itemprice glass">' . $glass . '</span> ';
	if( isset( $bottle ) ) $bottle = '<span class="itemprice bottle">' . $bottle . '</span> ';
	

	
	// Now let's rebuild the output. 
	$output = '<li class="' . implode( ' ', $class ) . '">' . $itemdesc . $image . $title . $winevariety . $wineyear . $wineregion . $itemprice . $hhprice . $tuesprice . $glass . $bottle . $date . $author . $category_display_text . $excerpt . $content . '</li>';


	// Finally we'll return the modified output
	return $output;
}

And then I'm using this after it.


/**
 * Display Posts Shortcode, add category classes 
 * @see https://displayposts.com/2019/01/03/add-category-classes/
 */
function be_dps_add_category_classes( $classes ) {
  $categories = get_the_terms( get_the_ID(), array('house-selection','coravin-wine-program') );
  if( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
    foreach( $categories as $category) {
      $classes[] = 'cat-' . $category->slug;
    }
  }
  return $classes;
}
add_filter( 'display_posts_shortcode_post_class', 'be_dps_add_category_classes' );

My expectation was that anything with the term 'house-selection' or 'coravin-wine-program' would display class="cat-house-selection', etc and then I can just style that class. But for some reason... nothin'. Just "list-item".

I did have the inner-wrapper bits in there, but that made everything freak out, so I remove it and it all worked okay. Except for this bit. :)

@billerickson

This comment has been minimized.

Copy link
Owner Author

@billerickson billerickson commented Oct 28, 2020

The second parameter of get_the_terms() should be the taxonomy, not a list of terms.

Assuming the taxonomy is 'category', this code should work:

/**
 * Display Posts Shortcode, add category classes 
 * @see https://displayposts.com/2019/01/03/add-category-classes/
 */
function be_dps_add_category_classes( $classes ) {
  $categories = get_the_terms( get_the_ID(), 'category' );
  if( ! empty( $categories ) && ! is_wp_error( $categories ) ) {
    foreach( $categories as $category) {
      $classes[] = 'cat-' . $category->slug;
    }
  }
  return $classes;
}
add_filter( 'display_posts_shortcode_post_class', 'be_dps_add_category_classes' );
@joellereeder

This comment has been minimized.

Copy link

@joellereeder joellereeder commented Oct 28, 2020

Thanks! I used that code initially, straight out of the tin, changing only the 'category' to 'house-selection', but nothing happened.

It's a custom taxonomy, not a category, so I wasn't sure what to do at that point. :) I just tried it again, just from the code you gave me here and selected only 'house selection', but it gives me li class="list-item"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.