How to Sort Biblical Scriptures Programmatically in WordPress

During a recent project for a local church, we had a unique challenge presented to us – provide a mechanism to sort recorded sermons which are tagged by the Biblical references made during the sermon and in the proper canonical order in the Bible. While there are several ways to accomplish this, we wanted to keep a consistent user experience for the end user who was actually populating this content — the scriptures referenced are a single text field written in the traditional “Book Name, Chapter:Verse” format (eg Matthew 4:1). Here’s how to sort biblical scriptures programmatically in WordPress:

Custom Sorting with PHP’s usort and uksort

In order to programmatically sort recorded sermons by their related biblical scriptures, we used the WordPress custom post type for the recorded sermons, and a custom meta field for the sermon reference. The basic principle for this could apply to any scenario by which you need to sort items with multiple data points by some specific, but arbitrary, order.

1. Define the Correct Order of the Books

Before we get too far into this specific use-case, we need to make sure to define the correct order of the books in the Bible. Perhaps the biggest downside to this implementation is that the written book names must match the entries in this array exactly. Fortunately, there’s no penalty to redundancy, misspellings, alternate names, etc. in this list. The list shown specifically below did the trick:

//manual scripture sort order
$scripture_order = array(
  'Genesis',
  'Exodus',
  'Leviticus',
  'Numbers',
  'Deuteronomy',
  'Joshua',
  'Judges',
  'Ruth',
  '1Samuel',
  '2Samuel',
  '1Kings',
  '2Kings',
  '1Chronicles',
  '2Chronicles',
  'Ezra',
  'Nehemiah',
  'Esther',
  'Job',
  'Psalms',
  'Proverbs',
  'Ecclesiastes',
  'Song of Solomon',
  'Song of Songs',
  'Song',
  'Isaiah',
  'Jeremiah',
  'Lamentations',
  'Ezekiel',
  'Daniel',
  'Hosea',
  'Joel',
  'Amos',
  'Obadiah',
  'Jonah',
  'Micah',
  'Nahum',
  'Habakkuk',
  'Zephaniah',
  'Haggai',
  'Zechariah',
  'Malachi',
  'Matthew',
  'Mark',
  'Luke',
  'John',
  'Acts',
  'Romans',
  '1Corinthians',
  '2Corinthians',
  'Galatians',
  'Ephesians',
  'Philippians',
  'Colossians',
  '1Thessalonians',
  '2Thessalonians',
  '1Timothy',
  '2Timothy',
  'Titus',
  'Philemon',
  'Hebrews',
  'James',
  '1Peter',
  '2Peter',
  '1John',
  '2John',
  '3John',
  'Jude',
  'Revelation'
);

With this list, we can use php’s usort and uksort functions, which allow you to sort an array with a custom comparison function, to get the sermons ordered correctly. Since this was in WordPress, and the recorded sermons are stored as a custom post type, our comparison function will take two posts and compare by the corresponding post meta field for the scripture reference.

2. Group Posts by the Reference Meta Value

Once we have an array of sermon posts, we can first group them all by the sermon reference. To do this, we’ll loop through them all, grab the sermon reference meta value, trim it down to the first word by splitting the value with strtok (which is the Bible book we want to sort by first), and create an array with the scripture reference as the key (if it doesn’t already exist) and then put this post in that array.

$sermons = array();
foreach ($posts as $post) {
  $sref = get_post_meta($post>ID, 'scripture_ref', true);
  $sref = strtok($sref, " ");
  if (!isset($sermons[$sref])) { $sermons[$sref] = array(); }
  array_push($sermons[$sref], $post);
}

3. Use uksort to Sort Each Array

Now we have an array of arrays that we can sort by our previously defined array. Array! Our scripture reference is the key of the sermons array, so we use uksort here in order to sort each array of sermons by the order in which the sermon key appears in the original scripture order array we created in step 1. Our comparison function is sorting our sermons by the scripture order by comparing their relative position in the array with array_search.

uksort($sermons, function($a, $b) use ($scripture_order) {
  return ((array_search($a, $scripture_order) > array_search($b, $scripture_order)) ? 1 : -1);
});

4. Set up a Custom Function to Sort Each Book by Chapter and Verse

Now, we should have our sermons array in the proper book order, but the chapters and verses are still not right. We can loop through each set of posts (for each book) and further sort them by chapter and verse. Using array_keys will give us all the scripture references that the set of sermon posts has and we’ll loop through each set and use usort here for yet another custom function to sort these sermons by the chapter and verse portion of the meta value.

$srefs = array_keys($sermons);
foreach($srefs as $sf) {
  $sorting_now = $sermons[$sf];
  usort($sorting_now, 'sort_sermons_by_postmeta');
  $sermons[$sf] = $sorting_now;
}

This time we pass a function name to usort, sort_sermons_by_postmeta, which is about as descriptive a function name as we can do here. First, we get those scripture reference meta values for each post we’re comparing, then use a regular expression to get the chapter and verse out of that value. Since these are written naturally, and we want to sort them numerically, we will pad a string of 0s to account for sorting 11 after 1, use a decimal instead of a colon, and convert our new number to a float value.

This will make sure that chapter/verse references like “1:1”, “1:2”, and “1:11” are sorted numerically as 1.01,1.02, and 1.11 — thus appearing in the proper ascending order.

function sort_sermons_by_postmeta( $posta, $postb ) {
  $a = get_post_meta( $posta->ID, 'scripture_ref', true );
  $b = get_post_meta( $postb->ID, 'scripture_ref', true );

  preg_match('/([A-Za-z]+) (\d+):(\d+) (.*)/', $a, $matcha);
  preg_match('/([A-Za-z]+) (\d+):(\d+) (.*)/', $b, $matchb);

  //matcha[2] and matchb[2] are now the book number, like "4" in "Matthew 4:1”

  $numA = floatval($matcha[2].'.'.str_pad($matcha[3],2,'0',STR_PAD_LEFT));
  $numB = floatval($matchb[2].'.'.str_pad($matchb[3],2,'0',STR_PAD_LEFT));
  if ( $numA === $numB ) {
    return 0;
  } else if ( $numA > $numB ) {
    return 1;
  } else {
    return -1;
  }
}

5. Merge Each Array into a Single Dimensional Array

Now, we take each array of posts in the array of sermons keyed by scripture reference and put them in a single dimensional array of all posts in the correct book, chapter, and verse order.

$sorted_sermons = array();
foreach ($sermons as $sref => $these_sermons) {
  $sorted_sermons = array_merge($sorted_sermons, $these_sermons);
}

There! Now you can loop through your sorted sermons and display them to your users along with any other images, content, or metadata you need. Or, you can sort something else. Or, take a break and have lunch — usort your day however you want to.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.