Change numerals to ordinals with PHP

  • # March 27, 2013 at 2:37 pm

    Is there a way to change a dynamic set of numerals I’m using with a custom field (not WordPress) to ordinal?

    Example: 1, 2, 3, etc to first, second, third, etc.

    # March 27, 2013 at 2:47 pm

    If you’re going to words, you’ll need to write some pretty complicated stuff. You can do a simple change like this:

    # March 27, 2013 at 2:57 pm

    What I’m trying to do is convert my already existing custom field that outputs a basic number (1, 2, 3, etc) and convert it to an ordinal. I was hoping there was a way much like `str_replace`.

    To output a basic numeral with my custom field, I just do the following:

    < ?php echo html($page->numeral)) ?>

    So figured I would have to use a variable to start off to change it into an ordinal:

    < ?php
    $ordinal = html($page->numeral));
    // not sure where to go from there exactly

    # March 27, 2013 at 3:08 pm

    I found [this](

    If `$page->numeral` is an integer, you can probably do (not sure what the html function does):

    < ?php echo html(convert_number($page->numeral)); ?>

    Don’t think there’s a standard php function that does the same.

    # March 27, 2013 at 3:14 pm


    < ?php echo html(convert_number($page->numeral)); ?>


    Fatal error: Call to undefined function convert_number()

    # March 27, 2013 at 3:16 pm

    Yeah, you would need to include the function from the link I gave you. Easiest way is to make a separate php file to past that function in and use require_once to include that file where ever you need the function.

    # March 27, 2013 at 3:18 pm

    @CrocoDillon Oops. Completely missed that link. Will try again.

    # March 27, 2013 at 3:23 pm

    Hmmm I just tried it and it’s not entirely what you’re after. I’ll look further.

    # March 27, 2013 at 3:24 pm

    @CrocoDillon Correct. It just outputs `one`, `two`, `three`, etc.

    # March 27, 2013 at 3:38 pm

    < ?php class ShortScale {
    // Source: Wikipedia (
    private static $scale = array(”, ‘thousand’, ‘million’, ‘billion’, ‘trillion’, ‘quadrillion’, ‘quintillion’, ‘sextillion’, ‘octillion’, ‘nonillion’, ‘decillion’, ‘undecillion’, ‘duodecillion’, ‘tredecillion’, ‘quattuordecillion’, ‘quindecillion’, ‘sexdecillion’, ‘septendecillion’, ‘octodecillion’, ‘noverndecillion’, ‘vigintillion’);
    private static $digit = array(”, ‘one’, ‘two’, ‘three’, ‘four’, ‘five’, ‘six’, ‘seven’, ‘eight’, ‘nine’, ‘ten’, ‘eleven’, ‘twelve’, ‘thirteen’, ‘fourteen’, ‘fifteen’, ‘sixteen’, ‘seventeen’, ‘eighteen’, ‘nineteen’);
    private static $digith = array(”, ‘first’, ‘second’, ‘third’, ‘fourth’, ‘fifth’, ‘sixth’, ‘seventh’, ‘eighth’, ‘ninth’, ‘tenth’, ‘eleventh’, ‘twelfth’, ‘thirteenth’, ‘fourteenth’, ‘fiftheenth’, ‘sixteenth’, ‘seventeenth’, ‘eighteenth’, ‘nineteenth’);
    private static $ten = array(”, ”, ‘twenty’, ‘thirty’, ‘fourty’, ‘fifty’, ‘sixty’, ‘seventy’, ‘eighty’, ‘ninety’);
    private static $tenth = array(”, ”, ‘twentieth’, ‘thirtieth’, ‘fortieth’, ‘fiftieth’, ‘sixtieth’, ‘seventieth’, ‘eightieth’, ‘ninetieth’);

    private static function floatToArray($number, &$int, &$frac) {
    // Forced $number as (string), effectively to avoid (float) inprecision
    @list(, $frac) = explode(‘.’, $number);
    if ($frac || !is_numeric($number) || (strlen($number) > 60)) throw new Exception(‘Not a number or not a supported number type’);
    // $int = explode(‘,’, number_format(ltrim($number, ‘0’), 0, ”, ‘,’)); — Buggy
    $int = str_split(str_pad($number, ceil(strlen($number)/3)*3, ‘0’, STR_PAD_LEFT), 3);

    private static function thousandToEnglish($number) {
    // Gets numbers from 0 to 999 and returns the cardinal English
    $hundreds = floor($number / 100);
    $tens = $number % 100;
    $pre = ($hundreds ? self::$digit[$hundreds].’ hundred’ : ”);
    if ($tens < 20)
    $post = self::$digit[$tens];
    $post = trim(self::$ten[floor($tens / 10)].’ ‘.self::$digit[$tens % 10]);
    if ($pre && $post) return $pre.’ and ‘.$post;
    return $pre.$post;

    private static function cardinalToOrdinal($cardinal) {
    // Finds the last word in the cardinal arrays and replaces it with
    // the entry from the ordinal arrays, or appends “th”
    $words = explode(‘ ‘, $cardinal);
    $last = &$words[count($words)-1];
    if (in_array($last, self::$digit)) {
    $last = self::$digith[array_search($last, self::$digit)];
    } elseif (in_array($last, self::$ten)) {
    $last = self::$tenth[array_search($last, self::$ten)];
    } elseif (substr($last, -2) != ‘th’) {
    $last .= ‘th’;
    return implode(‘ ‘, $words);

    public static function toOrdinal($number) {
    // Converts a xth format number to English. e.g. 22nd to twenty-second.
    return trim(self::cardinalToOrdinal(self::toCardinal($number)));

    public static function toCardinal($number) {
    // Converts a number to English. e.g. 22 to twenty-two.
    self::floatToArray($number, $int, $frac);
    $int = array_reverse($int);
    for($i=count($int)-1; $i>-1; $i–) {
    $englishnumber = self::thousandToEnglish($int[$i]);
    if ($englishnumber)
    $english[] = $englishnumber.’ ‘.self::$scale[$i];
    $post = array_pop($english);
    $pre = implode(‘, ‘, $english);
    if ($pre && $post) return trim($pre.’ and ‘.$post);
    return trim($pre.$post);

    Put that in a separate php file instead. Use it like `< ?php echo html(ShortScale::toOrdinal($page->numeral)); ?>`


    # March 27, 2013 at 3:48 pm

    It’s spitting out errors. So what I think I’m going to do, which is easier, is to create an additional custom field and manually add the words for every article.

    That way I can just do this to output what I need:

    < ?php echo html($page->ordinal) ?>

    # March 27, 2013 at 3:49 pm

    It worked for me :) But yeah that’s easier.

    # March 27, 2013 at 3:51 pm

    But thanks to you both for taking the time to help me out. Really appreciate it.

    @CrocoDillion @TheDoc

    # March 27, 2013 at 3:53 pm

    No problem!

Viewing 15 posts - 1 through 15 (of 15 total)

You must be logged in to reply to this topic.