felixarntz/wp-site-identity

View on GitHub
src/admin-pages/class-wp-site-identity-standard-admin-page-registry.php

Summary

Maintainability
A
1 hr
Test Coverage
<?php
/**
 * WP_Site_Identity_Standard_Admin_Page_Registry class
 *
 * @package WPSiteIdentity
 * @since 1.0.0
 */

/**
 * Class responsible for registering admin pages.
 *
 * @since 1.0.0
 */
class WP_Site_Identity_Standard_Admin_Page_Registry implements WP_Site_Identity_Admin_Page_Registry {

    /**
     * Prefix to use for all admin page slugs within WordPress.
     *
     * @since 1.0.0
     * @var string
     */
    protected $prefix = '';

    /**
     * All registered admin pages as `$slug => $instance` pairs.
     *
     * @since 1.0.0
     * @var array
     */
    protected $admin_pages = array();

    /**
     * Factory to create admin page objects.
     *
     * @since 1.0.0
     * @var WP_Site_Identity_Admin_Page_Factory
     */
    protected $factory;

    /**
     * Map for admin page hook suffixes generated by WordPress.
     *
     * @since 1.0.0
     * @var array
     */
    protected $hook_suffixes = array();

    /**
     * Constructor.
     *
     * Sets the prefix to use for registered admin pages.
     *
     * @since 1.0.0
     *
     * @param string $prefix Prefix to use for all admin page slugs within WordPress.
     */
    public function __construct( $prefix ) {
        $this->prefix = $prefix;

        $this->factory = new WP_Site_Identity_Admin_Page_Factory( $this );
    }

    /**
     * Gets all registered admin pages.
     *
     * @since 1.0.0
     *
     * @return array Array of `$slug => $instance` pairs.
     */
    public function get_all_admin_pages() {
        return $this->admin_pages;
    }

    /**
     * Gets a registered admin page instance.
     *
     * @since 1.0.0
     *
     * @param string $slug Slug of the admin page.
     * @return WP_Site_Identity_Admin_Page Registered admin page.
     *
     * @throws WP_Site_Identity_Admin_Page_Not_Found_Exception Thrown when a admin page cannot be found.
     */
    public function get_admin_page( $slug ) {
        if ( ! isset( $this->admin_pages[ $slug ] ) ) {
            /* translators: %s: admin page slug */
            throw new WP_Site_Identity_Admin_Page_Not_Found_Exception( sprintf( __( 'The admin page with the slug %s could not be found.', 'wp-site-identity' ), $slug ) );
        }

        return $this->admin_pages[ $slug ];
    }

    /**
     * Checks whether a admin page is registered.
     *
     * @since 1.0.0
     *
     * @param string $slug Slug of the admin page.
     * @return bool True if the admin page is registered, false otherwise.
     */
    public function has_admin_page( $slug ) {
        return isset( $this->admin_pages[ $slug ] );
    }

    /**
     * Registers a new admin page.
     *
     * @since 1.0.0
     *
     * @param WP_Site_Identity_Admin_Page $admin_page Admin page to register.
     */
    public function register_admin_page( WP_Site_Identity_Admin_Page $admin_page ) {
        $slug = $admin_page->get_slug();

        $this->admin_pages[ $slug ] = $admin_page;

        $this->register_in_wp( $admin_page );
    }

    /**
     * Unregisters an existing admin page.
     *
     * @since 1.0.0
     *
     * @param WP_Site_Identity_Admin_Page $admin_page Admin page to unregister.
     */
    public function unregister_admin_page( WP_Site_Identity_Admin_Page $admin_page ) {
        $slug = $admin_page->get_slug();

        if ( ! isset( $this->admin_pages[ $slug ] ) ) {
            return;
        }

        $this->unregister_in_wp( $this->admin_pages[ $slug ] );

        unset( $this->admin_pages[ $slug ] );
    }

    /**
     * Gets the URL to a registered admin page.
     *
     * @since 1.0.0
     *
     * @param WP_Site_Identity_Admin_Page $admin_page Admin page to get the URL for.
     * @return string URL to the admin page.
     */
    public function get_url_to_admin_page( WP_Site_Identity_Admin_Page $admin_page ) {
        $slug = $admin_page->get_slug();

        $query_args = array();

        $parent_file = 'admin.php';
        if ( is_a( $admin_page, 'WP_Site_Identity_Admin_Submenu_Page' ) ) {
            $parent_slug = $admin_page->get_parent_slug();

            if ( false !== strpos( $parent_slug, '?' ) ) {
                list( $base_slug, $query ) = explode( '?', $parent_slug, 2 );

                $parent_query_args = explode( '&', $query );
                foreach ( $parent_query_args as $parent_query_arg ) {
                    if ( false === strpos( $parent_query_arg, '=' ) ) {
                        continue;
                    }

                    list( $key, $value ) = explode( '=', $parent_query_arg, 2 );

                    $query_args[ $key ] = $value;
                }
            } else {
                $base_slug = $parent_slug;
            }

            if ( '.php' === substr( $base_slug, -4 ) ) {
                $parent_file = $parent_slug;
            }
        }

        $query_args['page'] = $this->prefix . $slug;

        return add_query_arg( $query_args, admin_url( $parent_file ) );
    }

    /**
     * Gets the factory to create admin page objects.
     *
     * @since 1.0.0
     *
     * @return WP_Site_Identity_Admin_Page_Factory Factory to create admin page objects.
     */
    public function factory() {
        return $this->factory;
    }

    /**
     * Prefixes an admin page slug.
     *
     * If no slug is given, the prefix is simply returned.
     *
     * @since 1.0.0
     *
     * @param string $slug Admin page slug to prefix.
     * @return string Prefixed admin page slug.
     */
    public function prefix( $slug = '' ) {
        return $this->prefix . $slug;
    }

    /**
     * Handles an admin page in WordPress.
     *
     * @since 1.0.0
     * @internal
     */
    public function handle_in_wp() {
        // This is hooked in here, as there is no dedicated hook that includes $hook_suffix.
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_in_wp' ) );

        $hook_suffix = substr( current_action(), strlen( 'load-' ) );

        if ( ! isset( $this->hook_suffixes[ $hook_suffix ] ) ) {
            return;
        }

        $admin_page = $this->hook_suffixes[ $hook_suffix ];

        $callback = $admin_page->get_handle_callback();
        if ( empty( $callback ) ) {
            return;
        }

        call_user_func( $callback, $admin_page );
    }

    /**
     * Enqueues assets for an admin page in WordPress.
     *
     * @since 1.0.0
     * @internal
     *
     * @param string $hook_suffix Hook suffix for the current page.
     */
    public function enqueue_in_wp( $hook_suffix ) {
        if ( ! isset( $this->hook_suffixes[ $hook_suffix ] ) ) {
            return;
        }

        $admin_page = $this->hook_suffixes[ $hook_suffix ];

        $callback = $admin_page->get_enqueue_callback();
        if ( empty( $callback ) ) {
            return;
        }

        call_user_func( $callback, $admin_page );
    }

    /**
     * Renders an admin page in WordPress.
     *
     * @since 1.0.0
     * @internal
     */
    public function render_in_wp() {
        $hook_suffix = current_action();

        if ( ! isset( $this->hook_suffixes[ $hook_suffix ] ) ) {
            return;
        }

        $admin_page = $this->hook_suffixes[ $hook_suffix ];

        $callback = $admin_page->get_render_callback();
        if ( empty( $callback ) ) {
            return;
        }

        call_user_func( $callback, $admin_page );
    }

    /**
     * Registers a new admin page in WordPress.
     *
     * @since 1.0.0
     *
     * @param WP_Site_Identity_Admin_Page $admin_page Admin page to register.
     */
    protected function register_in_wp( WP_Site_Identity_Admin_Page $admin_page ) {
        $slug = $this->prefix( $admin_page->get_slug() );

        $callback = 'add_submenu_page';
        $args = array(
            null,
            $admin_page->get_title(),
            $admin_page->get_title(),
            $admin_page->get_capability(),
            $slug,
            array( $this, 'render_in_wp' ),
        );

        if ( is_a( $admin_page, 'WP_Site_Identity_Admin_Submenu_Page' ) ) {
            $args[0] = $admin_page->get_parent_slug();
            $args[2] = $admin_page->get_menu_title();
        } elseif ( is_a( $admin_page, 'WP_Site_Identity_Admin_Menu_Page' ) ) {
            $callback = 'add_menu_page';
            $args[2] = $admin_page->get_menu_title();

            array_shift( $args );

            $args[] = $admin_page->get_icon_url();
            $args[] = $admin_page->get_position();
        }

        $hook_suffix = call_user_func_array( $callback, $args );

        add_action( "load-{$hook_suffix}", array( $this, 'handle_in_wp' ) );

        $this->hook_suffixes[ $hook_suffix ] = $admin_page;
    }

    /**
     * Unregisters an existing admin page in WordPress.
     *
     * @since 1.0.0
     *
     * @param WP_Site_Identity_Admin_Page $admin_page Admin page to unregister.
     */
    protected function unregister_in_wp( WP_Site_Identity_Admin_Page $admin_page ) {
        $slug = $this->prefix( $admin_page->get_slug() );

        $hook_suffix = array_search( $admin_page, $this->hook_suffixes, true );
        if ( false !== $hook_suffix ) {
            remove_action( "load-{$hook_suffix}", array( $this, 'handle_in_wp' ) );
            remove_action( "{$hook_suffix}", array( $this, 'render_in_wp' ) );

            unset( $this->hook_suffixes[ $hook_suffix ] );
        }

        $callback = 'remove_submenu_page';
        $args = array(
            null,
            $slug,
        );

        if ( is_a( $admin_page, 'WP_Site_Identity_Admin_Submenu_Page' ) ) {
            $args[0] = $admin_page->get_parent_slug();
        } elseif ( is_a( $admin_page, 'WP_Site_Identity_Admin_Menu_Page' ) ) {
            $callback = 'add_menu_page';

            array_shift( $args );
        }

        call_user_func_array( $callback, $args );
    }
}