Jump to content
Moebius

Sort results by title ascending, when title includes special characters (croatian letters)

Recommended Posts

I need to sort results by title ascending, and title includes special characters (croatian letters).

The problem is that results are sorted but not 100% correct:

e.g.

$authors = $pages->find("template=author,sort=title");
  • Cavali
  • Cavilon
  • Čavlović
  • Cesare
  • ...

You see intruder (bolded), it looks like sort engine treats letters C and Č as same ones.
I'm not sure that this is Processwire related, but maybe API has solution for this kind of behavior?

I have UTF-8 page content type .

 

 

 

Share this post


Link to post
Share on other sites

It depends on where in the sort order you want the special characters to go. Without doing anything special PHP would sort special characters after ASCII characters, so for instance that would place "Čavlović" after "Zola". If that is what you want (and I doubt that it is) it seems that you can achieve this kind of sort by using the "useSortsAfter" option for PageFinder:

$authors = $pages->find("template=author, sort=title", ['useSortsAfter' => true]);

BTW, it's far from clear to me what the "useSortsAfter" option does exactly.

But I don't think that is what you want anyway. To get a language-aware sort I think you would have to use something like PHP's Collator class - others may know better but I don't think PW has anything built in for this.

So here is something that might work, but it would mean you must get all your authors in one $pages->find() - no pagination in other words:

// Find the author pages
$authors = $pages->find("template=author");

// Get an array where key is author page ID and value is author page title
$titles = $authors->explode('title', ['key' => 'id']);
// New Collator instance
$collator = new \Collator('hr_HR'); // Croatian locale
// Apply language-aware sort
$collator->asort($titles);

// Apply custom sort property to author pages
$i = 1;
foreach($titles as $id => $title) {
    $author = $authors->get("id=$id");
    $author->custom_sort = $i;
    $i++;
}
// Sort authors by custom sort property
$authors->sort('custom_sort');

// Now loop over $authors and output markup

 

  • Like 2

Share this post


Link to post
Share on other sites
On 11/21/2017 at 11:21 PM, Robin S said:

get all your authors in one $pages->find() - no pagination in other words:

I think this Gist by @Soma may be of some help.

  • Like 1

Share this post


Link to post
Share on other sites

in my case pagination is not issue, I'll use Robin's solution for initial sort, save sort result value in new page custom field and then sort like we always do:

$authors = $pages->find("template=author,sort=my_new_sort_field");

 

works like a charm.

Share this post


Link to post
Share on other sites
8 hours ago, DaveP said:
On 22/11/2017 at 12:21 PM, Robin S said:

get all your authors in one $pages->find() - no pagination in other words:

I think this Gist by @Soma may be of some help.

My point about pagination was really that if you have a large number of authors you cannot apply a limit and must load all results into memory and loop over them to apply the sort. The options for "pseudo-pagination" don't get around this problem unfortunately.

 

3 hours ago, Moebius said:

I'll use Robin's solution for initial sort, save sort result value in new page custom field and then sort like we always do

The thing with that approach is that you would have to use a hook and loop over all author pages every time a new author is added or an author's name is edited. Sounds like that wouldn't be a big deal in your situation, but would be a problem if there were thousands of authors.

Thinking about a solution for large numbers of pages, I had an idea about generating a value for a hidden sort field based on the first letter of the author's name. It would go something like this...

In /site/config.php

// Prefixes for sort field
$config->sortChars = [
    'č' => 'czzzz', // sort after 'c'
    'đ' => 'daaaa', // sort before 'd'
    // etc
];

In /site/ready.php

$pages->addHookAfter('saveReady', function(HookEvent $event) {
    $page = $event->arguments(0);
    if($page->template != 'author') return;
    // Assuming author's last name is in Title field
    $initial = mb_strtolower(mb_substr($page->title, 0, 1));
    if(isset($this->config->sortChars[$initial])) {
        // If the initial letter matches a key in the sortChars array
        // add the prefix to the title and set to the sort field
        $page->sort_field = $this->config->sortChars[$initial] . $page->title;
    } else {
        // Otherwise use the title for the sort field
        $page->sort_field = $page->title;
    }
});

Then use sort=sort_field in the $pages->find() selector, and limiting/pagination is also possible.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By opalepatrick
      Hi, trying to order pages by modified date, date. I can do 'sort=-date_modified, sort=-date' but that will always put the modified date first regardless of actual date order. I just want to coalesce the two fields and sort. Any ideas would be appreciated.
    • By ngrmm
      I want to have filters with month names in german. I fetch them from date-fields with strftime('%B', $timestamp);
      But i'm not able to add them correctly to a wireArray()
      What's the right way to do that?
      $ms = wireArray(); $m1 = strftime('%B', 1579643232); // Januar $m2 = strftime('%B', 1583107200); // März $ms->prepend($m1); $ms->prepend($m2); foreach($ms as $name) { echo "$name "; // result: Januar M�rz }  
    • By louisstephens
      I have done a bit of searching, but I can not seem to find an actual answer. I have a list of services as child pages under "Services". I can output the services just fine, but I cant wrap my head around how to group them "alphabetically" like:
      Services A - Service "A" 1 - Service "A" 2 - Service "A" 3 B - Service "B" 1 - Service "B" 2 - Service "B" 3 C - Service "C" 1 - Service "C" 2 - Service "C" 3 Has anyone achieved this type of functionality before?
    • By nickngqs
      How do you guys sort according to the order of page listing?

      My template is sort order none, so I assume it would return according to order of page listing.
    • By rolisx
      Hi all!
      I have a little problem here. I want to sort a list of addresses by streetname and then by number. First, I just had a field "prod_objekt" (address) containing both and then have a foreach loop like this: $pages->get('/produzenten/')->prod_repeater->sort('prod_objekt') as $produzent. Unfortunately, this would not sort by streetnumber if I had the same streetname but multiple numbers.
      Now, I thought I could sort by two fields. prod_object (adress) first and then by prod_hausnummer (streetnumber). But I just don't know the code for it. I tried this: $pages->get('/produzenten/')->prod_repeater->sort('prod_objekt.prod_hausnummer') as $produzent, but it wouldn't work.
      Any ideas on how to solve this?
      Thanks for your help
      Roli
×
×
  • Create New...