Npm module classnames in PHP

March 26, 2020

If you’ve ever created any blocks for the Gutenberg editor, chance is that you’ve used the npm module classnames. Although it doesn’t have anything to do with specifically Gutenberg, that’s how I came in contact with it.

In short, it’s a method that takes different kind of objects (arrays, key-value pairs, etc.) and depending on what you send in to it, it’ll return a string which is the filtered classnames. Let’s see what the official documentation says.

A simple JavaScript utility for conditionally joining classNames together.
– From the classnames readme in the github repository

So that’s quite a neat functionality. And as I was working with rendering out templates in PHP, I noticed that I found myself wanting to use that method on the server as well. Subsequently, I rolled my own solution.

The code

It’s almost a complete port of the original javascript version, although modified to work with PHP constraints instead.

<?php

class CSSClassGenerator {
    static function classnames($arguments) {
        $classes = [];
        foreach($arguments as $key => $arg) {
            $argType = gettype($arg);

            if (gettype($key) === 'integer' && $argType === 'string') {
                $classes[] = $arg;
                continue;
            }

            if ($argType === 'string' || $argType === 'integer' || $argType === 'double') {
                if ($arg !== 0) {
                    $classes[] = $key;
                }
            } else if ($argType === 'boolean') {
                if ($arg === true) {
                    $classes[] = $key;
                }
            } else if ($argType === 'array') {
                $inner = self::classnames($arg);
                if ($inner) {
                    $classes[] = $inner;
                }
            }
        }

        return implode(' ', $classes);
    }
}

Usage

There’s a slight difference in how you use my version versus the original one. PHP doesn’t have a concept of objects in the same way Javascript does, but instead it uses associative arrays, so that’s what I’ve based my implementation on.

<?php
$size = FULL_WIDTH;
$color = 'green';

$containerClasses = CSSClassGenerator::classnames([
    'my-module',
    'my-module--full-width' => $size === FULL_WIDTH,
    'my-module--half-width' => $size === HALF_WIDTH,
    'my-module--third-width' => $size === THIRD_WIDTH,
    'my-module--background-' . $color => $color
    [
        // You can also nest arrays
        'my-module--is-large' => true,
        'my-module--is-small' => false,
    ]
]);

// $containerClasses = 'my-module my-module--full-width my-module--background-green my-module--is-large'
?>
<div class="<?php echo $containerClasses ?>">
    [....]
</div>

Conclusion

To sum up, the function helps a lot if you’re using BEM style in your css, because you can easily configure the variant classes in an easy to read and efficient manner.

Tags