felixarntz/plugin-lib

View on GitHub
src/components/admin-pages.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * Admin pages manager class
 *
 * @package Leaves_And_Love\Plugin_Lib
 * @since 1.0.0
 */

namespace Leaves_And_Love\Plugin_Lib\Components;

use Leaves_And_Love\Plugin_Lib\Service;
use Leaves_And_Love\Plugin_Lib\Traits\Container_Service_Trait;
use Leaves_And_Love\Plugin_Lib\Traits\Hook_Service_Trait;
use Leaves_And_Love\Plugin_Lib\Assets;
use Leaves_And_Love\Plugin_Lib\AJAX;
use Leaves_And_Love\Plugin_Lib\Error_Handler;

if ( ! class_exists( 'Leaves_And_Love\Plugin_Lib\Components\Admin_Pages' ) ) :

    /**
     * Class for the Admin Pages API
     *
     * This class manages admin pages.
     *
     * @since 1.0.0
     */
    class Admin_Pages extends Service {
        use Container_Service_Trait, Hook_Service_Trait;

        /**
         * Added admin pages.
         *
         * @since 1.0.0
         * @var array
         */
        protected $pages = array();

        /**
         * Hook suffixes of the added admin pages.
         *
         * @since 1.0.0
         * @var array
         */
        protected $hook_suffix_map = array();

        /**
         * Assets service definition.
         *
         * @since 1.0.0
         * @static
         * @var string
         */
        protected static $service_assets = Assets::class;

        /**
         * AJAX service definition.
         *
         * @since 1.0.0
         * @static
         * @var string
         */
        protected static $service_ajax = AJAX::class;

        /**
         * Constructor.
         *
         * @since 1.0.0
         *
         * @param string $prefix   The prefix for all shortcodes.
         * @param array  $services {
         *     Array of service instances.
         *
         *     @type Assets        $assets        The Assets API instance.
         *     @type AJAX          $ajax          The AJAX API instance.
         *     @type Error_Handler $error_handler The error handler instance.
         * }
         */
        public function __construct( $prefix, $services ) {
            $this->set_prefix( $prefix );
            $this->set_services( $services );

            $this->setup_hooks();
        }

        /**
         * Adds an admin page.
         *
         * This method must be called before the 'admin_menu' action.
         *
         * @since 1.0.0
         *
         * @param string            $slug                 Page slug.
         * @param string|Admin_Page $class_name           Either the name of the class to handle the
         *                                                page, or an already instantiated object of
         *                                                that class.
         * @param string|null       $parent_slug          Optional. Parent page slug. Default null.
         * @param int|null          $position             Optional. Page position index. Default null.
         * @param string            $administration_panel Optional. Either 'site', 'network' or 'user'.
         *                                                Default 'site'.
         * @param bool              $skip_menu            Optional. Whether to not add a menu or submenu
         *                                                item. Default false.
         * @return bool True on success, false on failure.
         */
        public function add( $slug, $class_name, $parent_slug = null, $position = null, $administration_panel = 'site', $skip_menu = false ) {
            if ( ! is_subclass_of( $class_name, 'Leaves_And_Love\Plugin_Lib\Components\Admin_Page' ) ) {
                return false;
            }

            if ( ! in_array( $administration_panel, array( 'site', 'network', 'user' ), true ) ) {
                return false;
            }

            if ( $this->exists( $slug, $administration_panel ) ) {
                return false;
            }

            $slug = $this->get_prefix() . $slug;

            if ( is_object( $class_name ) ) {
                $page = $class_name;
                if ( $page->slug !== $slug ) {
                    return false;
                }
            } else {
                $page = new $class_name( $slug, $this );
            }

            if ( $parent_slug && isset( $this->pages[ $administration_panel ][ $this->get_prefix() . $parent_slug ] ) ) {
                $parent_slug = $this->get_prefix() . $parent_slug;
            }

            $page->administration_panel = $administration_panel;
            $page->parent_slug          = $parent_slug;
            $page->position             = $position;
            $page->skip_menu            = $skip_menu;

            if ( ! isset( $this->pages[ $administration_panel ] ) ) {
                $this->pages[ $administration_panel ] = array();
            }

            if ( ! isset( $this->hook_suffix_map[ $administration_panel ] ) ) {
                $this->hook_suffix_map[ $administration_panel ] = array();
            }

            $this->pages[ $administration_panel ][ $slug ] = $page;

            return true;
        }

        /**
         * Gets a specific admin page.
         *
         * @since 1.0.0
         *
         * @param string $slug                 Page slug.
         * @param string $administration_panel Optional. Either 'site', 'network' or 'user'.
         *                                     Default 'site'.
         * @return Admin_Page Admin page instance, or null if it does not exist.
         */
        public function get( $slug, $administration_panel = 'site' ) {
            if ( ! $this->exists( $slug, $administration_panel ) ) {
                return null;
            }

            $slug = $this->get_prefix() . $slug;

            return $this->pages[ $administration_panel ][ $slug ];
        }

        /**
         * Checks whether a specific admin page exists.
         *
         * @since 1.0.0
         *
         * @param string $slug                 Page slug.
         * @param string $administration_panel Optional. Either 'site', 'network' or 'user'.
         *                                     Default 'site'.
         * @return bool True if the admin page exists, false otherwise.
         */
        public function exists( $slug, $administration_panel = 'site' ) {
            $slug = $this->get_prefix() . $slug;

            return isset( $this->pages[ $administration_panel ][ $slug ] );
        }

        /**
         * Removes an admin page.
         *
         * This method must be called before the 'admin_menu' action.
         *
         * @since 1.0.0
         *
         * @param string $slug                 Page slug.
         * @param string $administration_panel Optional. Either 'site', 'network' or 'user'.
         *                                     Default 'site'.
         * @return bool True on success, false on failure.
         */
        public function remove( $slug, $administration_panel = 'site' ) {
            if ( ! $this->exists( $slug, $administration_panel ) ) {
                return false;
            }

            $slug = $this->get_prefix() . $slug;

            unset( $this->pages[ $administration_panel ][ $slug ] );

            return true;
        }

        /**
         * Adds all the available admin pages to the WordPress menu.
         *
         * @since 1.0.0
         */
        protected function add_pages() {
            $administration_panel = 'site';
            if ( is_network_admin() ) {
                $administration_panel = 'network';
            } elseif ( is_user_admin() ) {
                $administration_panel = 'user';
            }

            if ( ! isset( $this->pages[ $administration_panel ] ) ) {
                return;
            }

            foreach ( $this->pages[ $administration_panel ] as $slug => $page ) {
                $callback = 'add_menu_page';
                $args     = array(
                    $page->title,
                    $page->menu_title,
                    $page->capability,
                    $slug,
                    array( $page, 'render' ),
                );

                if ( $page->parent_slug ) {
                    $callback = 'add_submenu_page';
                    array_unshift( $args, $page->parent_slug );
                } elseif ( $page->skip_menu ) {
                    $callback = 'add_submenu_page';
                    array_unshift( $args, null );
                } else {
                    $args[] = $page->icon_url;
                    $args[] = $page->position;
                }

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

                add_action( 'load-' . $hook_suffix, array( $page, 'handle_request' ), 10, 0 );

                $this->hook_suffix_map[ $administration_panel ][ $hook_suffix ] = $slug;
                $page->hook_suffix = $hook_suffix;
            }
        }

        /**
         * Registers all available settings pages content.
         *
         * @since 1.0.0
         */
        protected function register_settings() {
            $administration_panel = 'site';
            if ( is_network_admin() ) {
                $administration_panel = 'network';
            } elseif ( is_user_admin() ) {
                $administration_panel = 'user';
            }

            if ( ! isset( $this->pages[ $administration_panel ] ) ) {
                return;
            }

            foreach ( $this->pages[ $administration_panel ] as $slug => $page ) {
                if ( ! is_a( $page, Settings_Page::class ) ) {
                    continue;
                }

                $page->register();
            }
        }

        /**
         * Enqueues assets for the current admin page.
         *
         * @since 1.0.0
         *
         * @param string $hook_suffix Hook suffix of the current admin page.
         */
        protected function enqueue_assets( $hook_suffix ) {
            $administration_panel = 'site';
            if ( is_network_admin() ) {
                $administration_panel = 'network';
            } elseif ( is_user_admin() ) {
                $administration_panel = 'user';
            }

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

            $slug = $this->hook_suffix_map[ $administration_panel ][ $hook_suffix ];

            $this->pages[ $administration_panel ][ $slug ]->enqueue_assets();
        }

        /**
         * Sets up all action and filter hooks for the service.
         *
         * This method must be implemented and then be called from the constructor.
         *
         * @since 1.0.0
         */
        protected function setup_hooks() {
            $this->actions = array(
                array(
                    'name'     => 'admin_menu',
                    'callback' => array( $this, 'add_pages' ),
                    'priority' => 10,
                    'num_args' => 0,
                ),
                array(
                    'name'     => 'network_admin_menu',
                    'callback' => array( $this, 'add_pages' ),
                    'priority' => 10,
                    'num_args' => 0,
                ),
                array(
                    'name'     => 'user_admin_menu',
                    'callback' => array( $this, 'add_pages' ),
                    'priority' => 10,
                    'num_args' => 0,
                ),
                array(
                    'name'     => 'admin_init',
                    'callback' => array( $this, 'register_settings' ),
                    'priority' => 10,
                    'num_args' => 0,
                ),
                array(
                    'name'     => 'admin_enqueue_scripts',
                    'callback' => array( $this, 'enqueue_assets' ),
                    'priority' => 10,
                    'num_args' => 1,
                ),
            );
        }
    }

endif;