Wordpress display thousands of posts - php

I'm working on a project where I need to list all the categories, sub-categories (children, grand-children etc. to about 5th level) and posts inside them. At the moment I've managed to get the site working, but the issue is that the site takes minutes to load.
To be clear on what I want the site to look like, here's a drawing:
Category
Sub-category
Subsubcategory
Content
Subsubcategory
Content
Sub-category
You get the picture
And here's the code:
<?php
function listing($parentcat, $list_id='', $list_name='', $path=false) {
// parentcat is the desired category parent category, which is defined because the function is called a few times with different sets on the page.
// list_id, list_name and path are used for purposes not related to the question
echo "<ul><li name='$list_name'><h2><a href='#$list_name'>$list_name</a></h2>";
}
$args = array(
'parent' => $parentcat,
'include' => $cat_ids,
'hide_empty' => 1,
'orderby' => 'id'
);
$categories = get_categories( $args );
echo "<ul>";
foreach ($categories as $cat) {
if ($cat->cat_name != 'Uncategorized') {
$flat_path = substr(get_category_parents($cat->cat_ID, false, ' »' ), 14);
$catnam = $cat->cat_name;
$listtitle = ($path ? $flat_path : $catnam);
echo ('<li name="' . $cat->cat_ID . '"><h2>' . $listtitle . '</h2>' );
if (get_posts( "category_name=$catnam" ) ) {
if (have_posts()) : while (have_posts()) : the_post();
if (in_category($cat->cat_ID)) {
echo '<ul><li><div>';
the_content();
echo '</div></li></ul>';
} endwhile;
else :
_e('Empty list');
endif;
}
// Here's a recursive call for the function
listing($cat->cat_ID);
echo '</li>';
}
}
echo '</ul>';
}
?>

You might be missing 'posts_per_page' for posts
Have a look here http://codex.wordpress.org/Function_Reference/get_posts
&
'number' for categories
Have a look here http://codex.wordpress.org/Function_Reference/get_categories

Solution found! I'll answer to myself, so that if anybody else needs something similar, the answer is here.
Basically, the point is to first create an array which contains all the categories. After that one can simply loop through the array. This way we were able to avoid recursively using The Loop, which probably was the biggest issue in the previous solution.
Even this solution is really slow, but an incredible improvement over the last. First idea loaded few hundred posts tops before timeout after roughly 30 seconds. This one gets the whole site (about 1500 posts) in under 5-10 seconds. The speed is awful, but with the way our site will be used and the added functionality from dividing everything to separate posts outnumbers the speed issues.
$categories = get_categories('orderby=id');
$cats_by_parent = array();
foreach ($categories as $cat) {
$parent_id = $cat->category_parent;
if (!array_key_exists($parent_id, $cats_by_parent)) {
$cats_by_parent[$parent_id] = array();
}
$cats_by_parent[$parent_id][] = $cat;
}
$posts = get_posts(['posts_per_page' => 10000000]);
$posts_by_cats = array();
foreach ($posts as $post) {
$cat_id = wp_get_post_categories($post->ID)[0];
$posts_by_cats[$cat_id] = $post->post_content;
}
// Loop through the array and print with:
echo $posts_by_cats[$cat->cat_ID];

Related

Displaying the category of posts but returning empty array

Whenever I try to get the category name of a post, it returns an empty "array". I am not proficient with PHP in WordPress, though I have tried many things to get this to work. I have tried using both get_the_category() and the_category(', '), but the latter pulls the category names and puts them entirely at the beginning of the function (it looks like it strips the div off of them entirely).
I'd like to display a list of categories that each post belongs to and still keep them within my div ID's. Strangely enough (to me), get_the_date() works perfectly fine as is, but get_the_category() doesn't.
"Array" in orange should be showing category names separated by commas (ideally):
This is the code I'm using to get the posts inside of my functions.php file.
function ctmblog_posts() {
// Query Arguments
$ctmblog_args = array(
'orderby' => 'date',
'ignore_sticky_posts' => '1',
'cat' => 8,88,87,5 // Use the category id, can also replace with category_name which uses category slug
//'category_name' => array(SLUG OF FOO CATEGORY),
);
//Loop to display 10 recently updated posts
$ctmblog_loop = new WP_Query( $ctmblog_args );
$counter = 1;
$string .= '<ul><div id="timeline">';
while( $ctmblog_loop->have_posts() && $counter < 10 ) : $ctmblog_loop->the_post();
$string .= '<div id="timeline_event"><span id="timeline_date">'. get_the_date() .'</span> — '.'<span id="timeline_category">' .get_the_category() . '</span>'.' <br><li> ' .get_the_title( $ctmblog_loop->post->ID ) . '</li></div>';
$counter++;
endwhile;
$string .= '</div></ul>';
return $string;
wp_reset_postdata();
}
//add a shortcode
add_shortcode('blog-posts', 'ctmblog_posts');
If I could get any pointers, I'd really appreciate it! This is a great learning experience for me. I've searched the web and tried solutions other people have suggested to others, but I think this might be a unique case for me.
Let's read the documentation for the get_the_category() function: https://developer.wordpress.org/reference/functions/get_the_category/
It should work, right? Let's remember that in WordPress each post can have multiple categories - this results in the function returning an array.
Code by wordpress.org user Stefano
$categories = get_the_terms( $post->ID, 'taxonomy' );
// now you can view your category in array:
// using var_dump( $categories );
// or you can take all with foreach:
foreach( $categories as $category ) {
echo $category->term_id . ', ' . $category->slug . ', ' . $category->name . '<br />';
}

php loop error for count posts in category

I have multiple categories on my wordpress page and each of the categories has 1 to n subcategories. If a subcategory contains only 1 single post I would love to display an excerpt of this post, otherwise I'll display a description of the category.
I already have the part with the "normal" categories, but there is kind of a stupid mistake regarding the "single post categories". This is what I have so far:
<?php
$args = array(
'orderby' => 'slug',
'child_of' => $cat_id,
);
$categories = get_categories( $args );
foreach ( $categories as $category ) {
$cat_count = get_category($category->cat_ID);
if($cat_count->count == 1) { ?>
<!-- Cat has only one post, display post -->
<?php } else {
<!-- Cat has multiple posts, display cat description -->
}
}
?>
Result is: I am getting the normal categories (fine!) but the first of the "single post categories" multiple times. Something might be wrong with my loop, but I don't see it. Does someone see the mistake?
There are two possible mistakes:
The category is two times in the array (Please try to var_dump it.) -> fixable with array_unique https://www.php.net/manual/de/function.array-unique.php
You forgot an echo of some debug (Somewhere - the first solution should do the trick.)
If the First Solution doesn't fix it, please post the var_dump of the array of categories.
I have a working solution now... finally!
<?php
foreach ( $categories as $category ) {
// If there is only one post available, go directly to the post
if($category->count == 1) {
$all_posts = get_posts($category);
echo '<div class="item"><h4 class="item-title">' . get_the_title($all_posts[0]->ID) . '</h4>Read more</div>';
} else {
echo '<div class="item"><h4 class="item-title">' . $category->name . '</h4>Read more</div>';
}
}
?>

Wordpress query that sorts by category and time

I have found this question:
Wordpress outside loop sort by category and time
But there is not a lot of context provided in the question or answer to know if it is applicable to me. I am using the popular genesis framework and a child theme. I don't want to modify any core WP files because they would be overwritten on updates. I think this can be done through my functions.php or front-page.php file.
I have 25 posts listed at a time. Within those 25 posts, I would like to have any post that is from category one be listed on top and those from category two listed afterwards. Within the category one and category two loops, the posts would be listed by time of entry as normal.
What would be the best way to do this?
SDS
You need two loop one for categories and one for posts.
So you can try this type of code
/*category args for listed according to name in assending order*/
$category_arg = array(
'orderby' => 'name',
'order' => 'ASC'
);
$all_cat = get_categories($category_arg);
/*Loop for all category*/
foreach ($all_cat as $key => $cat) {
/*Query for post of perticular category with orderby posted date*/
$args = array(
'cat' => $cat->cat_ID,
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'DESC',
) ;
query_posts( $args );
echo '
<div class="one-category-block">
<h1>'.$cat->cat_name.'</h1>';
echo '<ul>';
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>
';
endwhile;
echo '</ul>
</div>';
wp_reset_query();
}
Try this type of code , then let me know the result.
Thanks
All right. You won't be able to do that on the query directly, I'm afraid.
However, it's still easy to do. First, get the posts out of the query into an array:
$posts = array();
while ( have_posts() ) {
the_post();
array_push($posts, $post);
}
Then sort that array:
usort($posts, function($a, $b) {
if(has_term("mycategory", "mytaxonomy", $a->ID) && !has_term("mycategory", "mytaxonomy", $b->ID)) return -1;
if(!has_term("mycategory", "mytaxonomy", $a->ID) && has_term("mycategory", "mytaxonomy", $b->ID)) return 1;
return $b->post_date - $a->post_date;
});
I've made it so that posts having mycatgegory in the mytaxonomy taxonomy will be on top, but generally sorted by post date.
Then just use a regular foreach loop to iterate over the (now sorted) posts
foreach($posts as $post) {
setup_postdata($post);
// continue outputting the posts here
}
wp_reset_postdata();
setup_postdata() is there to make sure that you can use get_the_ID(), get_permalink() et cetera without changing your code.

Wordpress - Only display first post title in list if multiple posts have the same title

I've written a couple of shortcodes that display the titles of posts (events) per category, however I have some posts that have the same name, because they are the same event, but have a different date. These duplicate names in my list are sure to cause confusion to visitors and don't look good, so I want to only display the first post with the same name. I can't just change the names, because I have a different list that bundles posts with the same name together for a calendar. I'm using The Events Calendar btw.
So my question is: how do i apply a filter or an if statement to display only the first of a series of posts with the same title, while not impacting the display of posts without a duplicate name?
It looks a bit like this currently:
Category
- crafting
- drawing
- origami <--
- origami <--
- origami <--
- woodworking
Origami appears thrice and I want it to only appear once.
My shortcode looks like this:
extract(
shortcode_atts(
array(
'posts_per_page' => -1,
),
$atts
)
);
$args = array(
'posts_per_page' => $posts_per_page,
);
ob_start();
$events = tribe_get_events( $args );
echo '<ul>';
foreach ($events as $event) {
$parent = $event->post_parent;
if(has_term(9,'tribe_events_cat', $event) && !$parent){
echo '<li>' . $event->post_title . '</li>';
}
}
echo '</ul>';
wp_reset_query();
$retVal = ob_get_contents();
ob_end_clean();
return $retVal;
I was thinking if it is possible to check if the previous item in the loop has the same title so I added the following to the if statement, but it didn't work sadly:
$prev = get_previous_post();
if($prev->post_title != $event->post_title){
You can push the results into a new array if they are not already there... something like:
$eventsArray = array();
foreach($events as $event){
if ( in_array($event, $eventsArray) ) {
continue;
}
$eventsArray[] = $event;
}
Other way is to store all the posted title in an array and check the condition.
// create an array to store all the titles which are displyed
$previous_posts = array();
foreach ($events as $event) {
$parent = $event->post_parent;
// add extra condition to check the title is not in previous posts array
if(has_term(9,'tribe_events_cat', $event) && !$parent && !in_array($event->post_title,$previous_posts)){
echo '<li>' . $event->post_title . '</li>';
}
// store all the titles to array
$previous_posts[] = $event->post_title;
}

Display random thumbnail from each category - Wordpress

I tried posting this on the WordPress exchange, but unfortunately I didn't get any further along, so I'm trying it here. Hopefully this works!
I have a feeling that I'm on the right track, I just don't have enough solid PHP knowledge to get much further than where I'm currently at.
I'm currently using the following code to return a list of child categories from a single category:
<?php
$taxonomyName = "category";
$terms = get_terms($taxonomyName,array('parent' => 79));
echo '<ul>';
foreach($terms as $term) {
echo '<li>';
echo ''.$term->name.'<br/>';
$thumbnails = get_posts('numberposts=1&orderby=rand');
foreach ($thumbnails as $thumbnail) {
echo '<a href="' . get_permalink( $thumbnail->ID ) . '" title="' . esc_attr( $thumbnail->post_title ) . '">';
if ( has_post_thumbnail($thumbnail->ID)) {
echo get_the_post_thumbnail($thumbnail->ID, 'thumbnail');
} else {
echo 'no thumbnail';
}
echo '</a>';
}
echo '<li>';
}
echo '</ul>';
?>
This code works somewhat. It returns a list of all six sub categories under the parent, ID 79. However, I want to also return one random thumbnail in each of the list items for each of the 6 sub categories.
Unfortunately, this code returns a random thumbnail from all of my posts, not just ID 79 and it's specific child. I need it to return one thumbnail from the same category that is returned in it's parent <li>.
Additionally, the code returns "no thumbnail" if there is no code, or if I take the else out, it returns nothing. I'd like to make it to where it returns at least one image every time, so ideally there would be some kind of logic that says to always return at least one image. I just don't know how to do that.
Is there some easy way to do this? I'm thinking I need to sort through that array and return the category in the nested foreach loop, but unfortunately it's over my head.
I think I'm looking for something similar to this person, but unfortunately, they didn't get any replies. -> https://stackoverflow.com/questions/18750040/random-featured-image-based-on-category
Thanks in advance for any help!
So in order to do this, I needed to first do a for each loop, store the category slug as a variable, JAMterm, and then use that in a query to pull one random thumbnail from the category.
Thanks to #Renishkhunt for helping me along the way to get this answer.
<?php
$taxonomyName = "category";
$terms = get_terms($taxonomyName,array('parent' => 79));
echo '<ul>';
foreach($terms as $term) {
echo '<li>'.$term->name.'<br/>';
$JAMterm = $term->slug;
global $wp_query;
$term = $wp_query->queried_object;
$args=array(
'orderby' => 'rand',
'posts_per_page' => 1,
'post_type' => 'post',
'tax_query' => array(
array(
'taxonomy' => 'category',
'field' => 'slug',
'terms' => $JAMterm
)
)
);
$new_query = null;
$new_query = new WP_Query($args);
while ($new_query->have_posts()) : $new_query->the_post();
the_post_thumbnail();
endwhile;
wp_reset_postdata();
echo '</li>';
}
echo '</ul>';
?>

Categories