Show posts in category that match username - php

This is fixed thanks to Alex's answer below.
So this is a bit of a weird one. I am setting up so I have category's with names "cat1, cat2, cat3" etc.
And say I had users called "cat1, cat2, cat3" so they matched the same as the category names.
I am then wanting to somehow only show the posts to the user that relates to their category, so basically if USER: "cat1" is logged in then they could only see the posts in category "cat1" as it matches their username.
I know you can do this to show posts only that the current user logged in has made but this wont work as the way the posts get put into the category complicated to explain.
<?php
// The Query
$args = array(
'post_status'=> '.....'
);
global $user_ID;
get_currentuserinfo();
if($user_ID) {
query_posts( $args,"author=$user_ID" );
}
?>
So if anyone has any insight into only showing posts to a user that matches a category with the same name as the user logged in hopefully they will be kind enough to help out.

It seems like you've started a round-about way of getting this accomplished. Since you have categories already set up with the username, you should just be able to place that in your query
//Get User -> ID -> Cat
global $current_user;
get_currentuserinfo();
$args = array(
category_name => $current_user->ID
); //or use $current_user->display_name if that's how they are set up.
// The Query
$the_query = new WP_Query( $args );
// The Loop
while ( $the_query->have_posts() ) : $the_query->the_post();
//Display your loop how you want
endwhile;
// Reset Post Data
wp_reset_postdata();
EDIT:
did you do var_dump($current_user->ID) to see if it matches the category name? That variable from the object might only contain an ID (like "1" or "178" etc). If that was the case, you'd need something like
$the_cat_name = 'category' . $current_user->ID;
//Append your 'naming structure' to the front of the user ID
Then just replace the array with
$args = array(
category_name => $current_user->ID
);
Alternatively, look at the Current User Functions (here). You may be able to use
$current_user->user_login
instead. You could also just try var_dump($current_user) (after calling global $current_user; get_currentuserinfo();) and see what variable contains the string you need

Related

A complicated query combining a WP Courseware function, ACF repeater fields and a meta_query looking for a particular template file

I have a pretty complicated query that I have not been able to get to work the way I need it to.
I have a Wordpress install using the plugins WP Courseware and ACF. I need to display a page of courses associated with the current user. I want the links to lead the user to the course "home" pages that the user should hit prior to starting the course. I have created course "home" pages, but the problem is WP Courseware has no way to associate a page with a course. So I had to use an ACF options repeater that associates the course ID with whatever course pages are necessary. The only way I know that one of those associated pages is the course "home" page is by the template I use for course home pages.
So the loops within loops need to first determine what courses the current user has access to, get those course IDs, loop the ACF options repeater to find the pages associated with those course IDs, then of those pages loop to find out which one (there is only one per course) uses the course home page template. This last loop I discovered needs to be a WP_Query loop as that's the only way to query for a Wordpress template.
I am lost in loops and I'm having the hardest time. I thought it might be simpler and most direct to use the WP_Query to query an array meta_queries of both the Wordpress template and the ACF repeater (to determine is the ACF repeater course ID matches the course ID the user has access to) but my attempts at querying ACF repeater sub fields is not working.
Here's my code:
$user = wp_get_current_user();
$user_id = $user->ID;
$user_course_list = WPCW_users_getUserCourseList($user_id);
$course_association_arr = get_field('course_association', 'option');
// Loop through user's courses
foreach ( $user_course_list as $user_course ) :
$course_id = $user_course->course_id;
$course_title = $user_course->course_title;
// Loop through the ACF course ID/page associations
foreach ( $course_association_arr as $course_association ) :
$assoc_course_id = $course_association['wp_courseware_id'];
if ( $course_id == $assoc_course_id ) :
// Loop through the ACF associated pages
foreach ( $course_association['associated_pages'] as $associated_page ) :
$page_id = $associated_page->ID;
$page_url = $associated_page->guid;
echo '<li>'. $course_title . '</li>';
endforeach;
endif;
endforeach;
endforeach;
This displays all pages associated with a user's courses, not just the ones using the course home template. I somehow have to incorporate a WP_Query with these args in there and nothing I have done has worked:
$args = array(
'post_type' => 'page',
'meta_query' => array(
array(
'key' => '_wp_page_template',
'value' => 'page-course-home.php',
),
)
);
If I could somehow turn the WP query into an if statement (if template = page-course-home.php) I could have that inside the associated pages query to only show course home pages. Or there maybe another more brilliant way to do what I need to do. I appreciate all feedback.
Ok I got something to work! I think spending so much time framing the question here helped me see one way I could do it:
$user = wp_get_current_user();
$user_id = $user->ID;
$user_course_list = WPCW_users_getUserCourseList($user_id);
$course_association_arr = get_field('course_association', 'option');
// Loop through user's courses
foreach ( $user_course_list as $user_course ) :
$course_id = $user_course->course_id;
$course_title = $user_course->course_title;
// Loop through the ACF course ID/page associations
foreach ( $course_association_arr as $course_association ) :
$assoc_course_id = $course_association['wp_courseware_id'];
if ( $course_id == $assoc_course_id ) :
// Loop through the ACF associated pages
foreach ( $course_association['associated_pages'] as $associated_page ) :
$page_id = $associated_page->ID;
$page_url = $associated_page->guid;
$args = array(
'post_type' => 'page',
'page_id' => $page_id,
'meta_query' => array(
array(
'key' => '_wp_page_template',
'value' => 'page-course-home.php',
),
)
);
$course_assoc_pages = new WP_Query( $args );
if( $course_assoc_pages->have_posts() ) :
while ( $course_assoc_pages->have_posts() ) : $course_assoc_pages->the_post();
echo '<li>'. $course_title . '</li>';
endwhile;
endif;
wp_reset_query();
endforeach;
endif;
endforeach;
endforeach;
This seems a bit cumbersome, but it works. I'm not sure if it would be better but it seems more elegant to incorporate the ACF subfield query into the meta query, so could eliminate two of the loops. If anyone has any thoughts on this I would love to hear them.

WordPress - Getting Posts by User Role, combining two queries into one

I am building a website where certain users will be "premium" and certain users will be non premium. Both roles will be able to make posts, but in our post queries, we would like all posts made by "premium" users to be returned first, with a css class of "premium", and then all non-premium posts returned after.
I need to do so in a way that preserves pagination.
I have the following query which I can use to return posts by user role:
<?php $premiums = get_users( array( 'role' => 's2member_level1, administrator' ) );
$premium_ids = array();
foreach( $premiums as $premium )
$premium_ids[] = $premium->ID;
$posts = new WP_Query( array( 'author' => implode( ',', $premium_ids ), 'post_type' => 'classifieds', 'paged' => get_query_var('paged') ) );
if ( $posts->have_posts() ) : while ( $posts->have_posts() ) : $posts->the_post();
// The post title, content, etc, encase in a PREMIUM css class
endwhile;
endif;
wp_reset_postdata(); ?>
The two roles specified above are our "premium" roles so all their posts should be returned first. The non premium roles use the "subscriber" role provided in WordPress.
For the non-premium posts, I was going to do a second query swapping out the role as needed, but I realized this would break pagination, or at least stop pagination from working in the traditional way.
Therefore, it seems to be clear that I need to have everything in a single query.
From reading posts such as the following, I know its possible to merge two queries into one, but I am not sure if this would be the best way to go.
https://wordpress.org/support/topic/multiple-queries-compiling-into-one-loop
Therefore, I am posting the question here to see if anyone might know of a way to query our premium users, return their posts, then query the non premium users and return their posts, all in one single query with a "premium" class on premium posts and a "non-premium" class on the non premium ones.
This is more of a PHP issue than a WordPress one I feel, so I have tagged this question as PHP first and WordPress second.
Hope someone can help.
Thanks
As nobody seems to have any solution for this, I had to solve it with jQuery which was/is not ideal.
My solution was to query the user role in each returned post and then use this as a var to assign a unique class to all "premium" posts. Then I use jQuery to move all premium posts to the top, into an empty div.
The empty div goes before the loop:
<div class="all-premium-posts"></div>
Then in the loop:
if(have_posts()): while(have_posts()):the_post();
$user_id = $author_id;
$user = new WP_User( $user_id );
if ( !empty( $user->roles ) && is_array( $user->roles ) ) {
foreach ( $user->roles as $role )
if($role == 's2member_level1') {
$premium_post = 'premium-post';
}
}
And then on each post in the loop:
<div class="post <?php echo $premium_post;?>">
And then the jQuery:
jQuery('.premium-post').prependTo('.all-premium-posts');
The severe disadvantage of this is that I have to return all posts on one page.
If there are hundreds of posts returned, it would cause a huge DB query and page load time.
It works for us though as we auto-prune posts every 30 days, so posts per category / posts per page should never exceed 20-30 at most for us, thus making this a workable/usable solution in this scenario.

IF author is author of Post then do something?

I want to write some simple code to figure out if the user is the author of any posts (Not if their role is author)
My attempt is as follows but I can't figure it out
I got the userID (set it to current in global header)
I have created a query to for custom-post-type and author
I have got all the current posts from the query
I have added an IF statement (Which I CANT seem to get right)
Here is my code try
<?php
// Global variable for current user ID
$user_ID;
// Create a new WP query object
$my_query = new WP_Query( array(
'post_type' => 'farmers',
'author' => $user_ID
));
// Get all the current user posts from the query object
$posts = $my_query->posts;
IF There are Posts (Not sure how to write this line) {
// Do something
} else {
// Do Something else
} ?>
Thanks for any help guidance
How about:
if( $posts ) {
// Do something
}
else {
// Do Something else
}

Query all wordpress post titles

I am using Wordpress auto suggests using this snippet of code
and currently it is searching all tags, I want it to search only post titles. Any help is appreciated.
This is sql query calling all the tags which needs to be modified for all posts.
<?php global $wpdb;
$search_tags = $wpdb->get_results("SELECT name from wp_terms WHERE name LIKE '$search%'");
foreach ($search_tags as $mytag)
{
echo $mytag->name. " ";
}
?>
These days i had to do some request in a wordpress theme.
In your case ( getting title can be done easier than getting tags, as in your example link ) the stuff can be done easier (i guess).
Firstly you have to make a php page to get posts. As you maybe know you won't be able to use wp stuff in standalone php files, so your file ( let call it get_posts.php ) will look like
<?php
// Include the file above for being able to use php stuff
// In my case this file was in a folder inside my theme ( my_theme/custom_stuff/get_posts.php ).
// According to this file position you can modify below path to achieve wp-blog-header.php from wp root folder
include( '../../../../wp-blog-header.php' );
// Get all published posts.
$list_posts = get_posts( array( 'numberposts' => -1 ) );
// Get "q" parameter from plugin
$typing = strtolower( $_GET["q"] );
//Save all titles
$list_titles = array();
foreach( $list_posts as $post ) { $list_titles[] = $post->post_title; }
// To see more about this part check search.php from example
foreach( $list_titles as $title ) {
if( strpos( strtolower( $title ), $typing ) ){
echo $title;
}
}
?>
I added some comments trying to help you better.
Now stuff get easy, you only have to call your page through jQuery plugin like
$('#yourInput').autocomplete( "path_to/get_posts.php" );
You can directly use wordpress in-build feature to get all post titles
// The Query
query_posts( 'posts_per_page=-1' );
// The Loop
while ( have_posts() ) : the_post();
echo '<li>';
the_title();
echo '</li>';
endwhile;
None of the answers here answer your real question:
How to query JUST post titles
The "raw SQL" way:
Few important things:
escape search for SQL! (also do that for the tags search!) use $GLOBALS['wpdb']->esc_like()
if you only need 1 column, you can use $GLOBALS['wpdb']->get_col()$GLOBALS['wpdb']->get_results() is if you want to fetch more columns in one row
use $GLOBALS['wpdb']->tableBaseName to make your code portable - takes care of the prefixe.g. $GLOBALS['wpdb']->posts
When querying posts you must also think about which post_type and post_status you want to query=> usually the post_status you want ispublish, but post_type may vary based on what you want
WordPress table "posts" contains ALL post types - post, page, custom, but also navigation, contact forms etc. could be there! => I strongly advice to use explicit post_type condition(s) in WHERE ! :)
...$GLOBALS is same as globalizing variabl -today performance difference is little
<?php
// to get ALL published post titles of ALL post types (posts, pages, custom post types, ...
$search_post_titles = $GLOBALS['wpdb']->get_col(
"SELECT post_title from {$GLOBALS['wpdb']->posts}
WHERE (
(post_status = 'publish')
AND
(post_title LIKE '{$GLOBALS['wpdb']->esc_like($search)}%')
)
ORDER BY post_title ASC
"); // I also added ordering by title (ascending)
// to only get post titles of Posts(Blog)
// you would add this to conditions inside the WHERE()
// AND (post_type = 'post')
// for Posts&Pages
// AND ((post_type = 'post') OR (post_type = 'page'))
// test output:
foreach ($search_post_titles as $my_title) {
echo $my_title . " ";
}
?>
The WP_Query way
This is more wordpress but has a little overhead, because although there is a fields param for new WP_Query()/get_posts(), it only has options:
'all' - all fields (also default), 'ids' - just ids, 'id=>parent' - ... if you pass anything else, you still get all, so you still need to add "all" BUT - WP however has filters for altering fields in SELECT.
I tried to make it the same as the raw SQL version, but it depends on how does WP does it's "search" - which I think is %search% for 1 word + some more logic if there are more words. You could leverage the $clauses filter used for fields to also add your custom where INSTEAD of adding the 's' into $args (remember to append to not-lose existing WHEREs $clauses['where' .= "AND ...;). Also post_type => 'any' does not produce always the same results as the raw query in cases like Navigation, Contact forms etc...
Also WP_Query sanitizes the input variables so actually don't escape $args!
<?php
$args = [
'fields' => 'all', // must give all here and filter SELECT(fields) clause later!
'posts_per_page' => -1, // -1 == get all
'post_status' => 'publish',
's' => $search,
// I also added ordering by title (ascending):
'orderby' => 'title',
'order' => 'ASC',
'post_type' => 'any', // all "normal" post types
// 'post_type' => 'post', // only "blog" Posts
// 'post_type' => ['post', 'page'], // only blog Posts & Pages
];
$onlyTitlesFilter = function($clauses, $query) {
// "fields" overrides the column list after "SELECT" in query
$clauses['fields'] = "{$GLOBALS['wpdb']->posts}.post_title";
return $clauses; // !FILTER! MUST RETURN!
};
$onlyTitlesFilterPriority = 999;
// add filter only for this query
add_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority, 2);
// Pro-tip: don't use variable names like $post, $posts - they conflict with WP globals!
$my_posts = (new WP_Query($args))->get_posts();
// !IMPORTANT!
// !remove the filter right after so we don't affect other queries!
remove_filter('posts_clauses', $onlyTitlesFilter, $onlyTitlesFilterPriority);
// test output:
// note that I used "my"_post NOT just $post (that's a global!)
foreach($my_posts as $my_post) {
echo $my_post->post_title . " ";
}
?>
Don't be confused - you will still get the array of WP_Posts - WP will throw some default properties&values into it, but in reality it will only query and fill-in with real values the fields you specify in the filter.
PS: I've tested these - they are working codes (at least on WP 5.4 and PHP7 :) )

Ordering Wordpress posts based on parent category

UPDATE: I have tried using the following code:
<?php if (is_category(events)) {
$posts = query_posts($query_string . '&orderby=event_date&order=desc');
} else {
$posts = query_posts($query_string . '&orderby=title&order=asc');
}
?>
Is there any reason why that wouldnt work? It seems to work fine organising posts in alphabetical order, but still no luck on the date order within 'events'.
--
After searching through various existing questions I can't quite find a solution to what I am trying to do.
Currently all posts on my site are ordered alphabetically, which is fine except for one new category that I have added. For this category I want to order all posts by a value that I enter into a custom field. The field is called 'event_date' - so I want to order the posts by date essentially, but not the date the post was created, the date the user manually enters into this field.
I managed to get it working by using:
<?php if (is_category($events)) { $posts = query_posts($query_string . '&orderby=$event_date&order=asc'); } ?>
However this overrides the aphabetical order for all other pages.
For alphabetical order I am using:
<?php if (is_category()) { $posts = query_posts( $query_string . '&orderby=title&order=asc' ); } ?>
Essentially I want a statement that tells the page to order all posts in aphabetical order, unless the category is 'events', where I want to order them by the custom event date.
As you can probably tell I'm very much front end, not back end so a lot of this is fairly new to me, so any help or advice is appreciated.
To order posts by a custom field value, you need add the custom meta field to the query itself. orderby=meta_value in addition to meta_key=metafieldid will allow ordering in this fashion.
I would use the pre_get_posts hook and modify the query object if get_query_var( "cat" ) (or a similar query var) returns the desired post category.
add_action( "pre_get_posts", "custom_event_post_order" );
function custom_event_post_order( $query )
{
$queried_category = $query -> get_query_var( "cat" );
/*
* If the query in question is the template's main query and
* the category ID matches. You can remove the "is_main_query()"
* check if you need to have every single query overridden on
* a page (e.g. secondary queries, internal queries, etc.).
*/
if ( $query -> is_main_query() && $queried_category == 123 )
{
$query -> set( "meta_key", "event_date" ); // Your custom field ID.
$query -> set( "orderby", "meta_value" ); // Or "meta_value_num".
$query -> set( "order", "ASC" ); // Or "DESC".
}
}
Remember that this approach overrides all queries that are using the category in question. You can build custom WP_Query objects that use their own parameters for constructing loops.
You also should standardize the way you save the custom field data to the database. For dates I prefer using UNIX-timestamp formatted times that are easy to move around and manipulate. This way no accidents happen when querying and some data is formatted in another way that the rest is.
Disclaimer: I did not have the time to test the above code in action, but the general idea should work properly.
EDIT: of course the above code should be inserted to functions.php or a similar generic functions file.
What about:
<?php $posts = query_posts($query_string . (is_category($events)?'&orderby='.$event_date:'&orderby=title') . '&order=asc'); ?>
<?php
$recent = new WP_Query(“cat=ID&showposts=x”);
while($recent->have_posts()) : $recent->the_post();
?>
Hopefully I understood your question, use the WP_Query and within the orderby add a space between your order by columns:
$args = array(
'posts_per_page' => 100,
'orderby' => 'title',
'order' => 'ASC',
);
if(is_category($events)){
$args['orderby'] .= " meta_value_num";
$args['meta_key'] = 'event_date';
}
$posts = (array) new WP_Query( $args );

Categories