Home › Toolset Professional Support › [Resolved] View to provide counts of the number of times a field has specific values
This is the technical support forum for Toolset - a suite of plugins for developing WordPress sites without writing PHP.
Everyone can read this forum, but only Toolset clients can post in it. Toolset support works 6 days per week, 19 hours per day.
No supporters are available to work today on Toolset forum. Feel free to create tickets and we will handle it as soon as we are online. Thank you for your understanding.
Sun | Mon | Tue | Wed | Thu | Fri | Sat |
---|---|---|---|---|---|---|
- | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | 9:00 – 13:00 | - |
- | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | 14:00 – 18:00 | - |
Supporter timezone: Asia/Karachi (GMT+05:00)
This topic contains 21 replies, has 2 voices.
Last updated by Waqar 1 year, 10 months ago.
Assisted by: Waqar.
We have a custom post type called Rides. Within this post type, we have custom fields for Ride Contact and Ride Sweep. These two fields give the names of the leader for each ride and the person that rides at the back of the ride to make sure nobody gets left behind.
We would like to set up a view that will display the following:
Header = Number of Rides Led or Swept
Fields = Name and then a numerical count of the occasions that name was present in either the Ride Contact or Ride Sweep field sorted in descending order.
This would produce output like this:
Name #1 - 15
Name #2 - 12
Name #3 - 10
Name #4 - 9
Name #5 - 2
Name #6 - 1
where the number would be a combined total of the times that name was present in either field and the names in Ride Contact and the names in Ride Sweep would be combined together for a single list.
Or, if it would be easier this way, we would be fine with the following:
Header = Number of Rides Led
Fields = Name and then a numerical count of the occasions that name was present in the Ride Contact field sorted in descending order.
Header = Number of Rides Swept
Fields = Name and then a numerical count of the occasion that name was present in the Ride Sweep field sorted in descending order.
This would have the same output structure, but the names in the first list would ONLY be from the Ride Contact field and the names in the second list would ONLY be from the Ride Sweep field.
I'm not sure how to do this because we're not actually displaying the rides themselves and we're not doing the counts on the number of rides total that are displayed, but instead the number of rides led by each individual in the two fields.
We already have successfully set up a view that displays a list of all rides and can be filtered by Ride Contact or Ride Sweep. So we can get this info for each individual that way. That view can be seen here:
hidden link
But if we have 50 Ride Contacts, for example, we'd have to use this search filter 50 times to get counts for each. That's better than having to count them all ourselves, but if we could just have a list with the number for each Ride Contact and Ride Sweep, that would be even better. I'd know how to do this using [wpv-loop-index] if I wanted the number of total rides displayed with the view the way we have it set up on the existing view. But I don't know how to do it to get a count for each individual based on the number of times each name is present within these two fields.
Please let me know if what we're going for is doable or if you need further clarification on this and thanks in advance for whatever assistance you can provide.
Hi,
Thank you for contacting us and I'd be happy to assist.
Based on the requirements that you've shared, here is what I'll recommend:
1. If you're not already doing this, the first step would be to create and maintain the list of riders that can be used in the 'Ride Contact' and 'Ride Sweep' fields.
This will have 2 main benefits:
a). Data entry and consistency benefit, as the user/admin won't have to manually type the names in these fields each time.
b). It will be possible to loop through all the riders so that their participation number/count can be shown.
So to achieve this, you can add a new custom post type "Riders" and enter all riders as separate posts in this post type.
2. Next, you can remove the 'Ride Contact' and 'Ride Sweep' fields and add them back again as the 'select' type custom fields. The options of these fields can then be programmatically generated from the new "Riders" post type, using the 'wpt_field_options' filter:
https://toolset.com/documentation/programmer-reference/types-api-filters/#wpt_field_options
Example thread with an example code snippet of this filter's usage:
https://toolset.com/forums/topic/cpt-call-field-in-a-second-cpt/#post-2207723
As a result, whenever a selection is made for the 'Ride Contact' and 'Ride Sweep' fields in the "Rides" post type, the respective "Rider" post's ID will be stored in those fields.
3. Once the Rides and the Riders data has been stored in this structure, you can create two classic/legacy post views to show the count of each rider's participation:
a). The parent view will be set to show the list of all the "Riders" posts
b). Inside the loop of the parent view, you can show a nested child view that will show "Rides" posts. But with a query filter for the 'Ride Contact' and 'Ride Sweep' fields. So that only posts where the value for any of those fields is the same as the current parent post's ID (rider).
As you only need the count from this child view, the loop of this view will be empty and this view will only return the count through the "wpv-found-count" shortcode:
https://toolset.com/documentation/programmer-reference/views/views-shortcodes/#wpv-found-count
I hope this helps and please let me know if you have any follow-up questions.
regards,
Waqar
I simultaneously like this approach and don't like it. 😉 It's a lot more work than I was expecting/hoping for, but I recognize it's the best way to do it and will make things more flexible for future things we might decide we want to display related to Rides & Ride Leaders/Sweeps.
Thanks a bunch for the logic and confirmation that it is doable. Please keep this ticket open while I do everything to accomplish this in case I run into any roadblocks along the way. It's probably going to take me a bit to create all the new Ride Leader posts under the new content type. We'll go with Ride Leader as the content type because we have many Riders that are not Contacts or Sweeps and we may decide we need a separate Rider content type for some future need.
OK, I have now created the new Ride Leader content type. I also added custom fields to that content type that were previously in the Rides content type for Ride Contact Phone, Ride Contact Email, and Ride Contact Website. I decided to make the Ride Contact and Ride Sweep option into a custom taxonomy within Ride Leader. That way Ride Contact and Ride Sweep are both still under the Ride Leader umbrella.
I added the following as custom code:
------------------------------------------------------------
add_filter( 'wpt_field_options', 'func_to_dynamically_populate_ride_contact, 10, 3);
function func_to_dynamically_populate_ride_contact( $options, $title, $type ){
switch( $title ){
case 'Ride Leader':
$options = array();
// add first empty value
$options[] = array('#value' => '', '#title' => '---');
// get all "Ride Leaders" post items
$args = array( 'post_type' => 'model-cpt-slug', 'posts_per_page' => -1, 'post_status' => 'publish','orderby' => 'title' );
$results = get_posts( $args );
if ( $results ) {
foreach ( $results as $post ) {
$options[] = array('#value' => $post->ID, '#title' => $post->post_title);
}
}
break;
}
return $options;
}
----------------------------------------------------------------------------------------
I'm not sure if I have everything right with the above code.
I then tried to add the Ride Contact custom field back into Rides as a Select field, but I didn't see the options in there. I went ahead and created all posts for the Ride Leader content type that we're going to have. But that didn't populate as options in the field either. So I'm sure I've done something incorrectly here.
I deleted Ride Contact, Ride Contact Phone, Ride Contact Email, and Ride Contact Website from the Ride custom field group since they were present in the Ride Leader custom field group now. I decided I should probably create a Relationship between Ride and Ride Leader content types. I did that as one-to-many and set a limit of 2 per ride. That way we can have one Ride Contact and one Ride Sweep for each ride.
I think I will also need help restoring the Ride Contact Phone, Ride Contact Email, and Ride Contact Website fields into the Ride content type, or at least to display properly on the Ride page template possibly pulled through the relationship I set up. But for now let's just see if we can get the Ride Contact and Ride Sweep fields to be Select fields with a dropdown showing all Ride Leader post titles as the options.
Thank you for sharing this update and glad my suggested structure helped.
To troubleshoot why the 'select' fields are not generating the options properly, I'll need to see exactly how this post type, custom fields, and custom code are set up in the admin area.
Can you please share the temporary admin login details of the website, along with the information about where that custom code can be seen?
Note: Your next reply will be private and making a complete backup copy is recommended before sharing the access details.
Sorry about the delay in getting back on this, as we had an unusually busy forum queue after the weekend.
During troubleshooting, I noticed that field names/titles and custom post-type slugs were not used properly in the code snippet "ride-contact-select-field".
I've updated with these corrections and it is working properly to connect the "Ride Contact" and "Ride Sweep" fields with the options from the "ride-leader" post type:
add_filter( 'wpt_field_options', 'func_to_dynamically_populate_ride_contact', 10, 3); function func_to_dynamically_populate_ride_contact( $options, $title, $type ){ switch( $title ){ case 'Ride Contact': case 'Ride Sweep': $options = array(); // add first empty value $options[] = array('#value' => '', '#title' => '---'); // get all "Ride Leaders" post items $args = array( 'post_type' => 'ride-leader', 'posts_per_page' => -1, 'post_status' => 'publish','orderby' => 'title' ); $results = get_posts( $args ); if ( $results ) { foreach ( $results as $post ) { $options[] = array('#value' => $post->ID, '#title' => $post->post_title); } } break; } return $options; }
Please feel free to test and let me know if you have any follow-up questions.
No worries at all on the delay. I'm beyond ecstatic with and blown away by your level of support. Worrying about waiting a few days for the level of help you guys provide would be absurd. I'm sorry for how much I'm pushing the limits on what can be done with all these advanced use ideas and getting all this help from you guys. I'm hoping seeing these suggested uses from end-users like me is helpful to you guys for getting ideas for adding new functionality to the plugin.
Woo-hoo! I see on the Add New Ride page that the Ride Contact and Ride Sweep fields now have the dropdowns and are populated with all the Ride Leaders I added.
Can we get these sorted in the opposite order? They are currently displaying with the option that should be last in the list being first and the first being last. I'm not seeing how to change that in the code you provided.
So now my other remaining question with this is how do we handle the following fields:
Ride Contact Phone, Ride Contact Email, Ride Contact Website.
What we want to happen is these three fields should be present in the Ride content type. However I removed them and put them in the Ride Leader content type, figuring they can still be pulled through the Relationship between Ride and Ride Leader. So how do I accomplish getting those three fields to be used within each Ride and populated with data based on which Ride Contact was selected in that field. Note that we do not need these three fields for the Ride Sweep. Only the Ride Contact needs to see these fields added to each Ride. Do I have to do anything within the Ride field group for these fields to be passed? Or can I just do it on the Ride page template by displaying these fields through the relationship to the chosen Ride Leader in some way?
Note that if I have to add these Phone, Email and Website fields back into the Ride field group, that would be OK. I know we'd probably then have to then manually add that information for each Ride. But if it can be automatically pulled from the Ride Leader relationship, that's much better and what I was hoping could be done once I saw your suggested logic.
I'm not seeing any way to add fields from the Ride Leader field group within the Ride page template. So this looks like it is going to be more difficult than I was hoping for.
Is there a way to do this? If not, then we'll have to add those fields back to the Rides content type and add the data manually each time instead of having it pull the data from fields within the Ride Leader content type based on which Ride Leader is chosen in the Ride Contact field.
I did find this older support ticket that I hoped would solve this for me:
https://toolset.com/forums/topic/trying-to-show-childs-fields-in-a-parent-content-template/
But I'm not sure what to do here as it relates to my specific need because this isn't entirely the same.
Thanks for the update and glad that we're making progress.
> Can we get these sorted in the opposite order? They are currently displaying with the option that should be last in the list being first and the first being last. I'm not seeing how to change that in the code you provided.
- To change the ordering direction in the list of options, you can change the line in that code snippet from:
$args = array( 'post_type' => 'ride-leader', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title' );
To:
$args = array( 'post_type' => 'ride-leader', 'posts_per_page' => -1, 'post_status' => 'publish', 'orderby' => 'title', 'order' => 'ASC' );
You can read more about the function "get_posts" at:
https://developer.wordpress.org/reference/functions/get_posts/
As for showing the custom field values from the connected 'Ride Leaders' post, I see you've created and used a view named "Ride Contact Fields" in the "Template for Rides".
It is the right approach and here are a few adjustments that were needed to make it work:
1. The view had a relationships query filter added to narrow down to the related "Ride Leaders" post.
( screenshot: hidden link )
But in this case, we're not using the post-relationship, but have the ID of the related "Ride Leaders" post, stored in the custom field "Ride Contact".
So instead of the post-relationship filter, I've included the "Post ID" filter and linked it with the shortcode attribute "ids".
( screenshot: hidden link )
2. As the shortcode attribute value can't be passed through the "Views" block. I've removed the "Views" block that was calling this view in the "Template for Rides".
In its place, I've included the "Shortcode" block, and called the same view, but through the view's shortcode, like this:
( ref: https://toolset.com/documentation/programmer-reference/views/views-shortcodes/#wpv-view )
[wpv-view name="ride-contact-fields" ids="[types field='ride-contact-2' output='raw'][/types]"]
As a result, this view only shows the "Ride Leaders" post, whose ID is passed in the view's shortcode attribute "ids". And that is being called through the custom field shortcode [types field='ride-contact-2' output='raw'][/types].
I hope this helps and please let me know if you need any further assistance with this.
Wow! My head is exploding trying to follow everything with this. There is no way in the world I'd have been able to figure all of this out, but I'm extremely pleased that it is doable with your plugin with this extensive assistance from someone that knows all these details.
When I set up my view to show the ride fields, I was testing to see if I could make it work, but it didn't. I was thinking that the reason might have been because we were pulling the titles of the Ride Leaders as options for the Ride Contact field and that it wasn't working with the direct relationship between Rides and Ride Leaders. So I actually do follow everything you said in #1 above and was on the right path of thought. I just wouldn't have known at all how to do what you did with the Post ID filter.
But then what you said in #2 above has me wishing I could wrap my head around everything with this. I do follow where you said that you removed the Views block and instead called the View with a shortcode. That makes logical sense, but I wouldn't have known that limitation with the Views block. Everything with doing this through the Post ID has me feeling like there is still no way I could duplicate this on my own even seeing exactly what you did here. I'm still feeling like this is wayyyyy beyond my skill level to grasp this to this degree. I have enough of a programming background to follow along to a certain extent, but then lack enough in that background to just reach a point where I know I'm out of my league and my brain kind of shuts down from overload at that point. This has me in that mode right now.
I have to ask in a half joking, half serious manner, how long does it take to become this level of Jedi Master with Toolset? Wow.
I'm looking at this test Ride page here:
hidden link
I'm seeing that the email and phone fields are showing. So what you've done looks like it is working perfectly. We don't have websites defined for our current Ride Leaders, but I added that field because it was present in the Events Calendar plugin functionality that I was trying to duplicate. We'll be able to use that field going forward and may seek to get websites from our existing ride leaders, if they have any. For now, I'll just assume that field is working fine in the view as the email and phone fields are.
I'll be able to edit this view to perfect how the fields are displaying through the Ride page template. I have to eliminate those social media things that display at the bottom of every result on every view until I block it through CSS. But it looks like we'll have these fields working fine.
So that leaves the creation of the View that prompted this ticket in the first place. I'll next set up the view to display all Ride Leaders along with the counts of Rides they have been chosen on. I'm sure I'm going to need some help with how to calculate and display those counts. I'll get you the details in a follow up to this reply after I give it my best shot.
Oh yeah, I added the sort bit as instructed and that worked.
Thanks immensely for getting this to where it is now.
I had a View set up for this count already started here:
Ride Leader Number of Rides List
hidden link
I'm completely lost as to how to display the Ride Leaders along with a count on the number of times they have been chosen as either Ride Contact or Ride Sweep on the Ride pages.
First I'm not sure if I should set the View to display Rides or Ride Leaders. I could display Rides and have it show the Ride Contact and Ride Sweep fields. Or I could just display Ride Leaders and have it show Post Titles. I'm not sure which is the right approach here because I don't know how the count field should be added. Going back to your original reply to me, I'm seeing this:
----------------------------------------------------------------------------
3. Once the Rides and the Riders data has been stored in this structure, you can create two classic/legacy post views to show the count of each rider's participation:
a). The parent view will be set to show the list of all the "Riders" posts
b). Inside the loop of the parent view, you can show a nested child view that will show "Rides" posts. But with a query filter for the 'Ride Contact' and 'Ride Sweep' fields. So that only posts where the value for any of those fields is the same as the current parent post's ID (rider).
As you only need the count from this child view, the loop of this view will be empty and this view will only return the count through the "wpv-found-count" shortcode:
https://toolset.com/documentation/programmer-reference/views/views-shortcodes/#wpv-found-count
----------------------------------------------------------------------------
Here's how I'm interpreting this for where we are now:
3a) This means I should set the view to display Ride Leader posts, right?
3b) This has me somewhat lost. Are you saying I need to create a second view that displays Rides and set up query filters on that second view for Ride Contact and Ride Sweep and then display that second view within the first view in some way? If so, then how and where do I set where you're saying to show only posts where the value for any of those fields is the same as the current parent post's ID? I do understand what you're saying to leave the loop of the view as empty so that only the count is returned. But then I'm unclear of how to set up the found count as a field within the parent view to go alongside each Rider Leader name.
OK, I have now set up two views:
Ride Leader Number of Rides List
hidden link
Ride Leader Number of Rides List Count Field
hidden link
The page where I'm displaying these is here:
hidden link
I've done it the way I interpreted your initial message, but it isn't working. I do have it showing the Ride Leader Names for the first field using Post Title for the Ride Leader posts. But I tried setting up the nested view you mentioned and that's what isn't working. It is showing No items found for all of them. Obviously I've done something wrong in the Ride Leader Number of Rides List Count Field view. In there, I didn't see a way to set up the Query Filters for the Ride Contact and Ride Sweep fields to show "only posts where the value for any of those fields is the same as the current parent post's ID (rider)". I'm missing something there. Either that or I've placed the nested view in the wrong place within the parent view. Or maybe both.
I'm worried that the structure I've set up may not work. I'm seeing in your instructions that you said that the query filter should show "only posts where the value for any of those fields is the same as the current parent post's ID (rider)". The way I have this set up, the Ride content type is the parent and Ride Leader is the child. So I'd need the Ride Contact and Ride Sweep fields from the parent match with the ID of the child, right? I have no idea how to set that up with what I'm seeing for options within the query filters. I've looked at setting the query filters as a string equal to a Constant, but didn't know what to use as the comparison field. I tried it as a string equal to a URL Parameter, but didn't know what to put in that comparison field either. And then I tried it as a string equal to a Shortcode attribute, but didn't know what to put in that comparison field again. That seems to be where I'm stuck on following your instructions for this.
Should I have set this relationship up for Ride Leaders to be the parent and Rides to be the children? It really should be Rides as the parent and Ride Leaders as the children logically with how our system should view these, but if that makes it impossible to get this count view to work, then I may have to change this structure again. I hope that's not the case and there is a way to compare a parent field to the child ID for the query filters.
Just checking in again. No problem with waiting, but I want to make sure this ticket hasn't been forgotten.
I apologize for the delay in getting back on this, again. We are a little light on the coverage during the holiday season.
1. Classic/legacy views editor:
I can understand that for someone starting new with Toolset, the features of classic/legacy views can be quite overwhelming. But with some practice and real-life scenarios, that learning curve can easily be attained.
Before the blocks-based Gutenberg editor was introduced by WordPress, this classic/legacy views editor was being used as the main editor. It has been around for quite some time now and therefore is much more advanced yet flexible. It can be used for many complex requirements, which can't be achieved through the relatively newer blocks-based editor.
Apart from the steps discussed in this ticket, I'll also recommend going through our documentation on the legacy feature, to better understand how it works:
https://toolset.com/documentation/legacy-features/views-plugin/
2. Page: Ride Leader Number of Rides List
I've reviewed the two views used on this page, and here are the changes that I made to make them work. Through these practical steps and explanations, I'll do my best to explain why these changes were needed. But in case any point is not clear or needs further explanation, please do let me know:
a). In the child view "Ride Leader Number of Rides List Count Field", the query filter section included filters for the "Ride Contact" and "Ride Sweep" fields. But, it was set to compare the 'Constant' values (which were empty) and as a string.
( screenshot: hidden link )
What we actually want in this case is to compare the field values as 'numerical' values (because we're storing 'Ride Leaders' post IDs in these fields), which are connected to the shortcode attribute value, coming from the parent view.
( the technique of passing shortcode attribute is useful in cases where we want the views to become dynamic, based on the value coming from the parent page or another view. Basically from where the view is being called in from, which in this case is from inside another view 'Ride Leader Number of Rides List' )
So, I changed the query filters of these fields to use a 'numerical' comparison, linked to the shortcode attribute named 'targetrider'.
( screenshot: hidden link )
Because we want to pass the same value for the comparison of both these fields (which is the post ID of the 'Ride Leaders' post from the parent view), I've used the same shortcode attribute 'targetrider'.
b). In the view "Ride Leader Number of Rides List", where the child view's shortcode was being called in, I've added this shortcode attribute 'targetrider', so that it passes the current 'Ride Leaders' post's ID through the "[wpv-post-id]" shortcode:
[wpv-view name="ride-leader-number-of-rides-list-count-field" targetrider="[wpv-post-id]"]
c). The next step is a little trickier. If you'll check the query filter section of the view "Ride Leader Number of Rides List Count Field", it reads:
( screenshot: hidden link )
Select items with field: Ride Sweep is a number equal to VIEW_PARAM(targetrider) AND Ride Contact is a number equal to VIEW_PARAM(targetrider)
Theoretically, it means that the query will look for any 'Rides' posts, where the values of the 'Ride Sweep' and 'Ride Sweep' fields both are equal to our target 'Ride Leaders' (because of the 'AND' operator in between), which is not what we want.
We want instead that the query looks for any 'Rides' posts, where the value of either the 'Ride Sweep' or the 'Ride Sweep' field is equal to our target 'Ride Leaders' ( so there should be the 'OR' operator, instead of the 'AND' ).
There is no option to change that from the query filter section's settings, so, I've added a new code snippet at WP Admin -> Toolset -> Settings -> Custom Code, that targets the query filter for this specific view, and programmatically changes the 'AND' operator to 'OR':
( ref: https://toolset.com/documentation/programmer-reference/views-filters/#wpv_filter_query )
add_filter( 'wpv_filter_query', 'filter_view_meta_relation', 1000 , 3 ); function filter_view_meta_relation( $view_query_args, $view_settings ) { if ( ( isset($view_settings['view_id']) && $view_settings['view_id'] == 4185) ) { $view_query_args['meta_query']['relation'] = 'OR'; } return $view_query_args; }
d). The last adjustment that I made was to move the "[wpv-found-count]" shortcode, out from the loop of the view "Ride Leader Number of Rides List Count Field", so that it is not repeated for each found post and shows only once for each rider.
( screenshot: hidden link )
I hope these steps and explanations will make this usage clearer and any follow-up questions are welcome.