Skip Navigation

[Resolved] Sort by View

This support ticket is created 2 years, 11 months ago. There's a good chance that you are reading advice that it now obsolete.

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.

Sun Mon Tue Wed Thu Fri Sat
- 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 9:00 – 12:00 -
- 13:00 – 18:00 13:00 – 18:00 13:00 – 18:00 14:00 – 18:00 13:00 – 18:00 -

Supporter timezone: America/Jamaica (GMT-05:00)

This topic contains 37 replies, has 3 voices.

Last updated by igorL-3 2 years, 10 months ago.

Assisted by: Shane.

Author
Posts
#2143113

Tell us what you are trying to do?
I have a many-to-many relationship called ARTIST between two custom types ART and PERSON. I then made two views. One view gives artists related to the art [wpv-view name="art-artist”] and the other view shows the artist, the art and the title of the art like this:
<div style="text-align: center;">
[wpv-view name="art-artist"]
[wpv-post-featured-image]<br>
[wpv-post-link]
</div>

where [wpv-post-featured-image] is the image from the custom type ART and [wpv-post-link] is the link to the post. Everything works fine but I want to sort alphabetically by the artist. The custom type PERSON already has fields: first_name and surname. And I want to sort by the surname in the above view.

Is there any documentation that you are following?

Is there a similar example that we can see?

What is the link to your site?

#2143147

Hello, it is only possible to filter or sort a View by the properties and fields of the post type selected in the View's Content Selection panel. In other words, if the View's Content Selection is "Art", then it is only possible to sort or filter by the properties and custom fields of Art posts. If you need to sort or filter by the surname field, that can only be accomplished in a View of Person posts, since the surname field exists in the Person post type.

If I understand correctly, you would like to sort the results of the art-artist View based on the surname custom field in the Person post type. It looks like you have a nested View structure. The outer View is a View of Art posts, and the inner View is a View of the intermediary post type, Artist...is that correct? If so, then I would replace the View of the intermediary post type with a View of Persons posts. In the View of Persons posts, I would add a Post Relationship Query Filter based on the Artists post relationship, displaying Person posts as related to the current Art post in the loop.

If you need to display other information in the View of Person posts, like custom fields from the post relationship/intermediary post type, then you can use the Types field shortcode with an "item" attribute. The syntax for displaying information from the relationship/intermediary fields in a View of the Person post type is like this:

[types field="field-slug" item="@relationship-slug.intermediary"][/types]

You would replace field-slug with the slug of the custom field, and replace relationship-slug with the slug of the post relationship.

Let me know if I've misunderstood what you're trying to accomplish, or if this does not solve the problem. It maybe helpful for me to log in and see how everything is configured in wp-admin to be able to give better advice. I am activating private reply fields here so you can share login credentials in your next reply.

#2143207

Thank you for your reply Christian, and on a Sunday too 🙂

I already have what you’ve described. The outer View is a View of ART POSTS and the inner View is a View of PERSONS posts with a relationship filter displaying the posts in the ARTIST RELATIONSHIP with ART posts displaying posts in related to the current posts in the loop. But that doesn’t let me sort the ART posts by the PERSON posts.

I thought that maybe instead I should make an outer view of PERSONS posts and the inner view of ART so that I can sort
by PERSON fields but I’m not sure how I would exclude those PERSON posts that are not related to the ART posts

#2143273

I thought that maybe instead I should make an outer view of PERSONS posts and the inner view of ART so that I can sort
by PERSON fields but I’m not sure how I would exclude those PERSON posts that are not related to the ART posts

You can display information about the related PERSON post inside the View of ART POSTS instead of displaying information about the PERSON post inside the View of PERSON posts. For example, you probably have something like this in your View of PERSON posts to display the first name and surname:

[types field="first_name"][/types] 
[types field="surname"][/types]

Remove those shortcodes from the PERSON View. Move those shortcodes into the View of ART POSTS, and the custom fields will only be displayed when the PERSON is related to at least one ART POST. The trick is to pass the current PERSON post ID into the View of ART POSTS using a shortcode attribute. In the Loop Editor of the View of PERSON posts, add the 'person' shortcode attribute to the View of ART POSTS like this:

[wpv-view name="your-view-of-art-posts" person="[wpv-post-id]"]

Now in the nested View, you will have access to the current PERSON post ID in the wpv-attribute shortcode. So you can use the "item" attribute and wpv-attribute shortcode in the ART POSTS View to display custom fields from the related PERSON post. Something like this:

[types field="first_name" item="[wpv-attribute name='person']"][/types] 
[types field="surname" item="[wpv-attribute name='person']"][/types]

Place those shortcodes in the Loop Editor panel in the View of ART POSTS, inside the wpv-items-found shortcode, but outside the wpv-loop tag. That will display the PERSON post information only if the PERSON is related to at least one ART POST.

#2143943
Screenshot 2021-08-16 at 19.06.35.png

Hello Christian,

This didn’t work for me. I did make one error before when I told you that ARTISTS is a many-to-many relationship. It is in fact a one-to-many where PEOPLE(is one) and ARTS(are many) if that alters the situation.

If I follow you direction then what I get is the name of the first PERSON post listed on all the ART POSTS. The only way I could get it to work was to have two views:

View for ARTS posts with a slug: art-by-artist

[wpv-layout-start]
[wpv-items-found]
<!-- wpv-loop-start -->
<wpv-loop>
[wpv-post-body view_template="loop-item-in-artis-art-by-artist"]
</wpv-loop>
<!-- wpv-loop-end -->
[/wpv-items-found]
[wpv-no-items-found]
[wpml-string context="wpv-views"]No Art found[/wpml-string]
[/wpv-no-items-found]
[wpv-layout-end]

where loop-item-in-artis-art-by-artist is:

[types field="first-name" item="[wpv-attribute name='person']"][/types]
[types field="surname" item="[wpv-attribute name='person']"][/types]<br>
[wpv-post-featured-image]<br>[wpv-post-link]<br><br>

and

View for PERSON posts with a slug: list-of-art-by-artists
which I sort by the surname field

[wpv-layout-start]
[wpv-items-found]
<!-- wpv-loop-start -->
<wpv-loop>
[wpv-post-body view_template="loop-item-in-list-of-art-by-artists"]
</wpv-loop>
<!-- wpv-loop-end -->
[/wpv-items-found]
[wpv-no-items-found]
[wpml-string context="wpv-views"]No Persons found[/wpml-string]
[/wpv-no-items-found]
[wpv-layout-end]

where loop-item-in-list-of-art-by-artists is:

[wpv-view name="art-by-artist" person="[wpv-post-id]”]

And Query Filter set in the ARTS relationship as related items of the post with ID set by the shot code attribute person (as you can see in the attached screenshot)

This sort of works but it does produce a lot of No Art found messages when it doesn’t find ARTS post related to a PEOPLE posts without an active relation, as is expected. The only way I can suppress the No Art found message is to remove the [wpv-no-items-found] short code. But that causes issues when I try to organise output into 3 columns. Where No Art found would appear creates an empty grid spot.

What am I doing wrong with your method? And if my method is ok how do I get rid of the empty grid spots created when there is no ARTS posts related to a PERSON post.

I’d be happy to give you access but this part I haven’t uploaded to a server yet and am debuting it on a local version.

PLEASE HELP!!!

Thank you in advance

#2144125

It's hard to say without really understanding how you are setting up the grid, the CSS classes involved, the container element, how rows are defined, etc. This approach does not lend itself to a grid-based design that requires rows defined in the markup, if the art posts from one person could be split across two rows of columns. One way you could do it with a Bootstrap grid is to disable "wrap" in the Views loops and use the grid class corresponding to 3 equal columns in the loop of art posts. In Bootstrap 4 that would be .col-4. So in the Persons View you would set up the container:

[wpv-layout-start]
[wpv-items-found]
<div class="container">
<!-- wpv-loop-start -->
<wpv-loop>
[wpv-post-body view_template="loop-item-in-list-of-art-by-artists"]
</wpv-loop>
<!-- wpv-loop-end -->
</div>
[/wpv-items-found]
[wpv-no-items-found]
[wpml-string context="wpv-views"]No Persons found[/wpml-string]
[/wpv-no-items-found]
[wpv-layout-end]

Then in the Art View, apply the 3-column grid class to each item in the loop and delete everything in the no items found section:

[wpv-layout-start]
[wpv-items-found]
<!-- wpv-loop-start -->
<wpv-loop>
<div class="col-4">[wpv-post-body view_template="loop-item-in-artis-art-by-artist"]</div>
</wpv-loop>
<!-- wpv-loop-end -->
[/wpv-items-found]
[wpv-no-items-found][/wpv-no-items-found]
[wpv-layout-end]

Each art post would take up 1/3 of the available width in the container. Without any .row divs, the grid cells should automatically break to multiple rows as needed, and the art posts from one person could be displayed across multiple rows if necessary.

I'd really need to see it in the browser to give you more direct guidance here. You can set up a free account on our sandbox site at discover-wp.com if you don't have a staging environment available.

#2144541

Hi this is not quite the problem. It comes becouse say one artist has 6 pieces of art. That will fill the entire row. Then say the next artist has only only 5 or even just 1 then the pieces will be displyed and then the view would exit the inner view or art and go to the persons view and leave blank spaces becouse the next row will start fresh. I have played with wrap and pad all to no avail.

So I've uploaded the site to a live server and hiden the pages. Please send me a secure request and I will send you the loggings.

Thank you again!!!

#2144625

Private fields are enabled here.

#2144949

Okay it turns out the "row" div is necessary for Bootstrap 4 because of its flexbox implementation. So I have set up the two Views basically just like I told you, and I added the row div in the outer View. You can't use wrap and pad in either View. Those features will not help when the Views are nested like this and the number of Art posts for each Person is not always evenly divisible by 3. You want the Art posts arranged in a 3-column grid, regardless of the parent Person. I deleted the loop templates since there is no need for extra templates here, and the loop contents are placed directly in the loop of each View now. It will be easier to edit this way.

Outer View has the container and row:

[wpv-layout-start]
  [wpv-items-found]
    <div class="container">
      <div class="row">
      <!-- wpv-loop-start -->
	  <wpv-loop>
            [wpv-view name="art-by-artist" person="[wpv-post-id]"]
	  </wpv-loop>
	  <!-- wpv-loop-end -->
      </div>
	</div>
  [/wpv-items-found]
  [wpv-no-items-found]
    [wpml-string context="wpv-views"]No Persons found[/wpml-string]
  [/wpv-no-items-found]
[wpv-layout-end]

Inner View produces the grid cells:

[wpv-layout-start]
  [wpv-items-found]
    <!-- wpv-loop-start -->
		<wpv-loop>
          <div class="col-4">
          	[types field='first-name' item="[wpv-attribute name='person']"][/types]
		[types field="surname" item="[wpv-attribute name='person']"][/types]<br>
		[wpv-post-featured-image]<br>
		[wpv-post-link]<br><br>
          </div>
	    </wpv-loop>
	<!-- wpv-loop-end -->
  [/wpv-items-found]
  [wpv-no-items-found][/wpv-no-items-found]
[wpv-layout-end]
#2144973

Thank you very much. A subtle change made all the difference.

One more thing. Where do I place the pagination controls? In the inner or outer view?

#2145107

Where do I place the pagination controls? In the inner or outer view?
The built-in pagination features don't work in a nested View structure. If you put pagination in the outer View, you would paginate by Person. That means each "page" of results would only include the Art posts associated with one Person. If you put pagination in the inner View, that means pagination would repeat for each Person, and you would be paginating per Person.

If pagination is a requirement, a nested View approach is not possible. To use the built-in pagination system, you would need custom code to produce the results in a single View using our Post Relationships APIs and Views APIs and Filters. The general idea is that you would create one View of Art Posts filtered using post__in and ordered by the same list of Art post IDs used in filter. You would have to generate that list of Art post IDs using a query of Person posts, sorted by surname, and a nested Post Relationships query, then supply the produced list of Art post IDs to the post__in argument of a post IDs query filter. Since the results are all produced by one View, that would allow you to use the built-in pagination features in a single grid View of Art posts.

Since it's a one-to-many (O2M) relationship and not a many-to-many (M2M) relationship, you only have one Person related to each Art post. That means you could get the custom fields from the Person post in a View of Art posts using the item attribute and @relationship-slug.parent syntax instead of passing the Person ID in and accessing it in a wpv-attribute shortcode. In a View of Art posts that would look like this:

[types field="surname" item="@relationship-slug.parent"][/types]

You would replace relationship-slug with the slug of the Person-Artist O2M relationship.

#2145147

My issue is resolved now. Thank you!

#2145735

Hi Christian,

I’m trying to do this a little different by atempting to modify $query_args in wpv_filter_query filter because I have already set that filter up to do custom filtering using other fields in ARTS. But I’m not too sure if I’m on the right track as I’m a bit stuck nor am sure if this is actually possible.

If you recall there are two post types ARTS and PEOPLE. Additionally PEOPLE has a meta-field wpcf-surname. So the idea is to order ARTS posts alphabetically by wpcf-surname meta field from the PEOPLE posts. There is also a one-to-many relationship between PEOPLE(one) and ARTS(many) with a slug: artist-art-person

I have tried various things like getting the PERSON posts first and then sorting them but that seems to mess-up $query_args.

Is this a reasonable approach and if so I’d be grateful to be pointed in the right direction?

Again thank you in advance

#2145813

I have tried various things like getting the PERSON posts first and then sorting them but that seems to mess-up $query_args.
Are you creating a new WP_Query for Person posts, or are you using the Views API to get the results of a separate Person View? If you are not very familiar with creating custom WP_Query code, it might be easier to create a separate Person View, and apply the desired surname sorting in that View. Then you can use the Views API get_view_query_results, which will give you access to those Person posts, already sorted in the correct order by surname.
https://toolset.com/documentation/programmer-reference/views-api/#get_view_query_results
Once you have those sorted Person posts, use a foreach loop to loop over them and then use the post relationships API toolset_get_related_posts to get the IDs of all the Artist posts related to those Person posts and push them into one large array of Artist post IDs. The idea is that after you loop over all the Person posts and get their related Artist posts, you have created an array of Artist post IDs in the desired sort order:

[82, 192, 41, 48, 39, 192, 37, 11, 42, 22, etc..]

Since the Persons posts were already sorted by the Person View and you are looping over the results of that View to get Artist IDs, this new array of Artist post IDs is already sorted by Person. Now you can use this array of Artist post IDs to set the
post__in argument in the original query in wpv_filter_query. When you use post__in to set the Artist post IDs like this, you can also use orderby 'post__in', so the Artist order in the results will be exactly like the ID order you provided in the array of post__in IDs. This is the only way I can think of to sort a query of Artist posts based on information in a related post type, because WordPress queries are not designed to allow you to sort directly by related post information.
https://developer.wordpress.org/reference/classes/wp_query/#post-page-parameters (using post__in in WP_Query )
https://developer.wordpress.org/reference/classes/wp_query/#order-orderby-parameters (orderby post__in in WP_Query )
https://toolset.com/documentation/customizing-sites-using-php/post-relationships-api/#toolset_get_related_posts (get related posts)

Feel free to share any code you have so far, and I can help troubleshoot anything directly related to Toolset APIs like wpv_filter_query or toolset_get_related_posts.

#2145837

I have this but it's not giving me the alpabetically sorted result

$args_persons = [
'post_type' => 'person',
'orderby' => 'post_title',
'post_status' => 'any',
'order' => 'ASC',
'numberposts' => -1
];

$persons = get_posts( $args_persons );

foreach($persons as $person) {
$meta_person = get_post_meta($person -> ID);
$person -> surname = $meta_person['wpcf-surname'][0];
}

usort($persons, function ($a, $b) {
return strcmp($a->surname, $b->surname);
});

$arts = [];
foreach ($persons as $person) {
$art = toolset_get_related_posts(
[
'parent' => $person,
],
'artist-art-person',
);

if ( !empty($art) ) { array_push($arts, $art[0]); }

}

//echo('<br>');
//var_dump($arts);
//echo('<br>');

$query_args['post__in'] = $arts;

This ticket is now closed. If you're a Toolset client and need related help, please open a new support ticket.