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

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • 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
    • By celfred
      Hello,
      I'm facing an issue with my page fieldtype. Pages appear in the order they were created although I'd like to see them sorted in alphabetical order (by title). The pages are well-sorted in my tree, but in that particular Page fieldtype (on another page), I can't find any place where I would decide on what field I can sort them. Am I missing something here ?
      Let me know if I'm not clear enough in my explanations.
      Thanks in advance for a clue  
    • By Vigilante
      This is a pretty typical thing. Open a page, it does a $pages query, finds 112 things and I list them on the page. There is pagination too, 20 per page.
      I want a sort dropdown box so the visitor can change alpha sort or whatever other sorts and filters I eventually use.
      My first thought is to just refresh the page with a url query like "page/?sort=az" and then adjust the query in the template code. But to do this, it will require a page refresh, which means the sort box goes back to its default, and not sure how it effects pagination.
      If I do a page refresh, I'll have to keep the sort settings in the session or something, to make sure I always apply correct sort on page load.
      But at the same time, I've already got the $pages array, it would be much nicer to shuffle it and update the page without a page refresh, rather than run the query over and over again.
      But then again, the pagination buttons already cause page refreshes, so that is already happening anyway, unless I convert the pagination buttons to also be no-refresh somehow.
       
      I figure this is a very common problem, to paginate results and give users a sorting/filtering option. What is the common methods for handling it? Session, url query, ajax? If I just add the sort to the url query, how do I make that work in the pagination links?
×
×
  • Create New...