Skip to content

Instantly share code, notes, and snippets.

@billerickson
Created September 11, 2011 13:46
Show Gist options
  • Save billerickson/1209601 to your computer and use it in GitHub Desktop.
Save billerickson/1209601 to your computer and use it in GitHub Desktop.
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;
}
@billerickson
Copy link
Author

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
Copy link

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
Copy link
Author

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
Copy link

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
Copy link
Author

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
Copy link

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"

@joellereeder
Copy link

Just a follow up as I realized what I was doing wrong. I was adding the name of the term in place of 'category' instead of the taxonomy itself. Once I added 'wine_highlights' then it spit out what I wanted. So thank you again so much for your help, Bill! :)

@joellereeder
Copy link

joellereeder commented Jul 11, 2021

Hi Bill! I'm working on something similar as before and need to display the chosen value of a mutli-select field. I've tried cycling through the values per your note to Arsten above but am struggling to get it to display anything other than the number '2' (after a couple adjustments, now it's showing various numbers on every post, even though every post doesn't have a selection). It should be showing me words.

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 ) {
	global $post;
	
	//	Create an empty string
	$outputString = '';
	
	// Check rows exist
	if (have_rows('wine_list', $post->ID) || 		
		have_rows('beer_list', $post->ID)) :
	
	// Loop through rows.
		$outputString .= '<h3>' . $title . '</h3>';
	

	// WINE LIST
	while (have_rows('wine_list', $post->ID)) : the_row();

			// Get sub-field values
					$wine_year = get_sub_field('wine_year');
					$wine_name = get_sub_field('wine_name');
					$wine_varietal = get_sub_field('wine_varietal');
					$wine_region = get_sub_field('wine_region');	
					$wine_glass = get_sub_field('wine_glass'); 
					$wine_bottle = get_sub_field('wine_bottle');
					$wine_split = get_sub_field('wine_split');
					//$wine_key = get_sub_field('wine_key');
					$wine_key = get_post_meta( $post->ID, 'wine_key', true );
						foreach( $items as $item ) {
						$output .= $item;
					}


			$WineList = '';
	
			// If there's a value for the custom fields, wrap them in divs and append them to $
			if( $wine_year ) $WineList .= '<div class="year">' . $wine_year . '</div>';	
			if( $wine_name ) $WineList .= '<div class="vineyard">' . $wine_name . '</div>';
			if( $wine_varietal ) $WineList .= '<div class="varietal">' . $wine_varietal . '</div>';
			if( $wine_region ) $WineList .= '<div class="region">' . $wine_region . '</div>';		
			if( $wine_bottle ) $WineList .=  '<div class="price bottle">' . $wine_bottle . '</div> ';
			if( $wine_split ) $WineList .=  '<div class="price split">' . $wine_split . '</div> ';
			if( $wine_glass ) $WineList .=  '<div class="price glass">' . $wine_glass . '</div> ';
			if( $wine_key ) $WineList .= '<div class="key">' . $item . '</div>';
			

			
			if ($WineList) {
				$outputString .= '<li>' . $WineList . '</li>';
			}
	
	endwhile;
	

	// Now let's rebuild the output. 
		$output = $outputString . $category_display_text . $excerpt . $content;
	endif;
	
	// Shortcode output should always be returned, and since we're FILTERing it, we need to make sure that something is returned no matter what
	return $output;
} 

I'm certain that my $wine_key item is set up incorrectly, but I'm not sure how to fix what I'm missing here.

I'd appreciate any insight. :) Thank you!

@joellereeder
Copy link

Hi! I'm running into a little issue on something related to this topic. I'm really in a time sensitive place and am hoping someone sees this. Song of our people. :)

//* DISPLAY POSTS SHORTCODE CUSTOMIZATIONS *//

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;
$date_start = get_post_meta( $post->ID, 'seminar_date_time', true ) ;
$date_end = get_post_meta( $post->ID, 'seminar_end_time', true ) ;
$synopsis = get_post_meta( $post->ID, 'seminar_synopsis', true ) ;
$name = get_post_meta( $post->ID, 'seminar_name', true ) ;
$host = get_post_meta( $post->ID, 'seminar_host_name', true ) ;
$bio = get_post_meta( $post->ID, 'seminar_host_bio', true ) ;
$headshot = get_post_meta( $post->ID, 'seminar_host_headshot', true ) ;
$cost = get_post_meta( $post->ID, 'seminar_cost', true ) ;
$location = get_post_meta( $post->ID, 'seminar_location', true ) ;
$sponsor = get_post_meta( $post->ID, 'seminar_sponsor', true ) ;
$eventbrite = get_post_meta( $post->ID, 'seminar_eventbrite_link', 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( $date_start ) ) $date_start = '<div class="date">' . $date_start . ' &mdash;' . $date_end . '</div> ';

if( isset( $name ) ) $name = '<h4>' . $name . '</h4> ';
if( isset( $synopsis ) ) $synopsis = '<div class="synopsis">' . $synopsis . '</div> ';
if( isset( $headshot ) ) $headshot = '<img src="' . $headshot .'class="alignleft headshot" />';
if( isset( $host ) ) $host = '<h6>' . $host . '</h6>';
if( isset( $bio ) ) $bio = '<div class="bio">'. $bio . '</div> ';

if( isset( $location ) ) $location = '<div class="location">' . $location . '</div> ';
if( isset( $cost ) ) $cost = '<div class="cost">' . $cost . '</div> ';
if( isset( $eventbrite ) ) $eventbrite = '<a href="' . $eventbrite . '" class="button eventbrite-link">Reserve Your Spot</a>';

// Now let's rebuild the output.
$output = '<li>' . $date_start . $excerpt . $name . $synopsis . $headshot . $host .  $bio . $cost . $location . $eventbrite .'</li>';

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

This is all great, except it's not rendering my links or my images - despite me requesting a link and an image link.
And my dates are rendering like this: 2022-08-05 08:30:00 β€”2022-08-05 10:00:00

Is there a way to make those display the custom display I set in ACF? I set the date_format, but it made no difference.

Thank you!

@billerickson
Copy link
Author

In your rebuilding of the output at the end, you're not including the $image, and I'm not sure what link you want.

Your date is displaying as it is in the database since you're calling it directly. you can either:

a) Format your date, like date( 'F j Y, $date_start ) or
b) Use get_field() instead of get_post_meta() so ACF formats it.

@joellereeder
Copy link

I managed to get my dates to display properly using the actual field names instead of $date or $date_start. I just called the field in the conditionals area, which doesn't seem to be doing any conditionals, it shows everything whether it's set or not.

But, my biggest issue right now are the links. The last "eventbrite" item. That is happening in 90 minutes and I can't get the link to display. I've tried it without anything, just naked. I've tried it wrapped in html like I have here. I've tried making it an ACF text field instead of a URL, nothing seems to work. NOTHING displays in the "url" portion of it. It either pastes nothing, or it displays a broken button. I keep looking at my code and see no issues, so if anyone has a second pair of eyes, I'd appreciate it. :) Thanks!

@joellereeder
Copy link

Oh! Hi! sorry, I missed your reply. I got everything, but the $eventbrite link is my biggest issue right now. Sorry about not being more clear. :)

It's currently an ACF text field with a link it. I can't get it to give me anything.

@billerickson
Copy link
Author

I don't see anything obviously wrong with it.

@joellereeder
Copy link

Thanks, Bill. Yes, that's the kicker. Me either. πŸ˜„ Thanks for your help. I appreciate your time.

@joellereeder
Copy link

AH! So... this is what's not working. :)

if( isset( $headshot ) ) $headshot = '<img src="' . $headshot .'class="alignleft headshot" />';
Same with the link. It's because I'm trying to wrap it in HTML, I guess. Truth be told, I'm not sure how to fix that. The others seem to work fine because we're closing them, but this breaks down on the first double quote. Do I escape it or what should I do there, if you have a recommendation? If not, thank you anyway. :)

@billerickson
Copy link
Author

You're missing the closing double quote. It should be

if( isset( $headshot ) ) $headshot = '<img src="' . $headshot .'" class="alignleft headshot" />';

@joellereeder
Copy link

Oh my god, thank you. Leave it to the ol’ missing quotes. I stared at that for literally hours. Thank you so much.

@joellereeder
Copy link

That worked, thanks! Though I guess I had corrected that at some point - but maybe I don't clearly understand isset. Is that meant to be like a conditional?

I assumed it was saying "if this is not null, show this", but that's not what's happening. it's rendering the html regardless of whether or not the field is empty. Thanks again, I appreciate your help.

@billerickson
Copy link
Author

Isset is checking if that variable actually exists, regardless of whether it's empty or not. You probably want if( ! empty( $headshot ) )

@joellereeder
Copy link

OOOOOOOOOOOK. I was wondering about that. I was like "how does it know?" I feel silly because I write those conditionals all the time. Derp. πŸ˜„

@joellereeder
Copy link

joellereeder commented Oct 11, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment