=' ) ) { return; } $fifty_three_minute_tools_core_booted = self::VERSION; add_action( 'admin_post_fifty_three_minute_tools_activate_plugin', array( self::class, 'handle_activate_plugin' ) ); if ( did_action( 'admin_menu' ) ) { self::register_parent_menu(); self::register_plugin_submenus(); self::ensure_overview_submenu(); return; } add_action( 'admin_menu', array( self::class, 'register_parent_menu' ), 9 ); add_action( 'admin_menu', array( self::class, 'register_plugin_submenus' ), 11 ); add_action( 'admin_menu', array( self::class, 'ensure_overview_submenu' ), 12 ); } /** * Add or update the top-level 53mp Tools menu. */ public static function register_parent_menu() { remove_action( 'admin_menu', 'fifty_three_minute_tools_add_parent_menu', 9 ); remove_action( 'admin_menu', 'fifty_three_minute_tools_register_overview_submenu', 10 ); global $menu; $slug = self::PARENT_SLUG; $found = false; foreach ( (array) $menu as $index => $item ) { if ( isset( $item[2] ) && $slug === $item[2] ) { $menu[ $index ][0] = __( '53mp Tools', '53mp-fast-bulk-page-creator' ); $menu[ $index ][1] = self::CAPABILITY; $menu[ $index ][3] = self::overview_title(); $found = true; break; } } if ( $found ) { return; } add_menu_page( self::overview_title(), __( '53mp Tools', '53mp-fast-bulk-page-creator' ), self::CAPABILITY, $slug, array( self::class, 'render_all_plugins' ), 'dashicons-clock', 58 ); } /** * Create one submenu for each plugin in the shared registry. */ public static function register_plugin_submenus() { $plugins = apply_filters( 'fifty_three_minute_tools_plugins', array() ); if ( ! is_array( $plugins ) ) { return; } $plugins = self::sort_registered_plugins( $plugins ); $parent = self::PARENT_SLUG; foreach ( $plugins as $plugin ) { if ( ! is_array( $plugin ) ) { continue; } $slug = isset( $plugin['menu_slug'] ) ? (string) $plugin['menu_slug'] : ''; if ( '' === $slug || self::PARENT_SLUG === $slug ) { continue; } if ( empty( $plugin['menu_title'] ) || empty( $plugin['callback'] ) || ! is_callable( $plugin['callback'] ) ) { continue; } if ( self::submenu_slug_exists( $parent, $slug ) ) { continue; } $capability = isset( $plugin['capability'] ) ? (string) $plugin['capability'] : ''; if ( '' === $capability ) { continue; } $page_title = isset( $plugin['page_title'] ) && '' !== (string) $plugin['page_title'] ? (string) $plugin['page_title'] : (string) $plugin['menu_title']; add_submenu_page( $parent, $page_title, (string) $plugin['menu_title'], $capability, $slug, $plugin['callback'] ); } } /** * Keep All Plugins as the first submenu and point it at the header table. */ public static function ensure_overview_submenu() { $slug = self::PARENT_SLUG; $hook = 'toplevel_page_' . $slug; remove_submenu_page( $slug, $slug ); remove_all_actions( $hook ); add_submenu_page( $slug, self::overview_title(), self::overview_title(), self::CAPABILITY, $slug, array( self::class, 'render_all_plugins' ) ); self::move_submenu_first( $slug ); } /** * All Plugins page. Rows come from the WordPress.org plugin directory for DIRECTORY_AUTHOR. */ public static function render_all_plugins() { if ( ! current_user_can( self::CAPABILITY ) ) { wp_die( esc_html__( 'You do not have permission to access this page.', '53mp-fast-bulk-page-creator' ) ); } if ( ! function_exists( 'get_plugins' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } $plugins = self::directory_plugins(); $registered = self::registry_by_plugin_file(); $can_install = current_user_can( 'install_plugins' ); $can_activate = current_user_can( 'activate_plugins' ); ?>

get_error_message() ); ?>

get_error_message() ) ); } wp_safe_redirect( add_query_arg( '53mp-activated', '1', admin_url( 'admin.php?page=' . self::PARENT_SLUG ) ) ); exit; } /** * Published plugins for DIRECTORY_AUTHOR, from the WordPress.org plugin info API. * * @return array|\WP_Error */ private static function directory_plugins() { $cache_key = '53mp_tools_dir_plugins_' . self::DIRECTORY_AUTHOR; $cached = get_transient( $cache_key ); if ( is_array( $cached ) ) { return $cached; } if ( ! function_exists( 'plugins_api' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; } $rows = array(); $page = 1; $pages = 1; do { $api = plugins_api( 'query_plugins', array( 'author' => self::DIRECTORY_AUTHOR, 'per_page' => 100, 'page' => $page, 'fields' => array( 'short_description' => true, 'description' => false, 'sections' => false, 'versions' => false, 'downloaded' => false, ), ) ); if ( is_wp_error( $api ) ) { return $api; } $batch = ( is_object( $api ) && isset( $api->plugins ) && is_array( $api->plugins ) ) ? $api->plugins : array(); foreach ( $batch as $plugin ) { $slug = (string) self::plugin_field( $plugin, 'slug' ); if ( '' === $slug ) { continue; } $description = (string) self::plugin_field( $plugin, 'short_description' ); if ( '' === $description ) { $description = wp_strip_all_tags( (string) self::plugin_field( $plugin, 'description' ) ); } $rows[] = array( 'slug' => $slug, 'name' => self::normalize_plugin_name( (string) self::plugin_field( $plugin, 'name' ) ), 'description' => html_entity_decode( wp_strip_all_tags( $description ), ENT_QUOTES, 'UTF-8' ), 'version' => (string) self::plugin_field( $plugin, 'version' ), ); } if ( is_object( $api ) && isset( $api->info->pages ) ) { $pages = max( 1, (int) $api->info->pages ); } ++$page; } while ( $page <= $pages && $page <= 10 ); usort( $rows, static function ( $a, $b ) { return strcasecmp( $a['name'], $b['name'] ); } ); if ( ! empty( $rows ) ) { set_transient( $cache_key, $rows, 12 * HOUR_IN_SECONDS ); } return $rows; } /** * @param object|array $plugin Plugin API record. * @param string $key Field name. * @return mixed */ private static function plugin_field( $plugin, $key ) { if ( is_object( $plugin ) && isset( $plugin->{$key} ) ) { return $plugin->{$key}; } if ( is_array( $plugin ) && isset( $plugin[ $key ] ) ) { return $plugin[ $key ]; } return ''; } /** * Match a directory plugin to an installed plugin file. * * @param string $slug Directory slug. * @param string $name Directory plugin name. * @return string Plugin basename, or empty when it is not installed. */ private static function installed_plugin_file( $slug, $name ) { static $by_slug = null; static $by_name = null; if ( null === $by_slug ) { $by_slug = array(); $by_name = array(); foreach ( get_plugins() as $file => $data ) { $dir = dirname( $file ); $directory_slug = ( '.' === $dir ) ? basename( $file, '.php' ) : $dir; $by_slug[ $directory_slug ] = $file; $plugin_name = isset( $data['Name'] ) ? self::normalize_plugin_name( (string) $data['Name'] ) : ''; if ( '' !== $plugin_name ) { $by_name[ strtolower( $plugin_name ) ] = $file; } } } if ( isset( $by_slug[ $slug ] ) ) { return $by_slug[ $slug ]; } $key = strtolower( self::normalize_plugin_name( $name ) ); return isset( $by_name[ $key ] ) ? $by_name[ $key ] : ''; } /** * Decode directory names so they compare with local plugin headers. * * @param string $name Plugin name. * @return string */ private static function normalize_plugin_name( $name ) { $name = html_entity_decode( wp_strip_all_tags( $name ), ENT_QUOTES, 'UTF-8' ); $name = str_replace( array( '–', '—' ), '-', $name ); return trim( preg_replace( '/\s+/', ' ', $name ) ); } /** * @param string $slug Plugin directory slug. * @return string */ private static function install_url( $slug ) { return wp_nonce_url( self_admin_url( 'update.php?action=install-plugin&plugin=' . rawurlencode( $slug ) ), 'install-plugin_' . $slug ); } /** * @param string $plugin_file Plugin basename. * @return string */ private static function activate_url( $plugin_file ) { $url = add_query_arg( array( 'action' => 'fifty_three_minute_tools_activate_plugin', 'plugin' => $plugin_file, ), admin_url( 'admin-post.php' ) ); return wp_nonce_url( $url, 'fifty_three_minute_tools_activate_' . $plugin_file ); } /** * Settings screen for an installed, active suite plugin. * * @param string $plugin_file Plugin basename. * @param array> $registered Registry keyed by plugin file. * @return string */ private static function settings_url( $plugin_file, $registered ) { if ( ! isset( $registered[ $plugin_file ] ) || ! is_array( $registered[ $plugin_file ] ) ) { return ''; } $registration = $registered[ $plugin_file ]; $menu_slug = isset( $registration['menu_slug'] ) ? (string) $registration['menu_slug'] : ''; $capability = isset( $registration['capability'] ) ? (string) $registration['capability'] : ''; if ( '' === $menu_slug || '' === $capability || ! current_user_can( $capability ) ) { return ''; } return admin_url( 'admin.php?page=' . $menu_slug ); } /** * Loader version bundled with one installed plugin. * * @param string $plugin_file Plugin basename from get_plugins(). * @return string Empty when this plugin does not ship the loader. */ private static function bundled_loader_version( $plugin_file ) { if ( ! defined( 'WP_PLUGIN_DIR' ) ) { return ''; } $includes_dir = dirname( WP_PLUGIN_DIR . '/' . $plugin_file ) . '/includes'; if ( function_exists( 'fifty_three_minute_tools_read_bundle_version' ) ) { $version = fifty_three_minute_tools_read_bundle_version( $includes_dir ); return ( is_string( $version ) && '0.0.0' !== $version ) ? $version : ''; } $version_file = $includes_dir . '/fifty-three-minute-tools-version.php'; if ( ! is_readable( $version_file ) ) { return ''; } $version = include $version_file; return is_string( $version ) ? $version : ''; } /** * Registry entries keyed by plugin basename. * * @return array> */ private static function registry_by_plugin_file() { $registered = apply_filters( 'fifty_three_minute_tools_plugins', array() ); $by_file = array(); if ( ! is_array( $registered ) ) { return $by_file; } foreach ( $registered as $entry ) { if ( ! is_array( $entry ) || empty( $entry['plugin_file'] ) ) { continue; } $by_file[ (string) $entry['plugin_file'] ] = $entry; } return $by_file; } /** * Sort by position, then menu title. Missing positions sort after numbered ones. * * @param array> $plugins Registered plugins. * @return array> */ private static function sort_registered_plugins( $plugins ) { uasort( $plugins, static function ( $a, $b ) { $pos_a = ( is_array( $a ) && isset( $a['position'] ) && null !== $a['position'] && '' !== $a['position'] ) ? (int) $a['position'] : 1000; $pos_b = ( is_array( $b ) && isset( $b['position'] ) && null !== $b['position'] && '' !== $b['position'] ) ? (int) $b['position'] : 1000; if ( $pos_a !== $pos_b ) { return ( $pos_a < $pos_b ) ? -1 : 1; } $title_a = ( is_array( $a ) && isset( $a['menu_title'] ) ) ? (string) $a['menu_title'] : ''; $title_b = ( is_array( $b ) && isset( $b['menu_title'] ) ) ? (string) $b['menu_title'] : ''; return strcasecmp( $title_a, $title_b ); } ); return $plugins; } /** * @param string $parent Parent menu slug. * @param string $slug Submenu slug. * @return bool */ private static function submenu_slug_exists( $parent, $slug ) { global $submenu; if ( empty( $submenu[ $parent ] ) || ! is_array( $submenu[ $parent ] ) ) { return false; } foreach ( $submenu[ $parent ] as $item ) { if ( isset( $item[2] ) && $slug === $item[2] ) { return true; } } return false; } /** * @param string $slug Parent menu slug. */ private static function move_submenu_first( $slug ) { global $submenu; if ( empty( $submenu[ $slug ] ) || ! is_array( $submenu[ $slug ] ) ) { return; } $overview = null; $rest = array(); foreach ( $submenu[ $slug ] as $item ) { if ( null === $overview && isset( $item[2] ) && $slug === $item[2] ) { $overview = $item; continue; } $rest[] = $item; } if ( null === $overview ) { return; } $submenu[ $slug ] = array_merge( array( $overview ), $rest ); } } } } namespace { defined( 'ABSPATH' ) || exit; if ( ! function_exists( 'fifty_three_minute_tools_menu_slug' ) ) { /** * Admin menu slug for the 53mp Tools parent. * * @return string */ function fifty_three_minute_tools_menu_slug() { return \FiftyThreeMP\Tools\Core\v1_4_0\Core::parent_slug(); } } if ( ! function_exists( 'fifty_three_minute_tools_register_parent_menu' ) ) { /** * Register the top-level 53mp Tools admin menu once. * * @return string Parent menu slug. */ function fifty_three_minute_tools_register_parent_menu() { \FiftyThreeMP\Tools\Core\v1_4_0\Core::boot(); return \FiftyThreeMP\Tools\Core\v1_4_0\Core::parent_slug(); } } \FiftyThreeMP\Tools\Core\v1_4_0\Core::boot(); }