I am relatively new to the WordPress CMS and decided to use Pods for my custom field implementations including several image fields. While I love the admin UI I was a bit flustered trying output the images in my post template file.
After a lot of research and experimenting I wanted to share the technique I used. Obviously if there is a better way I'd love to know.
The first thing I learned from the Pods forum was that Pods saves images to the database as 'Attachment' posts. So, they can be accessed as you would access any regular old WordPress attachment.
Attachments have a parent-child relationship with their post which means you can programmatically grab all the attachments for a given post using this snippet adapted from WP beginners:
<?php
if ( $post->post_type == 'post-type' && $post->post_status == 'publish' ) {
$attachments = get_posts( array(
'post_type' => 'attachment',
'posts_per_page' => -1,
'post_parent' => $post->ID,
'exclude' => get_post_thumbnail_id()
) );
if ( $attachments ) {
foreach ( $attachments as $attachment ) {
$class = "post-attachment mime-" . sanitize_title( $attachment->post_mime_type );
$thumbimg = wp_get_attachment_image( $attachment->ID, 'thumbnail');
echo '<li class="' . $class . ' data-design-thumbnail">' . $thumbimg . '</li>';
}
}
}
?>
But this solution is sub-optimal because the parent-child relationship between the post and the image can only be broken if the image is deleted from the media library. So:
An image removed from it's original post but left in the library for future use will still be output by the above code on the original post
If you do re-purpose the image on a different post's Pod field the code above won't print it on the new entry.
The attachment system does not record field level relationships. So, if you have more than one image based Pod field on a Post the code above will print them all regardless if their field.
That said, I have found the best option for outputting Pod based image data by field is to combine the 'get_post_meta' function outlined here on the WordPress support forums with the 'wp_get_attachment_image' function as shown below.
<?php
if ( get_post_meta( get_the_ID(), 'image_field', false ) ){
$image_array = get_post_meta( get_the_ID(), 'image_field', false );
}
if ( $image_array ) {
echo '<ul>';
foreach ( $image_array as $image ) {
$class = "post-attachment mime-" . sanitize_title( $image->post_mime_type );
$thumbimg = wp_get_attachment_image( $image['ID'], 'thumbnail');
echo '<li class="' . $class . ' data-design-thumbnail">' . $thumbimg . '</li>';
}
echo '</ul>';
}
?>
The former function gives you an object with only the current images. The latter renders those images with size and alt info limited to the attachments system.
Related
I want to display the id's of my categories using the get_categories function.
I have looked on google and stackexchange and foud these 2 methods
$categories = get_categories(
array(
'orderby' => 'name',
'order' => 'ASC'
)
);
foreach( $categories as $category ) {
echo '<p>' .'Category id'. $category->cat_id . '</p>';
// the method above and below are the ones i found
// but both the id and cat_id give no results
echo '<p>' .'Category id'. $category->id . '</p>';
}
I know i can use:
echo get_cat_ID( $category->name );
But i want i want it clean like the code above.
Anyone has any ideas why this is not working?
I believe that "cat_ID" is a pseudonym of "term_id" and can only be used with a limited set of functions. You mention get_cat_ID and its source shows it returns term_id.
Your existing code may work if you change cat_id to cat_ID - but I'd use term_id instead (it certainly works for me with the "similar" get_the_category function)
I inherited a website that includes a custom post type (Cities). Due to some wonky url rewrites and redirects, SEO plugins won't work on those pages.
This custom post type has a taxonomy (States) and I need to insert the state name into the title tag in my header.php. I've tried the following, to no avail:
<title>Log Cabin Rentals in <?php single_term_title(); ?> - Find Your Dream Vacation Rental in <?php single_term_title(); ?></title>
I also tried:
<?php
$term = get_term_by( 'slug', get_query_var('term'), get_query_var('taxonomy') );
echo '<title>Cash for Gold Near ' . $term->name . ' - Find Gold Buyers Near ' . $term->name .'</title>';
echo '<meta name="description" content="Looking for cash for gold near ' . $term->name . '? Our cash for gold directory helps you find reputable local gold buyers and pawnshops near ' . $term->name . ', as well as info on how to earn the most cash for gold.">';
?>
What am I doing wrong?
Many thanks!
Cynthia
Give this a shot instead:
$term = get_term_by( 'slug', get_query_var('term'), get_query_var('taxonomy') );
echo $term->name;
If that echoes out your taxonomy name, you could replace the echoes in your title tag with $term->name
Solution One:
get_terms() - Retrieve the terms in a given taxonomy or list of taxonomies.
You can fully inject any customizations to the query before it is sent, as well as control the output with a filter.
The ‘get_terms’ filter will be called when the cache has the term and will pass the found term along with the array of $taxonomies and array of $args. This filter is also called before the array of terms is passed and will pass the array of terms, along with the $taxonomies and $args.
get_terms returns an array of objects. You cannot echo an array, if you do, you will just get Array(). What you can do is print_r($array) or var_dump($array) to see the data it contains.
$taxonomy = 'shirt';
$args=array(
'hide_empty' => false,
'orderby' => 'name',
'order' => 'ASC'
);
$tax_terms = get_terms( $taxonomy, $args );
foreach ( $tax_terms as $tax_term ) {
echo $tax_term->name;
}
Solution Two:
You can use the function called get_taxonomies() in order to query out the taxonomy that you need.
Syntax:
<?php get_taxonomies( $args, $output, $operator ) ?>
Example:
This example uses the 'object' output to retrieve and display the taxonomy called 'genre':
<?php
$args=array(
'name' => 'genre'
);
$output = 'objects'; // or names
$taxonomies=get_taxonomies($args,$output);
if ($taxonomies) {
foreach ($taxonomies as $taxonomy ) {
echo '<p>' . $taxonomy->name . '</p>';
}
}
?>
I want to create something like this in wordpress, so that in a wordpress page I can show users the post titles which are linked to their post links and also the date of those posts.
what kind of code should I use in wordpress? I am new to wordpress coding. so please give me some sample code so that I can use.
also I want to choose posts from one special category. how can I do that? is there any wordpress plugin which does this?
pagination links are also important to have.
Thanks
I would look into WP_Query. It may take a little while to get used to it but it lets you echo all the data you want. I use it for almost everything now.
In the $args array you define what you want to query (such as posts from a specific category, how many, in what order), and then from there you can pull the title, the date published, the attachments, the excerpt, featured image, etc.
<?php
// The Query
$args = array(
'numberposts' => '5',
'category_name' => 'my-category', // the slug
'offset' => '0',
'orderby' => 'post_date',
'order' => 'DESC',
'post_status' => 'publish'
);
$the_query = new WP_Query( $args );
// The Loop
if ( $the_query->have_posts() ) {
echo '<ul>';
while ( $the_query->have_posts() ) {
$the_query->the_post();
echo '<li>' . get_the_title() . '</li>';
}
echo '</ul>';
/* Restore original Post Data */
wp_reset_postdata();
} else {
// no posts found
}
?>
The great part about WP_query is that you can use it to have multiple loops on 1 template. This would replace the normal loop in the template.
For date, you would use the_date() or get_the_date(). So you might do an
echo '<p><span class="date">' . get_the_date() . '</span> <a class="my-title" href="' . get_the_title() . '">' . get_the_title() . '</a></p>';
There's more than one way to do this (and almost everything) in WordPress, so it depends on what you're doing and what else is going on in the code. There's query_posts() and wp_get_recent_posts()... really there's too many to mention. I'd post more links but my rep isn't high enough to.
I'd start looking into WP_Query as you can pull whatever data you want from that and format it to your heart's content.
Anyway, hope this well help you.
I have been searching for weeks and I still haven't found a proper solution to this problem.
I am writing a Wordpress Theme. I have a custom post type called Works. I would like to add my Works archive to my menu and have it as well as it's posts highlighted when I access them.
I can access my archive and posts on the following links
Works archive: /works/
Works single post: /works/postname/
My solution so fare have been to name my archive-works.php template file with a template name (Work archive). Then create an empty page using that template and adding the page to the menu. This highlights the archive in the menu but not the single posts.
I can easily solve this with a custom link and some javascript but there must be a better and cleaner way.
You can do a simple trick in your functions.php:
add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($classes, $item) {
// Get post_type for this post
$post_type = get_query_var('post_type');
// Go to Menus and add a menu class named: {custom-post-type}-menu-item
// This adds a 'current_page_parent' class to the parent menu item
if( in_array( $post_type.'-menu-item', $classes ) )
array_push($classes, 'current_page_parent');
return $classes;
}
In your case, you just have to add a class 'works-menu-item' with that archive menu item by the admin panel;
To add "custom posttype archive link" to menu, please look at the following guide
Open file functions.php , and enter code below
add_action('admin_head-nav-menus.php', 'wpclean_add_metabox_menu_posttype_archive');
function wpclean_add_metabox_menu_posttype_archive() {
add_meta_box('wpclean-metabox-nav-menu-posttype', __('Custom Post Type Archives'), 'wpclean_metabox_menu_posttype_archive', 'nav-menus', 'side', 'default');
}
function wpclean_metabox_menu_posttype_archive() {
$post_types = get_post_types(array('show_in_nav_menus' => true, 'has_archive' => true), 'object');
if ($post_types) :
$items = array();
$loop_index = 999999;
foreach ($post_types as $post_type) {
$item = new stdClass();
$loop_index++;
$item->object_id = $loop_index;
$item->db_id = 0;
$item->object = 'post_type_' . $post_type->query_var;
$item->menu_item_parent = 0;
$item->type = 'custom';
$item->title = $post_type->labels->name;
$item->url = get_post_type_archive_link($post_type->query_var);
$item->target = '';
$item->attr_title = '';
$item->classes = array();
$item->xfn = '';
$items[] = $item;
}
$walker = new Walker_Nav_Menu_Checklist(array());
echo '<div id="posttype-archive" class="posttypediv">';
echo '<div id="tabs-panel-posttype-archive" class="tabs-panel tabs-panel-active">';
echo '<ul id="posttype-archive-checklist" class="categorychecklist form-no-clear">';
echo walk_nav_menu_tree(array_map('wp_setup_nav_menu_item', $items), 0, (object) array('walker' => $walker));
echo '</ul>';
echo '</div>';
echo '</div>';
echo '<p class="button-controls">';
echo '<span class="add-to-menu">';
echo '<input type="submit"' . disabled(1, 0) . ' class="button-secondary submit-add-to-menu right" value="' . __('Add to Menu') . '" name="add-posttype-archive-menu-item" id="submit-posttype-archive" />';
echo '<span class="spinner"></span>';
echo '</span>';
echo '</p>';
endif;
}
Thanks
Thanks to rasmussvanejensen for her/his nice question and thethangtran for the answer, I am still confused why Wordpress has not yet added such a good feature to its code base by default.
By the way I think there is even a better solution than the one provided by thethangtran, as it may break on some situations.
Note 1
According to the Codex, using register_post_type, one can add extra post_types to the installation. There is chance, some one need to change the 'query_var' and thus the provided code will break.
Note 2
In addition, it may not handle the current-menu-item class, which will be used for css customization to show the menu item as active.
Note 3
As another note on the code, there is no need to define the loop_index, item and items variables. they are absolutely useless.
A better solution
So I suggest using this alternative, for those who want a more robust solution to on this:
function prefix_add_metabox_menu_posttype_archive(){
add_meta_box( 'prefix_metabox_menu_posttype_archive', __( 'Archives' ), 'prefix_metabox_menu_posttype_archive', 'nav-menus', 'side', 'default' );
}
add_action( 'admin_head-nav-menus.php', 'prefix_add_metabox_menu_posttype_archive' );
function prefix_metabox_menu_posttype_archive(){
$post_types = get_post_types( array( 'show_in_nav_menus' => true, 'has_archive' => true ), 'object' );
if( $post_types ){
foreach( $post_types as $post_type ){
$post_type->classes = array( $post_type->name );
$post_type->type = $post_type->name;
$post_type->object_id = $post_type->name;
$post_type->title = $post_type->labels->name;
$post_type->object = 'cpt_archive';
}
$walker = new Walker_Nav_Menu_Checklist( array() );?>
<div id="cpt-archive" class="posttypediv">
<div id="tabs-panel-cpt-archive" class="tabs-panel tabs-panel-active">
<ul id="ctp-archive-checklist" class="categorychecklist form-no-clear"><?php
echo walk_nav_menu_tree( array_map( 'wp_setup_nav_menu_item', $post_types ), 0, (object) array( 'walker' => $walker ) );?>
</ul>
</div>
</div>
<p class="button-controls">
<span class="add-to-menu">
<input type="submit"<?php disabled( $nav_menu_selected_id, 0 ); ?> class="button-secondary submit-add-to-menu" value="<?php esc_attr_e( 'Add to Menu' ); ?>" name="add-ctp-archive-menu-item" id="submit-cpt-archive" />
</span>
</p><?php
}
}
function prefix_cpt_archive_menu_filter( $items, $menu, $args ){
foreach( $items as &$item ){
if( $item->object != 'cpt_archive' ) continue;
$item->url = get_post_type_archive_link( $item->type );
if( get_query_var( 'post_type' ) == $item->type ){
$item->classes []= 'current-menu-item';
$item->current = true;
}
}
return $items;
}
add_filter( 'wp_get_nav_menu_items', 'prefix_cpt_archive_menu_filter', 10, 3 );
Navigate to Appearance > Menus;
Make sure you have the Works' custom post type selected at Screen Options;
Click on the name of your custom post type to expand it and then click on the ‘View all’ tab;
You will see an option for All Works. Check the box next to it and then click on the Add to Menu button;
Your custom post type archive will now appear as a menu item in the right column;
By default, the label will be "All Works". You can change this by writing something different at the Navigation Label;
Click on the Save Menu button to save your changes.
I found a solution on GitHub and it works out of the box by simply adding it to the functions.php without any walkers or extra classes.
This code solves it by comparing the slug of the current post type
with the navigation items, and adds a class accordingly.
Code on GitHub
I have a page which has a slideshow at the top, and images inserted inline into the content area.
I need to exclude the images that have been inserted into the post from the slideshow.
Currently I am excluding the 'Featured Image', but this limits me to one image that can be inserted into the post.
Here is my existing code:
$thumbnail = get_post_thumbnail_id();
$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);
Previously I have used the description field of the image meta data to exclude images by entering 'exclude'. This isn't as nice for the end user as I'd like it to be.
Any suggestions, plugins or code based!
Update:
I've updated the code, so now I get any image URLs from the post_content and check them against the slideshow images.
$content = $post->post_content;
$inlineImages = array();
preg_match( '/src="([^"]*)"/i', $content, $inlineImages ) ;
$thumbnail = get_post_thumbnail_id($post->ID);
$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);
if ($images) {
echo '<div id="slideshow">';
foreach ( $images as $attachment_id => $attachment ) {
$image = wp_get_attachment_image_src( $attachment_id,array(900,265));
if (!in_array($image[0],$inlineImages)) {
echo '<img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'">';
}
}
echo '</div>';
}
This is an OK solution, although the regex could be improved.
A nicer step would be to add the array of images to a custom field field, which
is updated on post / page update or publish.
Any suggestions on how to go about this?
Just needed to do the same thing. Your original approach is the way I wanted to do it -- simply exclude any images that had been inserted into the post from appearing in the slider. But I didn't want the client to have to do anything special to make it happen. Here's my code.
$args = array( 'post_type' => 'attachment', 'post_mime_type'=>'image','numberposts' => -1, 'post_status' => null, 'post_parent' => $post->ID );
$attachments = get_posts($args);
preg_match_all("/<img[^']*?src=\"([^']*?)\"[^']*?>/", $post->post_content, $matches, PREG_PATTERN_ORDER);
/* $matches[1] holds the urls as an array */
foreach ( $attachments as $attachment ) {
if(in_array($attachment->guid, $matches[1])){ continue;}
wp_get_attachment_image( $attachment->ID , 'slider_size');
}
First bit gets all of the images associated with the post. The $preg_match_all gets all of the images in the post body. Then as we loop through the images to display them in the slider the in_array checks the urls of the images that were inserted with the url of the image about to be added to the slider and skips on to the next one if there is a match.
Thanks for you post, got me thinking in the right direction.
I've updated the code, so now I get any image URLs from the post_content and check them against the slideshow images.
$content = $post->post_content;
$inlineImages = array();
preg_match( '/src="([^"]*)"/i', $content, $inlineImages ) ;
$thumbnail = get_post_thumbnail_id($post->ID);
$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);
if ($images) {
echo '<div id="slideshow">';
foreach ( $images as $attachment_id => $attachment ) {
$image = wp_get_attachment_image_src( $attachment_id,array(900,265));
if (!in_array($image[0],$inlineImages)) {
echo '<img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'">';
}
}
echo '</div>';
}
I think the easiest thing to do would be using the Meteor Slideshow plugin to create a slideshow for each page, then insert the shortcode for the proper slideshow in the content area of the proper page. Yes, it means you'll have to edit each page "outside" the page editor, but it also gives you easy, complete control over which photos do and do not appear in each slideshow, and the shortcode is very easy to put in with the page editor.
The Media Custom Fields plugin lets you add custom data to media items exactly as you would with custom post fields, providing a user-friendly way of flagging slideshow-only images. From the plugin FAQ:
In addition to giving you the option to add custom fields, your custom fields will show up in all appropriate places. If you go to the media section to manage your media like you usually do, they will show up on the edit media form. The custom fields also show up when you are uploading an image to a post, and in all other expected locations.
One approach is to install this plugin and add a custom field such as Slide with value TRUE to your slide images via the Dashboard -> Media menu. Then your filter code might be:
$thumbnail = get_post_thumbnail_id();
$images = get_children( /* removed for brevity */ );
if ($images) {
// ..
foreach ( $images as $attachment_id => $attachment ) {
// skip images not marked for slideshow
if ( !get_post_meta($attachment_id, 'Slide') ) continue;
// otherwise do slideshow things
}
// ..
}
Note that with this approach the value for Slide can be set to anything except the empty string. You may want to define Slide as a class constant somewhere to avoid hard-coding.
Advantages
Doesn't require any work on the poster's part
Future-proof: the plugin appears to be based on good-old post functionality, and attachments are just one kind of post anyway, so there's nothing weird.
Here is another approach to this.
I would not prefer using urls, because the picture inserted inside the content area could be of different size like medium, thumbnail or full. So, the url only would not match.
Using the above code,
function printMeImages() {
$content = $post->post_content;
$inlineImages = array();
// populate ids of images from wp-image-id
preg_match_all( '/wp-image-([^"]*)"/i', $content, $inlineImages ) ;
$thumbnail = get_post_thumbnail_id($post->ID);
$images = get_children( 'post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail);
$out = "";
if ($images) {
$out .= '<ul id="slideshow">';
foreach ( $images as $attachment_id => $attachment ) {
$image = wp_get_attachment_image_src( $attachment_id,'desiredImageSize');
// $inlineImages[1] has ids to be discarded
if (!in_array($attachment_id,$inlineImages[1])) {
$out .= '<li><img src="'.$image[0].'" width="'. $image[1] .'" height="'. $image[2].'"></li>';
}
}
$out .= '</ul>';
}
return $out;
}
The images which are not set as featured and not used inside the post are retrieved.
For performance reasons I would not execute the code while the page is being rendered, but rather bind the code to the save_post hook. When the post content is edited and saved, the hook will be called and all attached images (or their ids) which are not used in the content are saved into a postmeta table. When the slider is rendered the image ids can be accessed via get_post_meta($post_id, 'image_ids_for_slider').
Like this I can avoid to do the preg_match_all operation on page rendering. This might not be a performance reason when the post content is small and when there's only one slider loaded, but generally I find this a approach a little cleaner for scaling reasons.
//hook this function to save post action
function save_ids_of_image_attachments_not_used_in_the_content( $post_id, $post ) {
$args = array( 'post_type' => 'attachment',
'post_mime_type'=>'image',
'numberposts' => -1,
'post_status' => null,
'post_parent' => $post_id
);
$attachments = get_posts($args);
preg_match_all("/<img[^']*?src=\"([^']*?)\"[^']*?>/", $post->post_content, $matches, PREG_PATTERN_ORDER);
$ids_of_attached_images_not_in_content = array();
/* $matches[1] holds the urls as an array */
foreach ( $attachments as $attachment ) {
if(in_array($attachment->guid, $matches[1])){
continue;
}
$ids_of_attached_images_not_in_content[] = $attachment->ID;
}
// save the image_ids as postmeta
update_post_meta($post_id, 'image_ids_for_slider', $ids_of_attached_images_not_in_content);
}
add_action( 'save_post', 'save_ids_of_image_attachments_not_used_in_the_content', 10, 2 );
I haven't fully understood your problem, but how about excluding the div ID within which the slideshow is present?
$thumbnail = get_post_thumbnail_id();
$images = get_children('post_type=attachment&post_mime_type=image&order=asc&orderby=menu_order&post_parent='.$post->ID .'&exclude='.$thumbnail. '&NAME');
Replace 'NAME' after thumbnail.' in the parenthesis.
Hope this helps.