0

I'm working on a WordPress site, trying to sort post tags, which is an array of objects with various members including slug and name. I've created an array of tag slug strings in priority order, and trying to sort a post's array of tags according to that array's values, with the post's slug as the key. Example:

$tagPriorityMap = array(
  "research" => 0,
  "strategy" => 1,
  "naming" => 2,
  "identity" => 3,
  "packaging" => 4,
  "environment" => 5,
  "digital" => 6,
);
function sort_tags($a, $b) {
  if ($tagPriorityMap[$a->slug] == $tagPriorityMap[$b->slug]) {
    return 0;
  }
  return ($tagPriorityMap[$a->slug] < $tagPriorityMap[$b->slug]) ? -1 : 1;
}

If I echo some code inside the sort_tags function, it shows that $a->slug is a string like "strategy", but it also shows that $tagPriorityMap[$a->slug] returns no value. What am I doing wrong? Thanks.

2 Answers2

0

your $tagPriorityMap must be declared as a global variable inside the function. Jut try:

function sort_tags($a, $b) {
  global $tagPriorityMap;
  if ($tagPriorityMap[$a->slug] == $tagPriorityMap[$b->slug]) {
    return 0;
  }
  return ($tagPriorityMap[$a->slug] < $tagPriorityMap[$b->slug]) ? -1 : 1;
}

Added Idea provided from Maik Lowrey

just add the $tagPriorityMap as parameter of the function for a global usage

function sort_tags($a, $b, $tagPriorityMap) {
  if ($tagPriorityMap[$a->slug] == $tagPriorityMap[$b->slug]) {
    return 0;
  }
  return ($tagPriorityMap[$a->slug] < $tagPriorityMap[$b->slug]) ? -1 : 1;
}
Ruben
  • 319
  • 2
  • 14
0

I really wonder why @Cârnăciov deleted his answer, it was far better than the one that was accepted.
Dumping the priorities in a global is ok for a test, but if you solve all your problems by littering the global namespace you'll soon be in trouble.

You could avoid this with the use() keyword like Cârnăciov suggested.

But you can simply define your priorities as a static variable directly inside the function. It will behave exactly like a global, except nobody but the comparison function will see it.
The PHP7 spaceship operator can also be used to simplify the comparison, it's tailor-made for that:

function sort_tags ($a, $b) {
        static $prio = array(
          "research" => 0,
          "strategy" => 1,
          "naming" => 2,
          "identity" => 3,
          "packaging" => 4,
          "environment" => 5,
          "digital" => 6,
        );
        return $prio[$a->slug] <=> $prio[$b->slug];
    }

Or you can use arrow functions too. These allow you to emulate the convoluted way JavaScript has handled closures these last 25 years :D
(sorry, just a little joke)

$sort_tags = (function () { // this anonymous function closes over "prio"
        $prio = array(      // and returns the actual comparison function
          "research" => 0,
          "strategy" => 1,
          "naming" => 2,
          "identity" => 3,
          "packaging" => 4,
          "environment" => 5,
          "digital" => 6,
        );
        // the comparison function sees "prio" captured in the upper level closure
        return fn ($a, $b) => 
            $prio[$a->slug] <=> $prio[$b->slug]; // handles the -1, 0 and 1 cases in one go
    })(); // immediately invoked function expression, just like in JavaScript

A silly example demonstrating that you no longer need a global:

file test.php

<?php

function demo () {
    
    $sort_tags = function ($a, $b) {
            static $prio = array(
              "research" => 0,
              "strategy" => 1,
              "naming" => 2,
              "identity" => 3,
              "packaging" => 4,
              "environment" => 5,
              "digital" => 6,
            );
            return $prio[$a->slug] <=> $prio[$b->slug];
    };


    $sample = [
        (object)["slug" => "naming"   , "id" => 1],
        (object)["slug" => "packaging", "id" => 2],
        (object)["slug" => "research" , "id" => 3],
        (object)["slug" => "strategy" , "id" => 4]];

    echo "<br>before usort:<br><br>";
    foreach ($sample as $item) echo $item->slug, " => ", $item->id, "<br>";
    echo "<br>after usort:<br><br>";

    usort ($sample, $sort_tags);

    foreach ($sample as $item) echo $item->slug, " => ", $item->id, "<br>";
}

demo();
?>

browser output

before usort:

naming => 1
packaging => 2
research => 3
strategy => 4

after usort:

research => 3
strategy => 4
naming => 1
packaging => 2
kuroi neko
  • 8,479
  • 1
  • 19
  • 43