1. Home
  2. Docs
  3. Rules Developer Guide
  4. Extending Rules
  5. Class Map

Class Map

The class map is a data structure which describes object models and the associated data that can be derived from them. It allows the Rules plugin to use one piece of data to derive another. If your plugin uses its own object models to represent data, then extending the rules class map will allow rules to access your data points.

As an example, the class map tells Rules how to turn an integer (user_id) into a WP_User object, and then get the email address from that user. This allows rule configurations to use the data provided by events and arrive at related pieces of data needed by conditions and actions assigned to the rule.

Extending the rules class map can be done using the rules_class_map filter.

function myplugin_rules_class_map( $map ) {
    return array_replace_recursive( $map, array(
        // class mappings...
    ));
}
add_filter( 'rules_class_map', 'myplugin_rules_class_map' );

In the example above, you’ll notice that the $map array is being extended using the array_replace_recursive native PHP function. This is best practice since it ensures that other extensions of classes which may have already been added to the map are not overwritten, but are effectively spliced in.

The map itself is just an array which contains keys that correspond to the full class name of the object being mapped. You can extend the properties of existing classes and/or add your own classes to the map.

/**
 * @param  array  {
 *     The class map is an array whose primary keys are the fully qualified class 
 *     names of the objects they are mapping.
 *
 *     classname => array {
 *         Object attributes.
 *
 *         @type  string    (optional)  'label'     The label for the object type
 *         @type  callable  (optional)  'loader'    {
 *             A callback function used to load instances of the class given a primitive
 *             data type (such as an int or string).
 *
 *             param  mixed        $val    The value which represents an instance of this class
 *             param  string       $type   The type of the value (int, string, etc)
 *             param  string|NULL  $key    The key provided (if any) by the class assertion.
 *                                         For example, if a piece of data asserts to be
 *                                         a 'string' of class 'WP_User[email]', then the
 *                                         value of $key will be 'email'. If the argument 
 *                                         asserted a class of 'WP_User', then $key is NULL.
 *             return object|NULL          The loader should return a loaded instance of
 *                                         the class, or NULL if loading was not possible
 *         }
 *         @type  callable  (optional)  'reference'    {
 *             A callback function used to get a reference to the given object. The reference value
 *             should be compatible with your 'loader' to restore the object at a later time. 
 *             (Usually an ID of the item).
 *
 *             param  object     $object   The object
 *             return mixed                The reference value should be a scalar value which can
 *                                         be used by the loader to restore the object later. If
 *                                         you need to pass your loader a key to know how to load
 *                                         the object, return an array with the first value being
 *                                         the object reference value, and the second value being
 *                                         the key to pass to your loader.
 *         }
 *         @type   array   (optional)   'mappings'   {
 *             An associative array of data points that can be derived from a class instance.
 *
 *             name => array {
 *                 Data attributes.
 *
 *                 @type  string   (required)  'argtype'   The type of the mapped data 
 *                 @type  string   (required)  'label'     The label for the mapped property
 *                 @type  string   (optional)  'class'     A class that this data can instantiate
 *                 @type  bool     (optional)  'nullable'  Indicates if the data is sometimes NULL
 *                                                         Default: false
 *                 @type  callable (required)  'getter'    {
 *                     A callback used to retrieve the data being mapped.
 *
 *                     param  object   $object      The instance of the class this data is mapped to
 *                     return mixed
 *                 }
 *                 @type  array (optional)  'keys'    {
 *                     An associative array describing key/value pairs for 'array' argtypes
 * 
 *                     @type  bool     (optional)  'associative'  Indicates that the keys are associative
 *                     @type  bool     (optional)  'fixed'        Indicates that the only keys that are
 *                                                                retrievable are the ones that are mapped
 *                     @type  callable (optional)  'getter'    {
 *                         A callback used to retrieve specific key values from the array
 *
 *                         param  object     $object   The instance of the class this data is mapped to
 *                         param  int|string $key      The array key to retrieve
 *                         return mixed
 *                     }
 *                     @type  array   (optional)  'mappings'   {
 *                         An associative array of key/value mappings for the array
 *
 *                             key => array {
 *                                 @type  string   (required)  'argtype'   The type of the mapped data 
 *                                 @type  string   (required)  'label'     The label for the mapped property
 *                                 @type  string   (optional)  'class'     A class this data can instantiate
 *                             }
 *                     }
 *                     @type  array   (optional)  'default'   {
 *                         An associative array of default argtype attributes assumed for all key/value pairs 
 *
 *                             @type  string   (required)  'argtype'   The type of the mapped data 
 *                             @type  string   (required)  'label'     The label for the mapped property
 *                             @type  string   (optional)  'class'     A class that this data can instantiate
 *                     }
 *
 *                 }
 *             }
 *         }
 *     } 
 * }
 *
 *
 */

@Example Code

function myplugin_rules_class_map( $map ) {
    return array_replace_recursive( $map, array(
        'WP_User' => array(
            'label' => 'User',
            'loader' => function( $val, $type, $key ) {
                switch( $type ) {
                    case 'int': return get_user_by('id', $val);
                    case 'string': return get_user_by($key, $val);
                }
            },
            'reference' => function( $user ) {
                return (int) $user->ID;
            },
            'mappings' => array(
                'id' => array(
                    'argtype' => 'int',
                    'label' => 'User ID',
                    'getter' => function( $user ) {
                        return $user->ID;
                    },
                ),
                'login' => array(
                    'argtype' => 'string',
                    'label' => 'Login Name',
                    'getter' => function( $user ) {
                        return $user->user_login;
                    },
                ),
                'first_name' => array(
                    'argtype' => 'string',
                    'label' => 'First Name',
                    'getter' => function( $user ) {
                        return $user->first_name;
                    },
                ),
                'last_name' => array(
                    'argtype' => 'string',
                    'label' => 'Last Name',
                    'getter' => function( $user ) {
                        return $user->last_name;
                    },
                ),
                'nicename' => array(
                    'argtype' => 'string',
                    'label' => 'Nice Name',
                    'getter' => function( $user ) {
                        return $user->user_nicename;
                    },
                ),
                'email' => array(
                    'argtype' => 'string',
                    'label' => 'Email',
                    'getter' => function( $user ) {
                        return $user->user_email;
                    },
                ),
                'website_url' => array(
                    'argtype' => 'string',
                    'class' => 'MWP\Rules\WP\Url',
                    'label' => 'Website',
                    'nullable' => true,
                    'getter' => function( $user ) {
                        return $user->user_url ?: null;
                    }
                ),
                'posts_url' => array(
                    'argtype' => 'string',
                    'class' => 'MWP\Rules\WP\Url',
                    'label' => 'Author Posts Url',
                    'getter' => function( $user ) {
                        return get_author_posts_url( $user->ID );
                    }
                ),
                'registered' => array(
                    'argtype' => 'object',
                    'label' => 'Registration Date',
                    'class' => 'DateTime',
                    'getter' => function( $user ) {
                        try {
                            return new \DateTime( $user->user_registered );
                        } catch( \Exception $e ) { 
                            return new \DateTime();
                        }
                    }
                ),
                'capabilities' => array(
                    'argtype' => 'array',
                    'label' => 'Capabilities',
                    'getter' => function( $user ) {
                        return $user->allcaps;
                    },
                    'keys' => array(
                        'associative' => true,
                        'default' => array( 'argtype' => 'bool', 'label' => 'Capability' ),
                    ),
                ),
                'roles' => array(
                    'argtype' => 'array',
                    'label' => 'Roles',
                    'getter' => function( $user ) {
                        return $user->roles;
                    }
                ),
                'meta' => array(
                    'argtype' => 'array',
                    'label' => 'Meta Data',
                    'getter' => function( $user ) {
                        $meta = array();
                        foreach( array_keys( get_user_meta( $user->ID ) ) as $meta_key ) {
                            $meta[ $meta_key ] = get_user_meta( $user->ID, $meta_key, true );
                        }
                        return $meta;
                    },
                    'keys' => array(
                        'associative' => true,
                        'getter' => function( $user, $meta_key ) {
                            return get_user_meta( $user->ID, $meta_key, true );
                        },
                        'mappings' => array(
                            'last_update' => array(
                                'argtype' => 'int',
                                'class' => 'DateTime',
                                'label' => 'Last Update',
                            ),
                        ),
                    ),
                ),
                'last_post' => array(
                    'argtype' => 'object',
                    'class' => 'WP_Post',
                    'label' => 'Latest Post',
                    'nullable' => true,
                    'getter' => function( $user ) {
                        $posts = get_posts( array(
                            'numberposts' => 1, 
                            'orderby' => 'date',
                            'order' => 'DESC',
                            'author' => $user->ID,
                        ));
                        if ( $posts ) {
                            return $posts[0];
                        }
                    }
                )
            ),
        ),
    ));
}
add_filter( 'rules_class_map', 'myplugin_rules_class_map' );

Note: The properties you map in the class map don’t need to correspond with actual properties of the object, only data that can be derived if given the object. This means that if your plugin manages some data which is associated with a user, it is perfectly fine to add a new mapped property to the rules class map for WP_User which allows rule configurations to access your data given a WP_User object.

function myplugin_rules_class_map( $map ) {
    return array_replace_recursive( $map, array(
        'WP_User' => array(
            'mappings' => array(
                'myplugin_datapoint' => array(
                    'argtype' => 'string',
                    'label' => 'My Plugin Data Point',
                    'getter' => function( $user ) {
                        return myplugin_get_user_datapoint( $user );
                    },
                ),
            ),
        ),
    ));
}
add_filter( 'rules_class_map', 'myplugin_rules_class_map' );
Was this article helpful to you? Yes No

How can we help?