connectors/class-connector-acf.php

Summary

Maintainability
F
6 days
Test Coverage
F
55%
<?php
/**
 * Connector - Advanced Custom Fields
 *
 * @package WP_Stream
 */

namespace WP_Stream;

/**
 * Class - Connector_ACF
 */
class Connector_ACF extends Connector {
    /**
     * Connector slug
     *
     * @var string
     */
    public $name = 'acf';

    /**
     * Holds tracked plugin minimum version required
     *
     * @const string
     */
    const PLUGIN_MIN_VERSION = '4.3.8';

    /**
     * Actions registered for this connector
     *
     * @var array
     */
    public $actions = array(
        'save_post',
        'post_updated',
        'added_post_meta',
        'updated_post_meta',
        'delete_post_meta',
        'added_user_meta',
        'updated_user_meta',
        'delete_user_meta',
        'added_option',
        'updated_option',
        'deleted_option',
        'pre_post_update',
    );

    /**
     * Cached location rules, used in shutdown callback to verify changes in meta
     *
     * @var array
     */
    public $cached_location_rules = array();

    /**
     * Cached field values updates, used by shutdown callback to verify actual changes
     *
     * @var array
     */
    public $cached_field_values_updates = array();


    /**
     * Check if plugin dependencies are satisfied and add an admin notice if not
     *
     * @return bool
     */
    public function is_dependency_satisfied() {
        if ( class_exists( 'acf' ) ) { // TODO: Should this be function_exists?
            $acf = \acf();
            if ( version_compare( $acf->settings['version'], self::PLUGIN_MIN_VERSION, '>=' ) ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Return translated connector label
     *
     * @return string Translated connector label
     */
    public function get_label() {
        return esc_html_x( 'ACF', 'acf', 'stream' );
    }

    /**
     * Return translated action labels
     *
     * @return array Action label translations
     */
    public function get_action_labels() {
        return array(
            'created' => esc_html_x( 'Created', 'acf', 'stream' ),
            'updated' => esc_html_x( 'Updated', 'acf', 'stream' ),
            'added'   => esc_html_x( 'Added', 'acf', 'stream' ),
            'deleted' => esc_html_x( 'Deleted', 'acf', 'stream' ),
        );
    }

    /**
     * Return translated context labels
     *
     * @return array Context label translations
     */
    public function get_context_labels() {
        return array(
            'field_groups' => esc_html_x( 'Field Groups', 'acf', 'stream' ),
            'fields'       => esc_html_x( 'Fields', 'acf', 'stream' ),
            'rules'        => esc_html_x( 'Rules', 'acf', 'stream' ),
            'options'      => esc_html_x( 'Options', 'acf', 'stream' ),
            'values'       => esc_html_x( 'Values', 'acf', 'stream' ),
        );
    }

    /**
     * Register the connector
     */
    public function register() {
        add_filter( 'wp_stream_log_data', array( $this, 'log_override' ) );

        /**
         * Allow devs to disable logging values of rendered forms
         *
         * @return bool
         */
        if ( apply_filters( 'wp_stream_acf_enable_value_logging', true ) ) {
            $this->actions[] = 'acf/update_value';
        }

        parent::register();
    }

    /**
     * Add action links to Stream drop row in admin list screen
     *
     * @filter wp_stream_action_links_{connector}
     *
     * @param array  $links  Previous links registered.
     * @param object $record Stream record.
     *
     * @return array          Action links
     */
    public function action_links( $links, $record ) {
        $posts_connector = new Connector_Posts();
        $links           = $posts_connector->action_links( $links, $record );

        return $links;
    }

    /**
     * Tracks the creation of custom field group fields and settings (ACF v5+ only)
     *
     * @action save_post
     *
     * @param int     $post_id Post ID.
     * @param WP_Post $post    Post object.
     * @param bool    $update  Whether this is an existing post being updated or not.
     */
    public function callback_save_post( $post_id, $post, $update ) {
        // Bail if updating existing post.
        if ( false !== $update ) {
            return;
        }

        // Log new ACF field additions to field groups.
        if ( 'acf-field' === $post->post_type ) {
            $parent = get_post( $post->post_parent );
            if ( $parent ) {
                $this->log_prop( 'added', $post_id, $post, 'parent', $parent );
            }
        } elseif ( 'acf-field-group' === $post->post_type ) {
            $props = maybe_unserialize( $post->post_content );

            if ( ! empty( $props ) && is_array( $props ) ) {
                foreach ( $props as $prop => $value ) {
                    $this->log_prop( 'added', $post_id, $post, $prop, $value );
                }
            }
        }
    }

    /**
     * Tracks changes to custom field groups settings.
     *
     * @action post_updated
     *
     * @param int      $post_id       Post ID.
     * @param \WP_Post $posts_after   Newly saved post object.
     * @param \WP_Post $posts_before  Old post object.
     * @return void
     */
    public function callback_post_updated( $post_id, $posts_after, $posts_before ) {
        if ( 'acf-field-group' !== $posts_after->post_type ) {
            return;
        }

        $_new = ! empty( $posts_after->post_content ) ? maybe_unserialize( $posts_after->post_content ) : array();
        $_old = ! empty( $posts_before->post_content ) ? maybe_unserialize( $posts_before->post_content ) : array();

        // Get updated settings.
        $updated_keys = $this->get_changed_keys( $_new, $_old );
        $updated_keys = empty( $updated_keys ) ? array_keys( $_new ) : $updated_keys;

        // Process updated properties.
        foreach ( $updated_keys as $prop ) {
            $old_value = null;
            $value     = $_new[ $prop ];
            if ( empty( $value ) && is_array( $_old ) && ! empty( $_old[ $prop ] ) ) {
                $action    = 'deleted';
                $old_value = $_old[ $prop ];
            } else {
                $action = 'updated';
            }

            $this->log_prop( $action, $post_id, $posts_after, $prop, $value, $old_value );
        }
    }


    /**
     * Logs field/field group property changes (ACF v5 only).
     *
     * @param string     $action     Added, updated, deleted.
     * @param int        $post_id    Post ID.
     * @param WP_Post    $post       Post object.
     * @param string     $property   ACF property.
     * @param mixed|null $value      Value assigned to property.
     * @param mixed|null $old_value  Old value previously assigned to property.
     * @return void
     */
    public function log_prop( $action, $post_id, $post, $property, $value = null, $old_value = null ) {
        $action_labels = $this->get_action_labels();

        // Fields.
        if ( 'parent' === $property ) {
            if ( 'deleted' === $action ) {
                $meta_value = $old_value;
            }

            $this->log(
                /* translators: %1$s: field label, %2$s: form title, %3$s: action (e.g. "Message", "Contact", "Created") */
                esc_html_x( '"%1$s" field in "%2$s" %3$s', 'acf', 'stream' ),
                array(
                    'label'  => $post->post_title,
                    'title'  => $value->post_title,
                    'action' => strtolower( $action_labels[ $action ] ),
                    'key'    => $post->post_name,
                    'name'   => $post->post_excerpt,
                ),
                $value->ID,
                'fields',
                $action
            );
        } elseif ( 'position' === $property ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'acf_after_title' => esc_html_x( 'High (after title)', 'acf', 'stream' ),
                'normal'          => esc_html_x( 'Normal (after content)', 'acf', 'stream' ),
                'side'            => esc_html_x( 'Side', 'acf', 'stream' ),
            );

            $this->log(
                /* translators: %1$s: form title, %2$s a position (e.g. "Contact", "Side") */
                esc_html_x( 'Position of "%1$s" updated to "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options[ $value ],
                    'option'       => $property,
                    'option_value' => $value,
                ),
                $post_id,
                'options',
                'updated'
            );
        } elseif ( 'layout' === $property ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'no_box'  => esc_html_x( 'Seamless (no metabox)', 'acf', 'stream' ),
                'default' => esc_html_x( 'Standard (WP metabox)', 'acf', 'stream' ),
            );

            $this->log(
                /* translators: %1$s: form title, %2$s a layout (e.g. "Contact", "Seamless") */
                esc_html_x( 'Style of "%1$s" updated to "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options[ $value ],
                    'option'       => $property,
                    'option_value' => $value,
                ),
                $post_id,
                'options',
                'updated'
            );
        } elseif ( 'hide_on_screen' === $property ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'permalink'       => esc_html_x( 'Permalink', 'acf', 'stream' ),
                'the_content'     => esc_html_x( 'Content Editor', 'acf', 'stream' ),
                'excerpt'         => esc_html_x( 'Excerpt', 'acf', 'stream' ),
                'custom_fields'   => esc_html_x( 'Custom Fields', 'acf', 'stream' ),
                'discussion'      => esc_html_x( 'Discussion', 'acf', 'stream' ),
                'comments'        => esc_html_x( 'Comments', 'acf', 'stream' ),
                'revisions'       => esc_html_x( 'Revisions', 'acf', 'stream' ),
                'slug'            => esc_html_x( 'Slug', 'acf', 'stream' ),
                'author'          => esc_html_x( 'Author', 'acf', 'stream' ),
                'format'          => esc_html_x( 'Format', 'acf', 'stream' ),
                'featured_image'  => esc_html_x( 'Featured Image', 'acf', 'stream' ),
                'categories'      => esc_html_x( 'Categories', 'acf', 'stream' ),
                'tags'            => esc_html_x( 'Tags', 'acf', 'stream' ),
                'send-trackbacks' => esc_html_x( 'Send Trackbacks', 'acf', 'stream' ),
            );

            if ( is_array( $value ) && count( $options ) === count( $value ) ) {
                $options_label = esc_html_x( 'All screens', 'acf', 'stream' );
            } elseif ( empty( $value ) ) {
                $options_label = esc_html_x( 'No screens', 'acf', 'stream' );
            } else {
                $options_label = implode( ', ', array_intersect_key( $options, array_flip( $value ) ) );
            }

            $this->log(
                /* translators: %1$s: a form title, %2$s: a display option (e.g. "Contact", "All screens") */
                esc_html_x( '"%1$s" set to display on "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options_label,
                    'option'       => $property,
                    'option_value' => $value,
                ),
                $post_id,
                'options',
                'updated'
            );
        }
    }

    /**
     * Track addition of post meta
     *
     * @action added_post_meta
     */
    public function callback_added_post_meta() {
        $this->check_meta( 'post', 'added', ...func_get_args() );
    }

    /**
     * Track updating post meta
     *
     * @action updated_post_meta
     */
    public function callback_updated_post_meta() {
        $this->check_meta( 'post', 'updated', ...func_get_args() );
    }

    /**
     * Track deletion of post meta
     *
     * Note: Using delete_post_meta instead of deleted_post_meta to be able to
     * capture old field value
     *
     * @action delete_post_meta
     */
    public function callback_delete_post_meta() {
        $this->check_meta( 'post', 'deleted', ...func_get_args() );
    }

    /**
     * Track addition of user meta
     *
     * @action added_user_meta
     */
    public function callback_added_user_meta() {
        $this->check_meta( 'user', 'added', ...func_get_args() );
    }

    /**
     * Track updating user meta
     *
     * @action updated_user_meta
     */
    public function callback_updated_user_meta() {
        $this->check_meta( 'user', 'updated', ...func_get_args() );
    }

    /**
     * Track deletion of user meta
     *
     * Note: Using delete_user_meta instead of deleted_user_meta to be able to
     * capture old field value
     *
     * @action delete_user_meta
     */
    public function callback_delete_user_meta() {
        $this->check_meta( 'user', 'deleted', ...func_get_args() );
    }

    /**
     * Track addition of post/user meta
     *
     * @param string     $type       Type of object, post or user.
     * @param string     $action     Added, updated, deleted.
     * @param integer    $meta_id    Meta ID.
     * @param integer    $object_id  Object ID.
     * @param string     $meta_key   Meta Key.
     * @param mixed|null $meta_value Value being stored in meta.
     */
    public function check_meta( $type, $action, $meta_id, $object_id, $meta_key, $meta_value = null ) {
        $post = get_post( $object_id );
        if ( 'post' !== $type || ! $post || ! in_array( $post->post_type, array( 'acf', 'acf-field-group' ), true ) ) {
            $this->check_meta_values( $type, $action, $meta_id, $object_id, $meta_key, $meta_value );
            return;
        }

        $action_labels = $this->get_action_labels();

        // Fields.
        if ( 0 === strpos( $meta_key, 'field_' ) ) {
            if ( 'deleted' === $action ) {
                $meta_value = get_post_meta( $object_id, $meta_key, true );
            }

            $this->log(
                /* translators: %1$s: field label, %2$s: form title, %3$s: action (e.g. "Message", "Contact", "Created") */
                esc_html_x( '"%1$s" field in "%2$s" %3$s', 'acf', 'stream' ),
                array(
                    'label'  => $meta_value['label'],
                    'title'  => $post->post_title,
                    'action' => strtolower( $action_labels[ $action ] ),
                    'key'    => $meta_value['key'],
                    'name'   => $meta_value['name'],
                ),
                $object_id,
                'fields',
                $action
            );
        } elseif ( 'rule' === $meta_key ) {
            if ( 'deleted' === $action ) {
                $this->cached_location_rules[ $object_id ] = get_post_meta( $object_id, 'rule' );

                add_action( 'shutdown', array( $this, 'check_location_rules' ), 9 );
            }
        } elseif ( 'position' === $meta_key ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'acf_after_title' => esc_html_x( 'High (after title)', 'acf', 'stream' ),
                'normal'          => esc_html_x( 'Normal (after content)', 'acf', 'stream' ),
                'side'            => esc_html_x( 'Side', 'acf', 'stream' ),
            );

            $this->log(
                /* translators: %1$s: form title, %2$s a position (e.g. "Contact", "Side") */
                esc_html_x( 'Position of "%1$s" updated to "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options[ $meta_value ],
                    'option'       => $meta_key,
                    'option_value' => $meta_value,
                ),
                $object_id,
                'options',
                $action
            );
        } elseif ( 'layout' === $meta_key ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'no_box'  => esc_html_x( 'Seamless (no metabox)', 'acf', 'stream' ),
                'default' => esc_html_x( 'Standard (WP metabox)', 'acf', 'stream' ),
            );

            $this->log(
                /* translators: %1$s: form title, %2$s a layout (e.g. "Contact", "Seamless") */
                esc_html_x( 'Style of "%1$s" updated to "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options[ $meta_value ],
                    'option'       => $meta_key,
                    'option_value' => $meta_value,
                ),
                $object_id,
                'options',
                'updated'
            );
        } elseif ( 'hide_on_screen' === $meta_key ) {
            if ( 'deleted' === $action ) {
                return;
            }

            $options = array(
                'permalink'       => esc_html_x( 'Permalink', 'acf', 'stream' ),
                'the_content'     => esc_html_x( 'Content Editor', 'acf', 'stream' ),
                'excerpt'         => esc_html_x( 'Excerpt', 'acf', 'stream' ),
                'custom_fields'   => esc_html_x( 'Custom Fields', 'acf', 'stream' ),
                'discussion'      => esc_html_x( 'Discussion', 'acf', 'stream' ),
                'comments'        => esc_html_x( 'Comments', 'acf', 'stream' ),
                'revisions'       => esc_html_x( 'Revisions', 'acf', 'stream' ),
                'slug'            => esc_html_x( 'Slug', 'acf', 'stream' ),
                'author'          => esc_html_x( 'Author', 'acf', 'stream' ),
                'format'          => esc_html_x( 'Format', 'acf', 'stream' ),
                'featured_image'  => esc_html_x( 'Featured Image', 'acf', 'stream' ),
                'categories'      => esc_html_x( 'Categories', 'acf', 'stream' ),
                'tags'            => esc_html_x( 'Tags', 'acf', 'stream' ),
                'send-trackbacks' => esc_html_x( 'Send Trackbacks', 'acf', 'stream' ),
            );

            if ( count( $options ) === count( $meta_value ) ) {
                $options_label = esc_html_x( 'All screens', 'acf', 'stream' );
            } elseif ( empty( $meta_value ) ) {
                $options_label = esc_html_x( 'No screens', 'acf', 'stream' );
            } else {
                $options_label = implode( ', ', array_intersect_key( $options, array_flip( $meta_value ) ) );
            }

            $this->log(
                /* translators: %1$s: a form title, %2$s: a display option (e.g. "Contact", "All screens") */
                esc_html_x( '"%1$s" set to display on "%2$s"', 'acf', 'stream' ),
                array(
                    'title'        => $post->post_title,
                    'option_label' => $options_label,
                    'option'       => $meta_key,
                    'option_value' => $meta_value,
                ),
                $object_id,
                'options',
                'updated'
            );
        }
    }

    /**
     * Track changes to ACF values within rendered post meta forms
     *
     * @param string     $type       Type of object, post or user.
     * @param string     $action     Added, updated, deleted.
     * @param integer    $meta_id    Meta ID.
     * @param integer    $object_id  Object ID.
     * @param string     $key        Meta Key.
     * @param mixed|null $value      Value being stored in meta.
     *
     * @return bool
     */
    public function check_meta_values( $type, $action, $meta_id, $object_id, $key, $value = null ) {
        unset( $action );
        unset( $meta_id );

        if ( empty( $this->cached_field_values_updates ) ) {
            return false;
        }

        $object_key = $object_id;

        if ( 'user' === $type ) {
            $object_key = 'user_' . $object_id;
        } elseif ( 'taxonomy' === $type ) {
            if ( 0 === strpos( $key, '_' ) ) { // Ignore the 'revision' stuff!.
                return false;
            }

            if ( 1 !== preg_match( '#([a-z0-9_-]+)_([\d]+)_([a-z0-9_-]+)#', $key, $matches ) ) {
                return false;
            }

            list( , $taxonomy, $term_id, $key ) = $matches; // Skips 0 index.

            $object_key = $taxonomy . '_' . $term_id;
        } elseif ( 'option' === $type ) {
            $object_key = 'options';
            $key        = preg_replace( '/^options_/', '', $key );
        }

        if ( isset( $this->cached_field_values_updates[ $object_key ][ $key ] ) ) {
            if ( 'post' === $type ) {
                $posts_connector = new Connector_Posts();

                $post      = get_post( $object_id );
                $title     = $post->post_title;
                $type_name = strtolower( $posts_connector->get_post_type_name( $post->post_type ) );
            } elseif ( 'user' === $type ) {
                $user      = new \WP_User( $object_id );
                $title     = $user->get( 'display_name' );
                $type_name = esc_html__( 'user', 'stream' );
            } elseif ( 'taxonomy' === $type && isset( $term_id ) && isset( $taxonomy ) ) {
                $term      = get_term( $term_id, $taxonomy );
                $title     = $term->name;
                $tax_obj   = get_taxonomy( $taxonomy );
                $type_name = strtolower( get_taxonomy_labels( $tax_obj )->singular_name );
            } elseif ( 'option' === $type ) {
                $title     = 'settings page';
                $type_name = 'option';
            } else {
                return false;
            }

            $cache = $this->cached_field_values_updates[ $object_key ][ $key ];

            $this->log(
                /* translators: %1$s: a field label, %2$s: an object title, %3$s: an object type (e.g. "Message", "Hello World", "post") */
                esc_html_x( '"%1$s" of "%2$s" %3$s updated', 'acf', 'stream' ),
                array(
                    'field_label'   => $cache['field']['label'],
                    'title'         => $title,
                    'singular_name' => $type_name,
                    'meta_value'    => $value,
                    'meta_key'      => $key,
                    'meta_type'     => $type,
                ),
                $object_id,
                'values',
                'updated'
            );
        }

        return true;
    }

    /**
     * Track changes to rules, complements post-meta updates
     *
     * @action shutdown
     */
    public function check_location_rules() {
        foreach ( $this->cached_location_rules as $post_id => $old ) {
            $new  = get_post_meta( $post_id, 'rule' );
            $post = get_post( $post_id );

            if ( $old === $new ) {
                continue;
            }

            $new     = array_map( 'wp_stream_json_encode', $new );
            $old     = array_map( 'wp_stream_json_encode', $old );
            $added   = array_diff( $new, $old );
            $deleted = array_diff( $old, $new );

            $this->log(
                /* translators: %1$s: a form title, %2$d: the number of rules added, %3$d: the number of rules deleted (e.g. "Contact", "42", "7") */
                esc_html_x( 'Updated rules of "%1$s" (%2$d added, %3$d deleted)', 'acf', 'stream' ),
                array(
                    'title'      => $post->post_title,
                    'no_added'   => count( $added ),
                    'no_deleted' => count( $deleted ),
                    'added'      => $added,
                    'deleted'    => $deleted,
                ),
                $post_id,
                'rules',
                'updated'
            );
        }
    }

    /**
     * Override connector log for our own Settings / Actions
     *
     * @param array $data  Record data.
     *
     * @return array|bool
     */
    public function log_override( $data ) {
        if ( ! is_array( $data ) ) {
            return $data;
        }

        $is_acf_context = in_array( $data['context'], array( 'acf', 'acf-field-group', 'acf-field' ), true );

        if ( 'posts' === $data['connector'] && $is_acf_context ) {
            // If ACF field group CPT being logged.
            if ( 'acf' === $data['context'] || 'acf-field-group' === $data['context'] ) {
                $data['context']               = 'field_groups';
                $data['connector']             = $this->name;
                $data['args']['singular_name'] = esc_html__( 'field group', 'stream' );

                // elseif ACF field CPT being logged (ACF v5+ only).
            } elseif ( 'acf-field' === $data['context'] ) {
                $field_group = get_post( wp_get_post_parent_id( $data['object_id'] ) );

                $data['context']               = 'fields';
                $data['connector']             = $this->name;
                $data['args']['singular_name'] = ! empty( $field_group )
                    ? sprintf(
                        /* translators: %s: field group name */
                        esc_html__( 'field in the "%s" field group', 'stream' ),
                        $field_group->post_title
                    )
                    : esc_html__( 'field', 'stream' );
            }
        }

        return $data;
    }

    /**
     * Track changes to custom field values updates, saves filtered values to be
     * processed by callback_updated_post_meta
     *
     * @param string $value    Field value.
     * @param int    $post_id  Field post ID.
     * @param string $field    Field name.
     *
     * @return string
     */
    public function callback_acf_update_value( $value, $post_id, $field ) {
        $this->cached_field_values_updates[ $post_id ][ $field['name'] ] = compact( 'field', 'value', 'post_id' );
        return $value;
    }

    /**
     * Track changes to post main attributes, ie: Order No.
     *
     * @param int   $post_id Field post ID.
     * @param array $data    Array with the updated post data.
     */
    public function callback_pre_post_update( $post_id, $data ) {
        $post = get_post( $post_id );

        if ( 'acf' !== $post->post_type ) {
            return;
        }

        // menu_order, aka Order No.
        if ( $data['menu_order'] !== $post->menu_order ) {
            $this->log(
                /* translators: %1$s: a form title, %2$d: a numeric position, %3$d: numeric position (e.g. "Contact", "42", "7") */
                esc_html_x( '"%1$s" reordered from %2$d to %3$d', 'acf', 'stream' ),
                array(
                    'title'          => $post->post_title,
                    'old_menu_order' => $post->menu_order,
                    'menu_order'     => $data['menu_order'],
                ),
                $post_id,
                'field_groups',
                'updated'
            );
        }
    }

    /**
     * Track addition of new options
     *
     * @param string $key   Option name.
     * @param string $value Option value.
     */
    public function callback_added_option( $key, $value ) {
        $this->check_meta_values( self::get_saved_option_type( $key ), 'added', null, null, $key, $value );
    }

    /**
     * Track addition of new options
     *
     * @param string $key   Option key.
     * @param string $old   Old value.
     * @param string $value New value.
     */
    public function callback_updated_option( $key, $old, $value ) {
        unset( $old );
        $this->check_meta_values( self::get_saved_option_type( $key ), 'updated', null, null, $key, $value );
    }

    /**
     * Track addition of new options
     *
     * @param string $key Option key.
     */
    public function callback_deleted_option( $key ) {
        $this->check_meta_values( self::get_saved_option_type( $key ), 'deleted', null, null, $key, null );
    }

    /**
     * Determines the type of option that is saved
     *
     * @param string $key Option key.
     * @return string
     */
    private function get_saved_option_type( $key ) {
        return substr( $key, 0, 8 ) === 'options_' ? 'option' : 'taxonomy';
    }
}