0

In a custom J4 site I am using the Shack Locations (previously Focalpoint) core extension that displays a dynamically generated legend of location types on the front end, but it is listing the nine types randomly. I carefully created the location types in the order in which I wanted them to appear. I also used Joomla's ordering facility to no avail. So, I created an override which brings in the location type IDs as a class for each li item (by default there is no 'li' class), so on the front-end the html now shows this (although each also has an 'a' link, but that's not relevant here):

<li class="28">No meeting</li>
<li class="22">Tuesday afternoon</li>
<li class="23">Tuesday evening</li>
<li class="25">Wednesday evening</li>
<li class="27">Thursday evening</li>
<li class="20">Monday afternoon</li>
<li class="24">Wednesday afternoon</li>
<li class="26">Thursday afternoon</li>
<li class="21">Monday evening</li>

For what I hope are obvious reasons, I want the list to display like this:

<li class="20">Monday afternoon</li>
<li class="21">Monday evening</li>
<li class="22">Tuesday afternoon</li>
<li class="23">Tuesday evening</li>
<li class="24">Wednesday afternoon</li>
<li class="25">Wednesday evening</li>
<li class="26">Thursday afternoon</li>
<li class="27">Thursday evening</li>
<li class="28">No meeting</li>

The PHP for this element is

<?php
defined('_JEXEC') or die();

$markers = $this->chunkLegends($this->item->markerdata);

$html       = [];
$subtitle   = '';
$lastLegend = null;
foreach ($markers as $legend) {
    if ($lastLegend && $lastLegend != $legend->alias) {
        $html[] = '</ul>';
        $html[] = '</div>';
    }

    $subtitle = $legend->subtitle ? sprintf('<small>%s</small>', $legend->subtitle) : '';

    $html[] = sprintf(
        '<div class="%s"><h4>%s%s</h4>',
        $legend->alias,
        $legend->title,
        $subtitle
    );

    $html[] = '<ul class="sidebar">';
    foreach ($legend->markers as $marker) {
        $html[] = sprintf(
            '<li class="%s"><a data-marker-type="%s" class="active markertoggles markers-%s" href="#">%s</a></li>',
            $marker->locationtype_id, 
            $marker->locationtype_id,          
            $marker->locationtypealias,
            $marker->locationtype
        );
    }
    $html[] = '</ul>';
    $html[] = '</div>';
}

$html[] = $this->loadTemplate('legend_buttons');

echo join("\n", $html);

Can I sort the li items by their class, either by adding something to the PHP file, or writing vanilla JavaScript? No jQuery, please. TIA.

2
  • You can sort the array directly in PHP. See How to Sort a Multi-dimensional Array by Value.
    – Sharky
    Apr 22 at 12:52
  • Thank you. I've never done anything like that, so how do I specify that the array should come from the class of the li elements that I want sorted? And where would it go in the above PHP file?
    – Gillian
    Apr 22 at 13:14

2 Answers 2

0

I solved it with some vanilla JavaScript. I'd still like to know how it could be done in PHP as the JavaScript runs after page load and on a slow page load the resort might be visible to the naked eye.

Here is the script (using the li Ids - not shown above - rather than class):

window.onload = function() {
    if (document.getElementById("meetings")) {
    let
        list = document.querySelector('.sidebar'),
        results = document.querySelectorAll('.sort');
    let sliced = Array.prototype.slice.call(results, 0);
        sliced.sort(sortByElementText('a.markertoggles'));
        list.innerHTML = '';
        sliced.reduce(function(list, item) {
            list.appendChild(item);
            return list;
        },
        list);
        function sortByElementText(selector) {
            return function(a, b) {
            b.id;
            a.id;    
            return a.id > b.id;
            }
        }
    }
}

And hands up, I got the original idea from an answer (entitled 'A native js way.') on this post on Stackoverflow by @synthe1c

UPDATE: I have since discovered that although this works perfectly in Firefox, it doesn't in Chrome, Edge, Android.

6
  • please provide me with the var_export($markers) output so that I can demonstrate how to sort your data. A link to 3v4l.org or phpize.online will suffice.
    – mickmackusa
    Apr 22 at 16:47
  • I'm sorry @mickmackusa, but I haven't a clue. I didn't write this extension, it's from Joomlashack. I wouldn't know where to start looking, although the top of the PHP code in the first post says $markers = $this->chunkLegends($this->item->markerdata);. I have searched some of the other files for var_export($markers) but haven't found that string.
    – Gillian
    Apr 23 at 10:37
  • No no, I mean, I'd like you to temporarily overwrite the snippet that you posted in your question. Write var_export($markers); immediately after $markers is declared, then exit(), then show me what that data looks like. Once I have that data, I can prepare an answer for you.
    – mickmackusa
    Apr 23 at 10:39
  • Sorry. I'm hopeless. I've tried it in both a copy of the above PHP snippet in the phpize.online program and on my dev site file, in line 5, after $markers = $this->chunkLegends($this->item->markerdata); and also after the foreach ($legend->markers as $marker) code. In phpize.online I get "Fatal error: syntax error, unexpected variable "$html"..." and on the dev site I get a 500 internal server error wherever I put the code.
    – Gillian
    Apr 23 at 11:49
  • Ah, what I mean to ask for, is for you to modify your actual project code (temporarily) -- just to print out the data. I need to see the real data (...well, you can redact the actual values, but I need to see the data structure). Your snippet has two nested foreach loops, so I cannot confidently reverse engineer sample data on my own.
    – mickmackusa
    Apr 23 at 12:03
0

Use usort() to sort $legend->markers array:

usort(
    $legend->markers,
    static fn ($a, $b) => $a->locationtype_id <=> $b->locationtype_id
);
2
  • Thanks, @Sharky. I'm not sure where to put this and whether I should also delete something else.
    – Gillian
    Apr 24 at 11:28
  • This can be added after the first foreach() (which is where $legend is declared), and before the second foreach(). I'd probably squeeze it after the line that pushes <ul class="sidebar"> into the $html array.
    – mickmackusa
    Apr 24 at 15:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.