سؤال

I am trying to create a home page where it is a list of categories with an associated thumbnail for each. I would like it so it returns each category once and returns the associated thumbnail from the latest post, or even better does not require me to add a featured image to each post, but rather grabs the thumbnail from the image of the post, using post_mime_type ? I am still a ways off as it is returning the category for each post that is within that category and then associating the image with every category.

Here is the function I am working with:

    function home_filter() {
        if ( is_home() )
        {
        add_filter( 'the_content', 'home_cats' );
        }
    }
    add_action('template_redirect', 'home_filter');
    function home_cats(){
        $args=array(
        'orderby' => 'name',
        'order' => 'ASC',
        );
        $categories=get_categories($args);
           foreach($categories as $category) { 
   echo '<li><a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . '>' . get_the_post_thumbnail($page->ID, 'thumbnail') . $category->name.'</a></li> ';
        } 
}

The home page is simply :

<ul>
<?php while ( have_posts() ) : the_post(); ?>
<?php the_content();?>
<?php endwhile; ?>
</ul>

The output is something like:

<ul>
<li><a href="../?cat=1" title="View all posts in Cat A" ><img src="..image-A.jpg"  />Cat A</a></li> 
<li><a href="../?cat=3" title="View all posts in Cat B" ><img src="..image-A.jpg"  />Cat B</a></li> 
<li><a href="../?cat=1" title="View all posts in Cat A" ><img src="..image-B.jpg"  />Cat A</a></li> 
<li><a href="../?cat=3" title="View all posts in Cat B" ><img src="..image-B.jpg"  />Cat B</a></li>
<li><a href="../?cat=1" title="View all posts in Cat A" ><img src="..image-C.jpg"  />Cat A</a></li> 
<li><a href="../?cat=3" title="View all posts in Cat B" ><img src="..image-C.jpg"  />Cat B</a></li> 
 </ul>

Can someone please help me understand how to return each category only once and include the thumb from the latest post in that category? And even better can anyone think of a way to accomplish this without having to set the feature image every time?

هل كانت مفيدة؟

المحلول

Normally I like to shy away from recommending direct SQL, but in your use-case I think it is warranted.

I've coded this up as a direct SQL query; as you may notice is a bit complex. You can copy the following code to your theme's functions.php file or add it to the .php file of a plugin you might be writing:

function home_cats($max_image_height=150){
  $categories= get_taxonomy_latest_posts_with_attachment('category');
  echo '<h1>Categories</h1>';
  foreach($categories as $category) {
    $category_link = get_category_link( $category->term_id );
    $category_title = sprintf( __( "View all posts with category: '%s'" ),$category->term_name );
    $post_title = get_the_title($category->post_id);
    $post_link = get_permalink($category->post_id);
    $img_html = wp_get_attachment_image( $category->attachment_id, array( 'thumbnail',$max_image_height ) );
    $html = <<<HTML
<div id="category-{$category->term_slug}" class="category">
  <span style="float:right;">{$img_html}</span>
  <span  style="float:left;">
    <h2><a href="{$category_link}" title="{$category_title}">{$category->term_name}</a></h2>
    <p style="float:left;">Latest post: <a href="{$post_link}" title="{$post_title}">$post_title</a></p>
  </span>
</div>
<br clear="both" />
HTML;
    echo $html;
  }
}
function get_taxonomy_latest_posts_with_attachment($taxonomy) {
    global $wpdb;
    $sql =<<<SQL
SELECT
  categorized_posts.rownum,
  categorized_posts.term_id,
  categorized_posts.term_name,
  categorized_posts.term_slug,
  categorized_posts.post_id,
  categorized_posts.post_date,
  categorized_posts.post_title,
  attachments.ID AS attachment_id,
  attachments.post_title AS attachment_title,
  attachments.post_mime_type AS attachment_mime_type,
  attachments.guid AS attachment_guid
FROM
  (
  SELECT
    rownum,
    term_id,
    term_name,
    term_slug,
    post_id,
    post_date,
    post_title,
    post_parent,
    post_name,
    post_type
  FROM (
    SELECT
      IF( @prev <> {$wpdb->terms}.term_id, @rownum := 1, @rownum := @rownum+1 ) AS rownum,
      @prev := {$wpdb->terms}.term_id,
      {$wpdb->terms}.term_id,
      {$wpdb->terms}.name AS term_name,
      {$wpdb->terms}.slug AS term_slug,
      {$wpdb->posts}.ID as post_id,
      {$wpdb->posts}.post_date,
      {$wpdb->posts}.post_title,
      {$wpdb->posts}.post_parent,
      {$wpdb->posts}.post_name,
      {$wpdb->posts}.post_type
    FROM
      {$wpdb->term_taxonomy}
      INNER JOIN {$wpdb->terms} ON {$wpdb->term_taxonomy}.term_id={$wpdb->terms}.term_id
      INNER JOIN {$wpdb->term_relationships} ON {$wpdb->term_relationships}.term_taxonomy_id={$wpdb->term_taxonomy}.term_taxonomy_id
      INNER JOIN {$wpdb->posts} ON {$wpdb->posts}.ID={$wpdb->term_relationships}.object_id
      INNER JOIN (SELECT @rownum := NULL, @prev := 0) AS rownum_initializer ON 1=1
    WHERE 1=1
      AND {$wpdb->posts}.post_type='post'
      AND {$wpdb->posts}.post_status='publish'
      AND {$wpdb->term_taxonomy}.taxonomy='%s'
    ORDER BY {$wpdb->posts}.post_parent DESC, {$wpdb->posts}.post_date DESC
    ) x
  ) categorized_posts
    INNER JOIN (SELECT MAX(ID) AS post_id,post_parent FROM {$wpdb->posts} WHERE post_type='attachment' GROUP BY post_parent) attachment_join ON attachment_join.post_parent=categorized_posts.post_id
    INNER JOIN {$wpdb->posts} attachments ON attachments.ID=attachment_join.post_id
WHERE
  categorized_posts.rownum=1
GROUP BY
  categorized_posts.term_id
ORDER BY
  categorized_posts.term_name
SQL;
  return $wpdb->get_results($wpdb->prepare($sql,$taxonomy));
}

You'll note I separated the logic so that you can get the list of any taxonomy terms and their latests posts with a photo by calling the get_taxonomy_latest_posts_with_attachment() function and passing it a taxonomy identifier, like this:

$post_tags = get_taxonomy_latest_posts_with_attachment('post_tags');

Because of the complexity of the SQL in that function I'm not going to try to explain it (or I'd be here all night) but if you have specific follow up questions, just ask. Anyway, here's what the code looks like on my test side with test data:

Screenshot of a WordPress site with the list of Categories and the Latest Post for Each
(source: mikeschinkel.com)

P.S. The people in the photos are friends of mine and all work with WordPress in one way or another. Hope they don't mind me using their likeness. :)

نصائح أخرى

That hook contraption is kinda messy, why not just call home_cats() in template?

Try this (note that it is query per category and can get ugly for performance):

function home_cats() {

    $args = array(
        'orderby' => 'name',
        'order' => 'ASC',
    );
    $categories = get_categories($args);

    echo '<ul>';

    foreach ( $categories as $category ) {

        $link = get_category_link($category->term_id);
        $title = sprintf(__("View all posts in %s"), $category->name);

        $posts = get_posts( array(
            'cat' => $category->term_id,
            'numberposts' => 1,
        ) );

        $post = $posts[0];

        $thumbnail =  get_the_post_thumbnail($post->ID);
        echo "<li><a href='{$link}' title='{$title}'>{$thumbnail}{$category->name}</a></li>";
    }

    echo '</ul>';
}

There are different ways to mine for images, I usually go with Get The Image.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى wordpress.stackexchange
scroll top