> */ public function get_hooks(): array { return array( array( 'add_meta_boxes', array( $this, 'register' ) ), array( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ), 20, 1 ), ); } /** * Registers the metabox on all post types that support the editor. * * In the block editor (Gutenberg), the PluginSidebar registered by * `gutenberg-sidebar.js` provides the full experience. The classic * metabox is only shown when the block editor is not active for the * current post type (e.g. Classic Editor plugin installed, or a post * type that has `show_in_rest => false`). * * @since 1.0.0 * @hook add_meta_boxes * * @return void */ public function register(): void { if ( ! current_user_can( CapabilityMap::for( 'manage_links' ) ) ) { return; } $post_types = get_post_types( array( 'show_ui' => true ) ); foreach ( $post_types as $post_type ) { if ( ! post_type_supports( $post_type, 'editor' ) ) { continue; } // Skip post types that use the block editor — the Gutenberg // sidebar handles those. The metabox is only for Classic Editor. if ( $this->uses_block_editor( $post_type ) ) { continue; } add_meta_box( 'postlinkly-suggestions', __( 'Postlinkly', 'postlinkly' ), array( $this, 'render' ), $post_type, 'normal', 'default' ); } } /** * Returns whether a post type uses the block editor. * * @since 1.0.0 * * @param string $post_type Post type slug. * * @return bool */ private function uses_block_editor( string $post_type ): bool { // Classic Editor plugin sets this filter to return false. if ( function_exists( 'use_block_editor_for_post_type' ) ) { return (bool) use_block_editor_for_post_type( $post_type ); } // Gutenberg is available when the REST API supports the post type. $post_type_obj = get_post_type_object( $post_type ); return null !== $post_type_obj && ! empty( $post_type_obj->show_in_rest ); } /** * Enqueues the metabox JS and CSS on post-edit screens. * * On block-editor screens, enqueues the Gutenberg sidebar plugin. * On classic-editor screens, enqueues the overlay metabox JS. * * @since 1.0.0 * @hook admin_enqueue_scripts * * @param string $hook_suffix Current admin page hook suffix. * * @return void */ public function enqueue_assets( string $hook_suffix ): void { if ( ! in_array( $hook_suffix, array( 'post.php', 'post-new.php' ), true ) ) { return; } $post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read-only post ID for asset localisation. // Determine the post type so we know which editor is active. $post_type = 'post'; if ( $post_id > 0 ) { $queried_post = get_post( $post_id ); if ( null !== $queried_post ) { $post_type = (string) $queried_post->post_type; } } elseif ( isset( $_GET['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $post_type = sanitize_key( (string) $_GET['post_type'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } wp_enqueue_style( AssetRegistrar::HANDLE_BASE_CSS ); wp_enqueue_style( AssetRegistrar::HANDLE_MODAL_CSS ); wp_enqueue_script( AssetRegistrar::HANDLE_ADMIN_JS ); // Shared localisation data needed by both the metabox and the sidebar. $localize_data = array( 'postId' => $post_id, // Stamped into the suggestion CSV. A support report that does not // say which build produced it cannot be matched against a fix. 'version' => defined( 'POSTLINKLY_VERSION' ) ? (string) POSTLINKLY_VERSION : '', 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'postlinkly_get_suggestions' ), 'insertNonce' => wp_create_nonce( 'postlinkly_insert_link' ), 'logoUrl' => POSTLINKLY_PLUGIN_URL . 'assets/images/logo.svg', 'toolsUrl' => AdminUrls::tools(), 'i18n' => array( 'findSuggestions' => __( 'Find Link Suggestions', 'postlinkly' ), 'loading' => __( 'Finding suggestions…', 'postlinkly' ), 'noSuggestions' => __( 'No suggestions found for this post.', 'postlinkly' ), 'insert' => __( 'Insert Link', 'postlinkly' ), 'inserting' => __( 'Inserting…', 'postlinkly' ), 'inserted' => __( 'Inserted', 'postlinkly' ), /* translators: %d: number of links to insert */ 'insertSelected' => __( 'Insert %d Link(s)', 'postlinkly' ), 'selectAll' => __( 'Select All', 'postlinkly' ), /* translators: %d: number of suggestions found */ 'found' => __( '%d found', 'postlinkly' ), /* translators: 1: number of selected suggestions, 2: total suggestions */ 'selectedOf' => __( '%1$d of %2$d selected', 'postlinkly' ), 'panelTitle' => __( 'Link Suggestions', 'postlinkly' ), 'panelSubtitle' => __( 'Review and insert internal links into your post', 'postlinkly' ), 'linkingTo' => __( 'Linking to', 'postlinkly' ), 'linkThisPhrase' => __( 'Link this phrase', 'postlinkly' ), 'cancel' => __( 'Cancel', 'postlinkly' ), 'inbound' => __( 'Inbound', 'postlinkly' ), 'outbound' => __( 'Outbound', 'postlinkly' ), 'external' => __( 'External', 'postlinkly' ), 'statsError' => __( 'Run a scan to see link stats.', 'postlinkly' ), 'insertError' => __( 'Could not insert link. The anchor text may not be found in the post content.', 'postlinkly' ), /* translators: %d: number of suggestions available */ 'suggestionsAvailable' => __( '%d suggestions available', 'postlinkly' ), ), ); if ( $this->uses_block_editor( $post_type ) ) { // Block editor: enqueue the Gutenberg sidebar plugin. wp_enqueue_script( AssetRegistrar::HANDLE_GUTENBERG_JS ); wp_localize_script( AssetRegistrar::HANDLE_GUTENBERG_JS, 'postlinklyMetabox', $localize_data ); } else { // Classic editor: enqueue the overlay metabox JS. wp_localize_script( AssetRegistrar::HANDLE_ADMIN_JS, 'postlinklyAdmin', array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'postlinkly_admin' ), 'i18n' => array( 'loading' => __( 'Loading…', 'postlinkly' ), 'error' => __( 'An error occurred. Please try again.', 'postlinkly' ), 'saved' => __( 'Saved.', 'postlinkly' ), 'confirm' => __( 'Are you sure?', 'postlinkly' ), ), ) ); wp_enqueue_script( AssetRegistrar::HANDLE_METABOX_JS ); wp_localize_script( AssetRegistrar::HANDLE_METABOX_JS, 'postlinklyMetabox', $localize_data ); } } /** * Renders the metabox shell and the overlay panel container. * * The metabox shell shows stats + find button. * The overlay panel is hidden until the find button is clicked. * * @since 1.0.0 * * @param \WP_Post $post The post being edited. * * @return void */ public function render( \WP_Post $post ): void { $post_id = (int) $post->ID; ?>
—
—
—