Sorting WP user columns by non-meta value (PHP) - php

UPDATE: I've read a few more posts about similar issues and the consensus seemed to be that filtering by the actual data in the user admin table isn't an option, and that sorting needs to be done via adding the data to postmeta if it isn't there already. Hoping this isn't the case, but it's starting to sound like it.
I have added a handful of custom columns to the user admin table. Some of the columns get their values from custom user meta, but some do not. I've been able to make the columns that source their content from meta just fine with
if ( 'member_number' == $query->get( 'orderby' )) {
$query->set( 'orderby', 'meta_value' );
$query->set( 'meta_key', 'number' );
}
...but the column I'm unable to sort a column that gets its values by cross-referencing the user's info against entries from a Gravity Form, sorting the GF entries by date, and outputting the position of the GF entry that was matched to the user.
It might be simpler to just say that I want to display a "wait-list position" that can change frequently and would require updating postmeta of ~100 posts on a regular basis to accurately display the users position in the queue. Not thinking that was practical to do, the best I could come up with is to reference the user's email address against the list of those on the wait-list.
If it helps, the code that references my custom function and applies it to my column is:
if ('waitlist_pos' == $column_name){
$waitlistNumber = get_waitlist_position( $user_id );
$value = $waitlistNumber;
return $value;
}
...and my function to get those values is:
function get_waitlist_position( $user_id ){
$waitlistUser = get_user_by( 'id', $user_id);
if ( empty( $waitlistUser ) ) {
return;
} else {
$waitlistUserEmail = $waitlistUser->user_email;
$form_id = '18';
$entries = GFAPI::get_entries($form_id);
usort($entries, make_comparer('date_created'));
$emails = array_column( $entries, '3' );
$waitlistposition = array_search( $waitlistUserEmail, $emails );
if ( !in_array( $waitlistUserEmail, $emails, true )) {
return;
}
}
return $waitlistposition +1;
}
Only a few percent of users are on the waitlist.
I've managed to get the custom column created and to display the appropriate wait-list position of the user in the user admin table, but every guide I've found on making the column's content sortable either describe default WordPress sortable criteria, or by a meta query like I've done for other columns in the code above.
Any thoughts on simply sorting these columns by their value if the value does not actually exist as user meta or user data? The values are simple integers, starting from 1 and going to 100 or so.
I've tried leaving the created column alone, and although it does have the arrows indicating it is sort-able, clicking it does not change the order of the entries, and trying to force a query like the WP_Query used earlier, of course, results in a blank table once I try to sort.
Thanks for reading the long question about my simple problem! Also happy to hear if making the wait-list position into some sort of dynamic post-meta may make more sense.

Related

Sorting meta field values and select the lowest to store in an other meta field WordPress

What I tried to do:
I have several custom meta field in a custom post type. I want to retrieve the value of all the meta field with the name 'prix-du-produit' for the 'bons-plans' post type, compare them and store the lowest one inside another meta field named 'prix-promo' and do the same thing for the link attached. All of this should happen when the post is saved, published or updated.
It's basically a tool to select the best price of a product to later display it on front end with the corresponding link to the product. For now this isn't working at all and I'm all out of answer.
What I manage to understand or not
As I understood, using usort() is the best way to proceed since it will sort each array inside the first one, which is perfect for what I tried to achieve as it will allow me to select the link within corresponding to the lowest 'prix-du-produit' value. I also understood that using the publish_post hook should do the trick.
The (crappy) code:
function compare_prices($price1, $price2){
if($price1['prix-du-produit'] == $price2['prix-du-produit']){
return rand(0,1) ? 1 : -1//if it is the same then it is random
}
return $price1[0]['prix-du-produit'] > $price2[0]['prix-du-produit'];
// if not it sorts the array
}
function best_product( $id, $post ) {
if ( get_post_type($post->ID) = 'bons-plans' ) {
$products = get_post_meta( $post->ID, 'liens-produits' );
usort($products, 'compare_prices');
$lowest_price = $products[0]['prix-du-produit'];
$best_link = $products[0]['lien-du-produit'];
update_post_meta( $post->ID , 'lien-affilie' , $best_link);
update_post_meta( $post->ID , 'prix-promo' , $lowest_price);
}
}
add_action( 'publish_post', 'best_product', 10, 2 );
Keep in mind that I am still very new to PHP, so for those who are able to give me hint on what I did wrong will have to give me a precise answer.

Dynamic URLs in WordPress

Background
I'm building a course catalog for a school and am trying to make friendly, dynamic URLs. It has three custom post types:
catalog.
course. This post type contains a title, course number, and course description.
section. This post type contains a cost, start and end dates and times, etc. A section is an instance of a course; for example, there might be two sections of Drawing for Beginners, one on Thursday morning and one on Monday night and taught by two different faculty.
There is a one-to-many relationship between course and section. When viewing a section, it displays the parent course's course name, course number, and course description. It also displays that section's cost, start and end dates and times, etc.
The current URL for a section is this:
http://website.org/section/section-slug/
I would like it to be this:
http://website.org/class/spring-2019/drawing-for-beginners/01/
...where "class" is a 'virtual' folder / synthetic prefix
...where "spring-2019" corresponds to a "catalog" custom post type
...where "drawing-for-beginners" corresponds to a slug for the parent "course" custom post type
...where "01" corresponds to the section of the course.
WordPress should display the section post type that matches these criteria.
Research
I've read quite a bit about both the Rewrite API and the Endpoints API. The best article I could find on a topic closest to what I'm trying to accomplish is this one. Sadly, the example code on the page didn't work for me, resulting in a "too many redirects error." I can provide more details about exactly which portion didn't work, if desired. I also read this article on Make WordPress Plugins but it doesn't cover dynamic lookups.
What I'm trying to accomplish
http://website.org/class/spring-2019/drawing-for-beginners/01/
When the virtual URL is supplied to WordPress, I need the system to perform a query to look up the section whose number is "01" and which belongs to the "spring-2019" catalog and whose parent course has a slug of "drawing-for-beginners." That query isn't a challenge, it's all of the hooks that need to be called to execute that code and return the correct template (for the section page). I'm not sure whether I need to create an Endpoint or can just get away with adding rewrite rules.
Can someone offer some guidance?
--
As a "bonus," I'm also trying to accomplish this:
http://website.org/class/spring-2019/drawing-for-beginners/01/faculty_name
...where "faculty_name" is dynamic and is the name of the person teaching that section (and corresponds to a "faculty" custom post type).
http://website.org/class/spring-2019/drawing-for-beginners/01/gallery
...where "gallery" is a static name and shows a gallery custom post type.
After much investigation, I've found an answer to my question. Here it goes.
This is how to create truly dynamic URLs / slugs in WordPress. The URLs don't correspond to a page. Instead, the parts of the slug are used to look up a post ID and then render that post accordingly.
Step 1: Add the rewrite rule
function pce_rewrite_rules ( ) {
add_rewrite_rule ( '^class/([^/]*)/([^/]*)/([^/]*)/?', 'index.php?post_type=section&catalog_name=$matches[1]&course_name=$matches[2]&section_no=$matches[3]','top' ) ;
add_action ( 'init', 'pce_rewrite_rules', 10, 0 ) ;
Step 2: Register the query variables
function pce_register_query_vars ( $vars ) {
$vars[] = 'course_name';
$vars[] = 'catalog_name';
$vars[] = 'section_no';
return $vars;
}
add_filter ( 'query_vars', 'pce_register_query_vars' );
Step 3: Modify the WP query
Use pre_get_posts to modify the main query. But you have to force some variables in the query so that WordPress loads the template that you need. To find the variables I needed to manually set, I used a WP plugin (Query Monitor) to examine the contents of the WP query, and I used var_dump on the type of post I wanted to "copy."
function pce_dynamic_section_lookup ( $wp ) {
if ( is_admin() || ! $wp->is_main_query() ){
return;
}
if ( $wp->is_main_query() ) {
// Only defined if we're looking at a "fake" URL.
// Example: http://pce.local/class/spring-2019/handmade-books/01/
if ( get_query_var ('course_name' ) ) {
// These are some of the variables I needed to set manually.
$wp->query_vars['post_type'] = 'section' ;
$wp->query_vars['is_single'] = true ;
$wp->query_vars['is_singular'] = true;
$wp->query_vars['is_archive'] = false;
$course_name = get_query_var ('course_name' ) ;
$catalog_name = get_query_var ('catalog_name' ) ;
$section_no = get_query_var ('section_no' ) ;
// More code is here to look up the post ID I need.
// Set the post ID here. This makes the magic happen.
$wp->query_vars['p'] = $post_id ;
// This also makes the magic happen. It forces the template I need to be selected.
$wp->is_single = true ;
$wp->is_singular = true ;
$wp->is_archive = false ;
$wp->is_post_type_archive = false ;
}
}
}
add_action ( 'pre_get_posts', 'pce_dynamic_section_lookup', 0, 2 ) ;
I had a post with this original URL:
http://pce.local/section/handmade-books-01/
And now I can load it at this URL (and it loads it, it does not forward it):
http://pce.local/class/spring-2019/handmade-books/01/
I needed to do this because multiple sections are going to be added in future catalogs and I wanted to keep the URLs friendly. In the summer if the class is offered, it will be...
http://pce.local/class/summer-2019/handmade-books/01/
Instead of...
http://pce.local/section/handmade-books-01-2/
or whatever slug WordPress assigns it. Having only a couple of sections isn't a big deal, but there will be several in the future.
If i understood good, this might help you.
I am not sure how did you make relationship but i will put the code that i usually use. And lets say that catalog-course also have a relationship.
function add_rewrite_rules( $wp_rewrite )
{
$section_rules = array(
'class/(.+?)/?$' => 'index.php?post_type=post&name='. $wp_rewrite->preg_index(1),
);
$wp_rewrite->rules = $section_rules + $wp_rewrite->rules;
}
add_action('generate_rewrite_rules', 'add_rewrite_rules');
function change_section_links($post_link, $id=0){
$courses = new WP_Query( array(
'post_type' => 'course',
'post__in' => get_post_meta( $catalog_id, '_course', true ),
) );
if ( $courses-> have_posts() ) { while ( $courses->have_posts() ) {
$courses->the_post();
$catalog_name = get_the_title();
}
$sections = new WP_Query( array(
'post_type' => 'section',
'post__in' => get_post_meta( $course_id, '_section', true ),
) );
if ( $sections-> have_posts() ) { while ( $sections->have_posts() ) {
$sections->the_post();
$course_name = get_the_title();
}
$post = get_post($id);
if( is_object($post) && $post->post_type == 'section'){
return home_url('/class/'. $catalog_name. '/'. $course_name. '/'. $post->post_name.'/');
}
return $post_link;
}
add_filter('post_link', 'change_section_links', 1, 3);
I hope that it would help you. If it doesnt, tell me how did you make relationship.

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.

Dynamically pre-populate Gravity Forms field with custom fields from custom post types

Tried to be as specific as possible in the title. Essentially I have a real estate site that I am working on that has property listings. The property listing is a custom post type and there are several other custom post types (each with their own custom fields) attached to it.
Each property has an agent (custom post type) attached to it with custom fields such as email, facebook, phone number, etc.
I need to dynamically pre-populate a hidden field on Gravity Forms with the agent email (which is NOT the same as the author email) so that I can send an email to that address.
I have tried the following with no luck because I'm sure something is missing to call the custom field from the Agent custom post type, but I'm not sure how. This is what I'm working with so far:
add_filter('gform_field_value_agentemail', 'populate_post_agent_email');
function populate_post_agent_email($value){
global $post;
$agents_email = get_post_meta($post->ID, 'agent_email', true);
return $agents_email;
}
I have added the parameter name "agentemail" to the gravity form field. If anyone knows what I am missing to be able to get this field (or any field from the agent custom post) into this form, it would be much appreciated.
Thanks.
Here's How I Populated my GravityForms Dropdown using a little code that I found created by Joshua David Nelson, josh#joshuadnelson.com
With a few minor modifications I was able to get the proper output to the dropdown box (was looking for user email addresses instead of user nicenames, but you can modify this script to output anything you want with a few small changes to the query args)
// Gravity Forms User Populate, update the '1' to the ID of your form
add_filter( 'gform_pre_render_1', 'populate_user_email_list' );
function populate_user_email_list( $form ){
// Add filter to fields, populate the list
foreach( $form['fields'] as &$field ) {
// If the field is not a dropdown and not the specific class, move onto the next one
// This acts as a quick means to filter arguments until we find the one we want
if( $field['type'] !== 'select' || strpos($field['cssClass'], 'your-field-class') === false )
continue;
// The first, "select" option
$choices = array( array( 'text' => 'Just Send it to the Default Email', 'value' => 'me#mysite.com' ) );
// Collect user information
// prepare arguments
$args = array(
// order results by user_nicename
'orderby' => 'user_email',
// Return the fields we desire
'fields' => array( 'id', 'display_name', 'user_email' ),
);
// Create the WP_User_Query object
$wp_user_query = new WP_User_Query( $args );
// Get the results
$users = $wp_user_query->get_results();
//print_r( $users );
// Check for results
if ( !empty( $users ) ) {
foreach ( $users as $user ){
// Make sure the user has an email address, safeguard against users can be imported without email addresses
// Also, make sure the user is at least able to edit posts (i.e., not a subscriber). Look at: http://codex.wordpress.org/Roles_and_Capabilities for more ideas
if( !empty( $user->user_email ) && user_can( $user->id, 'edit_posts' ) ) {
// add users to select options
$choices[] = array(
'text' => $user->user_email,
'value' => $user->id,
);
}
}
}
$field['choices'] = $choices;
}
return $form;
}
/* end of populate advisors for dropdown field */
To get this to work all you should need to do is add the above code to your functions.php file, add the 'ID' (into the add_filter reference) of the GravityForm that you're looking to alter and add the 'Class' of your dropdown field (where is says 'your-field-class').
If you have any questions about the above code, let me know.
Adam
I'm working on this one right now - I was able to pass the values from one page to another appending the information onto the end of the url -
ex. http://www.your-website.com/?agentemail=agent#email.com
For this to work you have to check the 'Allow this field to be populated Conditionally' when editing the field in question.
It's not the be-all-end-all for me (I'd like to generate this on page load, rather than attaching it to a button, but it's a start. I'll comment again when I have the filtering worked out.
Adam

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