3task Toolbar. * * Saving goes through options.php and the registered sanitize callback; this class only renders. * * @package ThreeCE */ if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Admin screens. */ class ThreeCE_Admin { const PAGE = 'threece'; /** * Hooks. */ public static function init(): void { add_filter( 'plugin_action_links_' . plugin_basename( THREECE_FILE ), array( __CLASS__, 'action_links' ) ); add_action( 'admin_menu', array( __CLASS__, 'menu' ) ); add_filter( 'post_row_actions', array( __CLASS__, 'row_actions' ), 15, 2 ); add_filter( 'page_row_actions', array( __CLASS__, 'row_actions' ), 15, 2 ); add_filter( 'display_post_states', array( __CLASS__, 'post_state' ), 10, 2 ); add_action( 'admin_notices', array( __CLASS__, 'notice_classic_editor' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'assets' ) ); } /** * Styles, live preview and toolbar builder, on our settings page only. * * @param string $hook_suffix Admin page. */ public static function assets( $hook_suffix ): void { if ( 'settings_page_' . self::PAGE !== $hook_suffix || ! current_user_can( 'manage_options' ) ) { return; } wp_enqueue_style( 'threece-inserter', THREECE_URL . 'assets/css/inserter.css', array(), THREECE_VERSION ); wp_enqueue_style( 'threece-admin', THREECE_URL . 'assets/css/admin.css', array( 'threece-inserter' ), THREECE_VERSION ); // The Design tab shows real elements in the chosen style. wp_enqueue_style( 'threece-elements' ); // wp-api-fetch sends the choice on the thank-you card with the REST nonce of WordPress. wp_enqueue_script( 'threece-settings', THREECE_URL . 'assets/js/settings.js', array( 'wp-api-fetch' ), THREECE_VERSION, true ); // The toolbar preview draws the buttons with the icons of the editor itself: WordPress' editor styles and TinyMCE skin. wp_enqueue_style( 'editor-buttons' ); wp_enqueue_style( 'threece-mce-skin', includes_url( 'js/tinymce/skins/lightgray/skin.min.css' ), array(), isset( $GLOBALS['tinymce_version'] ) ? (string) $GLOBALS['tinymce_version'] : THREECE_VERSION ); wp_enqueue_script( 'threece-toolbar-admin', THREECE_URL . 'assets/js/toolbar-admin.js', array(), THREECE_VERSION, true ); wp_add_inline_script( 'threece-toolbar-admin', 'window.threeceToolbarData = ' . wp_json_encode( array( 'i18n' => array( /* translators: %s: row number */ 'row' => __( 'Row %s', '3task-toolbar-for-classic-editor' ), 'addTo' => __( 'Add to', '3task-toolbar-for-classic-editor' ), 'added' => __( 'Add to the toolbar', '3task-toolbar-for-classic-editor' ), 'inToolbar' => __( 'in toolbar', '3task-toolbar-for-classic-editor' ), 'separator' => __( 'Separator', '3task-toolbar-for-classic-editor' ), 'drop' => __( 'Drag a button here or add one below.', '3task-toolbar-for-classic-editor' ), 'groupText' => __( 'Text', '3task-toolbar-for-classic-editor' ), 'groupParagraph' => __( 'Paragraph', '3task-toolbar-for-classic-editor' ), 'groupInsert' => __( 'Insert', '3task-toolbar-for-classic-editor' ), 'groupTools' => __( 'Tools', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'actions' => __( 'Actions for %s', '3task-toolbar-for-classic-editor' ), 'left' => __( 'Left', '3task-toolbar-for-classic-editor' ), 'right' => __( 'Right', '3task-toolbar-for-classic-editor' ), 'removeShort' => __( 'Remove', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'moveLeft' => __( 'Move %s left', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'moveRight' => __( 'Move %s right', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'moveUp' => __( 'Move %s to the row above', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'moveDown' => __( 'Move %s to the row below', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'remove' => __( 'Remove %s', '3task-toolbar-for-classic-editor' ), /* translators: 1: button name, 2: row number, 3: position in the row, 4: buttons in the row */ 'moved' => __( '%1$s: row %2$s, position %3$s of %4$s.', '3task-toolbar-for-classic-editor' ), /* translators: %s: button name */ 'removed' => __( '%s removed.', '3task-toolbar-for-classic-editor' ), /* translators: %s: row number */ 'full' => __( 'Row %s is full.', '3task-toolbar-for-classic-editor' ), ), ) ) . ';', 'before' ); } /** * "Edit (classic editor)" and "Edit (block editor)" in the post list while users may choose. * * @param array $actions Row actions. * @param WP_Post $post Post. * @return array */ public static function row_actions( $actions, $post ) { if ( ! self::offers_both( $post ) || ! current_user_can( 'edit_post', $post->ID ) ) { return $actions; } $edit = get_edit_post_link( $post->ID, 'raw' ); if ( ! $edit ) { return $actions; } $title = _draft_or_post_title( $post ); $links = array( 'threece_classic' => array( 'classic', __( 'Edit (classic editor)', '3task-toolbar-for-classic-editor' ), /* translators: %s: post title */ __( 'Edit “%s” in the classic editor', '3task-toolbar-for-classic-editor' ), ), 'threece_block' => array( 'block', __( 'Edit (block editor)', '3task-toolbar-for-classic-editor' ), /* translators: %s: post title */ __( 'Edit “%s” in the block editor', '3task-toolbar-for-classic-editor' ), ), ); foreach ( $links as $key => $link ) { $actions[ $key ] = sprintf( '%3$s', esc_url( wp_nonce_url( add_query_arg( 'threece-editor', $link[0], $edit ), ThreeCE_Editor_Switch::link_action( $post->ID ), ThreeCE_Editor_Switch::LINK_NONCE ) ), esc_attr( sprintf( $link[2], $title ) ), esc_html( $link[1] ) ); } return $actions; } /** * Shows next to the title which editor a post was last edited in. * * @param array $states Post states. * @param WP_Post $post Post. * @return array */ public static function post_state( $states, $post ) { if ( ! self::offers_both( $post ) ) { return $states; } $editor = ThreeCE_Editor_Switch::post_editor( $post->ID ); if ( 'block' === $editor ) { $states['threece_editor'] = __( 'Block editor', '3task-toolbar-for-classic-editor' ); } elseif ( 'classic' === $editor ) { $states['threece_editor'] = __( 'Classic editor', '3task-toolbar-for-classic-editor' ); } return $states; } /** * Users may choose and the post type can use the block editor at all. * * @param mixed $post Post from a filter, checked here. */ private static function offers_both( $post ): bool { return $post instanceof WP_Post && ThreeCE_Editor_Switch::settings()['allow_users'] && use_block_editor_for_post_type( $post->post_type ); } /** * Both plugins decide the same thing, so the old one can go. Dashboard, plugins and our page only. */ public static function notice_classic_editor(): void { global $pagenow; if ( ! in_array( $pagenow, array( 'index.php', 'plugins.php', 'options-general.php' ), true ) || ! current_user_can( 'activate_plugins' ) ) { return; } if ( ! function_exists( 'is_plugin_active' ) ) { require_once ABSPATH . 'wp-admin/includes/plugin.php'; } if ( ! is_plugin_active( 'classic-editor/classic-editor.php' ) ) { return; } printf( '

%1$s %3$s

', esc_html__( '3task Toolbar has taken over the settings of the plugin "Classic Editor". Both decide which editor opens, so please deactivate "Classic Editor".', '3task-toolbar-for-classic-editor' ), esc_url( admin_url( 'plugins.php' ) ), esc_html__( 'Go to plugins', '3task-toolbar-for-classic-editor' ) ); } /** * Registers the settings page for users who may manage options. */ public static function menu(): void { add_options_page( __( '3task Toolbar', '3task-toolbar-for-classic-editor' ), __( '3task Toolbar', '3task-toolbar-for-classic-editor' ), 'manage_options', self::PAGE, array( __CLASS__, 'render' ) ); } /** * Links in the head of the page. */ const GUIDE_URL = 'https://wordpress.org/plugins/3task-toolbar-for-classic-editor/#faq'; const FORUM_URL = 'https://wordpress.org/support/plugin/3task-toolbar-for-classic-editor/'; /** * The Pro add-on (toolbar per role, text blocks, pricing tables and more). Linked in the head of the settings page * and in the plugins list, both dropped as soon as the add-on is active. */ const PRO_URL = 'https://www.3task.de/3task-toolbar-pro/'; /** * Whether the Pro add-on runs on this site. */ private static function pro_active(): bool { return class_exists( 'ThreeCE_Pro' ); } /** * Links on the plugins list: settings first, then the Pro add-on while it is not installed. * * @param mixed $links Links from WordPress. * @return mixed */ public static function action_links( $links ) { if ( ! is_array( $links ) ) { return $links; } $own = array( 'settings' => '' . esc_html__( 'Settings', '3task-toolbar-for-classic-editor' ) . '', ); if ( ! self::pro_active() ) { $own['pro'] = '' . esc_html__( 'Pro', '3task-toolbar-for-classic-editor' ) . ''; } return $own + $links; } /** * Tabler icons (MIT), inner SVG only; see credits.txt. */ const ICONS = array( 'writing' => ' ', 'tool' => '', 'pencil' => ' ', 'palette' => ' ', 'shield-lock' => ' ', 'check' => '', 'star' => '', 'users' => ' ', 'sparkles' => '', 'help' => ' ', 'book' => ' ', 'lifebuoy' => ' ', 'eye' => ' ', ); /** * One icon as inline SVG, hidden from screen readers. The markup is fixed in ICONS, wp_kses keeps it to SVG. * * @param string $name Icon name from ICONS. */ private static function icon( string $name ): void { if ( ! isset( self::ICONS[ $name ] ) ) { return; } $path = array( 'd' => true, 'stroke' => true, 'fill' => true, ); echo wp_kses( '', array( 'svg' => array( 'xmlns' => true, 'class' => true, 'width' => true, 'height' => true, 'viewbox' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true, 'stroke-linecap' => true, 'stroke-linejoin' => true, 'aria-hidden' => true, 'focusable' => true, ), 'path' => $path, ) ); } /** * Settings page: head with name, version and help links, tabs with icons, the tab as cards and a side column. */ public static function render(): void { if ( ! current_user_can( 'manage_options' ) ) { return; } $tab = isset( $_GET['tab'] ) ? sanitize_key( wp_unslash( $_GET['tab'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- only picks the tab to show. $tabs = array( 'editor' => array( 'writing', __( 'Editor', '3task-toolbar-for-classic-editor' ) ), 'toolbar' => array( 'tool', __( 'Toolbar', '3task-toolbar-for-classic-editor' ) ), 'look' => array( 'pencil', __( 'Writing', '3task-toolbar-for-classic-editor' ) ), 'design' => array( 'palette', __( 'Design', '3task-toolbar-for-classic-editor' ) ), ); /** * Tabs of add-ons, shown after our own: key => array( icon name from ICONS, label, render callback ). * The callback prints the cards of the tab; the side column stays. * * @since 1.0.2 * @param array $extra Tabs by key: array( icon, label, callback ). */ $extra = apply_filters( 'threece_settings_tabs', array() ); foreach ( (array) $extra as $key => $item ) { $key = sanitize_key( (string) $key ); if ( '' === $key || isset( $tabs[ $key ] ) || ! is_array( $item ) || ! isset( $item[1], $item[2] ) || ! is_callable( $item[2] ) ) { continue; } $tabs[ $key ] = array( isset( $item[0] ) && isset( self::ICONS[ $item[0] ] ) ? $item[0] : 'star', (string) $item[1], $item[2] ); } // Until 1.0.0 the privacy switch had its own tab; old links land where it lives now. $tab = 'privacy' === $tab ? 'look' : $tab; $tab = isset( $tabs[ $tab ] ) ? $tab : 'editor'; ?>


·

inert>

__( 'fine lines', '3task-toolbar-for-classic-editor' ), 'weich' => __( 'surfaces, round', '3task-toolbar-for-classic-editor' ), 'kontur' => __( 'strong, square', '3task-toolbar-for-classic-editor' ), ); $colors = ThreeCE_Design::accent_labels(); ?>

$label ) : ?>

/> $hex ) : ?> />

$row ) : ?>


aria-describedby="-help" />

array( __( 'Classic editor', '3task-toolbar-for-classic-editor' ), __( 'One writing area with a toolbar, like in a word processor.', '3task-toolbar-for-classic-editor' ) ), 'block' => array( __( 'Block editor', '3task-toolbar-for-classic-editor' ), __( 'Content as separate blocks, the default of WordPress.', '3task-toolbar-for-classic-editor' ) ), ); ?>

$choice ) : ?>