/
var
/
www
/
barefootlaw.org
/
wp-content
/
plugins
/
page-links-to
/
classes
/
Upload File
HOME
<?php /** * The Page Links To plugin. * * @package PageLinksTo */ defined( 'WPINC' ) or die; /** * The Page Links To class. */ class CWS_PageLinksTo { /** * The class instance. * * @var CWS_PageLinksTo */ static $instance; /** * The main plugin file path. * * @var string */ private $file; const LINK_META_KEY = '_links_to'; const TARGET_META_KEY = '_links_to_target'; const VERSION_KEY = 'txfx_plt_schema_version'; const DISMISSED_NOTICES = 'page_links_dismissed_options'; const MESSAGE_ID = 4; const NEWSLETTER_URL = 'https://pages.convertkit.com/8eb23c1339/1ce4614706'; const CSS_JS_VERSION = '3.3.4'; /** * Whether to replace WP links with their specified URLs. * * @var bool */ protected $replace = true; /** * Class constructor. Adds init hook. * * @param string $file The main plugin file path. */ function __construct( $file ) { self::$instance = $this; self::$instance->file = $file; $this->hook( 'init' ); } /** * Get the plugin instance. * * @return CWS_PageLinksTo The plugin class instance. */ public static function get_instance() { if ( ! self::$instance ) { self::$instance = new self(); } return self::$instance; } /** * Returns the main plugin file path. * * @return string The main plugin file path. */ public function get_file() { return $this->file; } /** * Add a WordPress hook (action/filter). * * @param mixed $hook first parameter is the name of the hook. If second or third parameters are included, they will be used as a priority (if an integer) or as a class method callback name (if a string). * @return true Will always return true. */ public function hook( $hook ) { $args = func_get_args(); $priority = 10; $method = self::sanitize_method( $hook ); unset( $args[0] ); foreach ( (array) $args as $arg ) { if ( is_int( $arg ) ) { $priority = $arg; } else { $method = $arg; } } return add_action( $hook, array( $this, $method ), $priority, 999 ); } /** * Sanitizes method names with bad characters. * * @param string $method The raw method name. * @return string The sanitized method name. */ private static function sanitize_method( $method ) { return str_replace( array( '.', '-' ), array( '_DOT_', '_DASH_' ), $method ); } /** * Includes a file (relative to the plugin base path) * and optionally globalizes a named array passed in. * * @param string $file The file to include. * @param array $data A named array of data to globalize. * @return void */ public function include_file( $file, $data = array() ) { extract( $data, EXTR_SKIP ); include( $this->get_path() . $file ); } /** * Bootstraps the upgrade process and registers all the hooks. * * @return void */ public function init() { // Check to see if any of our data needs to be upgraded. $this->maybe_upgrade(); // Load translation files. load_plugin_textdomain( 'page-links-to', false, basename( dirname( $this->file ) ) . '/languages' ); // Init hook. do_action( 'page_links_to_init', $this ); // Register hooks. $this->register_hooks(); } /** * Registers all the hooks. * * @return void */ function register_hooks() { // Hook in to URL generation. $this->hook( 'page_link', 'link', 20 ); $this->hook( 'post_link', 'link', 20 ); $this->hook( 'post_type_link', 'link', 20 ); $this->hook( 'attachment_link', 'link', 20 ); // Non-standard priority hooks. $this->hook( 'do_meta_boxes', 20 ); $this->hook( 'admin_bar_menu', 999 ); $this->hook( 'wp_ajax_sample-permalink', 'disable_replacements', -999 ); // Non-standard callback hooks. $this->hook( 'load-post.php', 'load_post' ); $this->hook( 'wp_ajax_plt_dismiss_notice', 'ajax_dismiss_notice' ); $this->hook( 'wp_ajax_plt_quick_add', 'ajax_quick_add' ); // Standard hooks. $this->hook( 'wp_list_pages' ); $this->hook( 'template_redirect' ); $this->hook( 'save_post' ); $this->hook( 'wp_enqueue_scripts' ); $this->hook( 'edit_attachment' ); $this->hook( 'wp_nav_menu_objects' ); $this->hook( 'plugin_row_meta' ); $this->hook( 'display_post_states' ); $this->hook( 'admin_footer' ); $this->hook( 'admin_enqueue_scripts' ); $this->hook( 'enqueue_block_editor_assets' ); $this->hook( 'admin_menu' ); $this->hook( 'rest_api_init' ); // Gutenberg. $this->hook( 'use_block_editor_for_post', 99999 ); // Page row actions. $this->hook( 'page_row_actions' ); $this->hook( 'post_row_actions', 'page_row_actions' ); $this->hook( 'init', 'register_meta_keys', 9999 ); $this->hook( 'rest_api_init', 'register_meta_keys', 9999 ); // Notices. if ( self::should_display_message() ) { $this->hook( 'admin_notices', 'notify_generic' ); } } /** * Checks if the specified post is going to use the block editor, and adds custom-fields support. * * We have to do this because PLT requires custom-fields support to update post meta in the block editor. * So if you add a custom post type without 'custom-fields' support, you'll get an error. * We check that this post is going to use the block editor, and that its post type supports the block editor, * and only then do we add 'custom-fields' support for the post type. * * @param boolean $use_block_editor Whether they are going to use the block editor for this post. * @param WP_Post $post The post they are editing. * @return boolean We return the original value of their decision. */ public function use_block_editor_for_post( $use_block_editor, $post ) { if ( $use_block_editor && self::is_supported_post_type( get_post_type( $post ) ) ) { add_post_type_support( get_post_type( $post ), 'custom-fields' ); } return $use_block_editor; } /** * Adds custom-fields support to PLT-supporting post types during REST API initialization. * * @return void */ function rest_api_init() { $post_type_names = array_keys( get_post_types() ); foreach ( $post_type_names as $type ) { if ( self::is_supported_post_type( $type ) ) { add_post_type_support( $type, 'custom-fields' ); } } } /** * Registers the PLT post meta keys for supported post types. * * @return void */ public function register_meta_keys() { $post_type_names = array_keys( get_post_types() ); foreach ( $post_type_names as $type ) { if ( self::is_supported_post_type( $type ) ) { $this->register_meta( self::LINK_META_KEY, $type ); $this->register_meta( self::TARGET_META_KEY, $type ); do_action( 'page_links_to_register_meta_for_post_type', $type ); } } } /** * Registers a post meta key for a given post type. * * @param string $key The key name. * @param string $post_type The post type. * @return boolean Whether the meta key was registered. */ public function register_meta( $key, $post_type ) { return register_meta( 'post', $key, array( 'object_subtype' => $post_type, 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'auth_callback' => array( $this, 'rest_auth' ), ) ); } /** * Determines REST API authentication. * * @param bool $allowed Whether it is allowed. * @param string $meta_key The meta key being checked. * @param int $post_id The post ID being checked. * @param int $user_id The user ID being checked. * @param string $cap The current capability. * @param array $caps All capabilities. * @return bool Whether the user can do it. */ public function rest_auth( $allowed, $meta_key, $post_id, $user_id, $cap, $caps ) { return user_can( $user_id, 'edit_post', $post_id ); } /** * Performs an upgrade for older versions * * * Version 3: Underscores the keys so they only show in the plugin's UI. * * @return void */ function maybe_upgrade() { // In earlier versions, the meta keys were stored without a leading underscore. // Since then, underscore has been codified as the standard for "something manages this" post meta. if ( ! get_option( self::VERSION_KEY ) || get_option( self::VERSION_KEY ) < 3 ) { global $wpdb; $total_affected = 0; foreach ( array( '', '_target', '_type' ) as $meta_key ) { $meta_key = 'links_to' . $meta_key; $affected = $wpdb->update( $wpdb->postmeta, array( 'meta_key' => '_' . $meta_key, ), compact( 'meta_key' ) ); if ( $affected ) { $total_affected += $affected; } } // Only flush the cache if something changed. if ( $total_affected > 0 ) { wp_cache_flush(); } } } /** * Disables replacements. * * @return void */ public function disable_replacements() { $this->replace = false; } /** * Enqueues frontend scripts. * * @return void */ public function wp_enqueue_scripts() { if ( self::supports( 'new_tab' ) ) { wp_enqueue_script( 'page-links-to', $this->get_url() . 'dist/new-tab.js', array(), self::CSS_JS_VERSION, true ); } } /** * Enqueues backend scripts. * * @return void */ public function admin_enqueue_scripts() { if ( !is_customize_preview() && current_user_can( 'edit_posts' ) ) { wp_register_script( 'plt-clipboard', $this->get_url() . 'dist/clipboard.min.js', array(), self::CSS_JS_VERSION, true ); wp_enqueue_script( 'plt-quick-add', $this->get_url() . 'dist/quick-add.js', array( 'plt-clipboard', 'jquery-ui-dialog' ), self::CSS_JS_VERSION, true ); wp_enqueue_style( 'plt-quick-add', $this->get_url() . 'dist/quick-add.css', array( 'wp-jquery-ui-dialog' ), self::CSS_JS_VERSION ); } } /** * Enqueues block editor scripts. * * @return void */ public function enqueue_block_editor_assets() { // Gutenberg. if ( self::is_block_editor() && self::is_supported_post_type() ) { wp_enqueue_script( 'plt-block-editor', $this->get_url() . 'dist/block-editor.js', array( 'wp-edit-post', 'wp-element', 'wp-plugins' ), self::CSS_JS_VERSION, true ); wp_localize_script( 'plt-block-editor', 'pltOptions', [ 'supports' => [ 'newTab' => self::supports( 'new_tab' ), ], 'panelTitle' => self::get_panel_title(), ]); do_action( 'page_links_to_enqueue_block_editor_assets' ); } } /** * Adds our items to the admin bar. * * @param WP_Admin_Bar $bar The admin bar object. * @return void */ public function admin_bar_menu( $bar ) { if ( is_admin() ) { $bar->add_node( array( 'id' => 'new-page-link', 'title' => __( 'Page Link', 'page-links-to' ), 'parent' => 'new-content', 'href' => '#new-page-link', )); } } /** * Filters the page row actions. * * @param array $actions The current array of actions. * @param WP_Post $post The current post row being processed. * @return array The updated array of actions. */ public function page_row_actions( $actions, $post ) { if ( self::get_link( $post ) ) { $new_actions = array(); $inserted = false; $original_html = '<a href="' . esc_attr( $this->original_link( $post->ID ) ) . '" class="plt-copy-short-url" data-clipboard-text="' . esc_attr( $this->original_link( $post->ID ) ) . '" data-original-text="' . __( 'Copy Short URL', 'page-links-to' ) . '">' . __( 'Copy Short URL', 'page-links-to' ) . '</a>'; $original_key = 'plt_original'; foreach ( $actions as $key => $html ) { $new_actions[ $key ] = $html; if ( 'view' === $key ) { $inserted = true; $new_actions[ $original_key ] = $original_html; } } if ( ! $inserted ) { $new_actions[ $original_key ] = $original_html; } $actions = $new_actions; } return $actions; } /** * Adds the Add Page Link menu item. * * @return void */ public function admin_menu() { add_submenu_page( 'edit.php?post_type=page', '', __( 'Add Page Link', 'page-links-pro' ), 'edit_pages', 'plt-add-page-link', '__return_empty_string' ); } /** * Adds the quick-add HTML to the admin footer. * * @return void */ public function admin_footer() { if ( current_user_can( 'edit_pages' ) ) { $this->include_file( 'templates/quick-add.php' ); } } /** * Returns a single piece of post meta. * * @param int $post_id a post ID. * @param string $key a post meta key. * @return string|false the post meta, or false, if it doesn't exist. */ public static function get_post_meta( $post_id, $key ) { $meta = get_post_meta( absint( $post_id ), $key, true ); if ( '' === $meta ) { return false; } return $meta; } /** * Returns the link for the specified post. * * @param WP_Post|int $post a post or post ID. * @return mixed either a URL or false. */ public static function get_link( $post ) { $post = get_post( $post ); $post_id = empty( $post ) ? null : $post->ID; return self::get_post_meta( $post_id, self::LINK_META_KEY ); } /** * Returns the _blank target status for the specified post. * * @param WP_Post|int $post a post or post ID. * @return bool whether it should open in a new tab. */ public static function get_target( $post ) { $post = get_post( $post ); $post_id = empty( $post ) ? null : $post->ID; return (bool) self::get_post_meta( $post_id, self::TARGET_META_KEY ); } /** * Adds the meta box to the post or page edit screen. * * @param string $page the name of the current page. * @param string $context the current context. * @return void */ public function do_meta_boxes( $page, $context ) { if ( ! self::is_block_editor() && self::is_supported_post_type( $page ) && 'advanced' === $context ) { add_meta_box( 'page-links-to', self::get_panel_title(), array( $this, 'meta_box' ), $page, 'advanced', 'low' ); } } /** * Determine whether a post type supports custom links. * * @param string $type The post type to check. * @return bool Whether this post type supports custom links. */ public static function is_supported_post_type( $type = null ) { if ( is_null( $type ) ) { $type = get_post_type(); } if ( is_object( $type ) ) { if ( isset( $type->id ) ) { $type = $type->id; } } /* Plugins that use custom post types can use this filter to hide the PLT UI in their post type. */ $hook = 'page-links-to-post-types'; $supported_post_types = (array) apply_filters( $hook, array_keys( get_post_types( array( 'show_ui' => true, ) ) ) ); return in_array( $type, $supported_post_types ); } /** * Outputs the Page Links To post screen meta box. * * @return void */ public function meta_box() { $null = null; $post = get_post( $null ); echo '<p>'; wp_nonce_field( 'cws_plt_' . $post->ID, '_cws_plt_nonce', false, true ); echo '</p>'; $url = self::get_link( $post->ID ); if ( ! $url ) { $linked = false; $url = ''; } else { $linked = true; } ?> <p><?php _e( 'Point this content to:', 'page-links-to' ); ?></p> <p><label><input type="radio" id="cws-links-to-choose-wp" name="cws_links_to_choice" value="wp" <?php checked( ! $linked ); ?> /> <?php _e( 'Its normal WordPress URL', 'page-links-to' ); ?></label></p> <p><label><input type="radio" id="cws-links-to-choose-custom" name="cws_links_to_choice" value="custom" <?php checked( $linked ); ?> /> <?php _e( 'A custom URL', 'page-links-to' ); ?></label></p> <div id="cws-links-to-custom-section" class="<?php echo ! $linked ? 'hide-if-js' : ''; ?>"> <p><input placeholder="http://" name="cws_links_to" type="text" id="cws-links-to" value="<?php echo esc_attr( $url ); ?>" /></p> <?php if ( $this->supports('new_tab') ) { ?> <p><label for="cws-links-to-new-tab"><input type="checkbox" name="cws_links_to_new_tab" id="cws-links-to-new-tab" value="_blank" <?php checked( (bool) self::get_target( $post->ID ) ); ?>> <?php _e( 'Open this link in a new tab', 'page-links-to' ); ?></label></p> <?php } ?> <?php do_action( 'page_links_to_meta_box_bottom' ); ?> </div> <script src="<?php echo esc_url( $this->get_url() ) . 'dist/meta-box.js?v=' . self::CSS_JS_VERSION; ?>"></script> <?php } /** * Saves data on attachment save. * * @param int $post_id The ID of the post being saved. * @return int the attachment post ID that was passed in. */ function edit_attachment( $post_id ) { return $this->save_post( $post_id ); } public static function supports( $feature = '' ) { switch( $feature ) { case 'new_tab': default: return apply_filters( 'page_links_to_supports_' . $feature, true ); } } /** * Saves data on post save. * * @param int $post_id a post ID. * @return int the post ID that was passed in. */ public static function save_post( $post_id ) { if ( isset( $_REQUEST['_cws_plt_nonce'] ) && wp_verify_nonce( $_REQUEST['_cws_plt_nonce'], 'cws_plt_' . $post_id ) ) { if ( ( ! isset( $_POST['cws_links_to_choice'] ) || 'custom' == $_POST['cws_links_to_choice'] ) && isset( $_POST['cws_links_to'] ) && strlen( $_POST['cws_links_to'] ) > 0 && $_POST['cws_links_to'] !== 'http://' ) { $url = self::clean_url( stripslashes( $_POST['cws_links_to'] ) ); self::set_link( $post_id, $url ); if ( isset( $_POST['cws_links_to_new_tab'] ) && self::supports( 'new_tab' ) ) { self::set_link_new_tab( $post_id ); } else { self::set_link_same_tab( $post_id ); } } else { self::delete_link( $post_id ); } } return $post_id; } /** * Cleans up a URL. * * @param string $url URL. * @return string cleaned up URL. */ public static function clean_url( $url ) { $url = trim( $url ); // Starts with 'www.'. Probably a mistake. So add 'http://'. if ( 0 === strpos( $url, 'www.' ) ) { $url = 'http://' . $url; } return $url; } /** * Have a post point to a custom URL. * * @param int $post_id post ID. * @param string $url the URL to point the post to. * @return bool whether anything changed. */ public static function set_link( $post_id, $url ) { do_action( 'page_links_to_set_link', $post_id, $url ); return (bool) update_post_meta( $post_id, self::LINK_META_KEY, $url ); } /** * Tell an custom URL post to open in a new tab. * * @param int $post_id post ID. * @return bool whether anything changed. */ public static function set_link_new_tab( $post_id ) { return (bool) update_post_meta( $post_id, self::TARGET_META_KEY, '_blank' ); } /** * Tell an custom URL post to open in the same tab. * * @param int $post_id post ID. * @return bool whether anything changed. */ public static function set_link_same_tab( $post_id ) { return delete_post_meta( $post_id, self::TARGET_META_KEY ); } /** * Discard a custom URL and point a post to its normal URL. * * @param int $post_id post ID. * @return bool whether the link was deleted. */ public static function delete_link( $post_id ) { $return = delete_post_meta( $post_id, self::LINK_META_KEY ); delete_post_meta( $post_id, self::TARGET_META_KEY ); // Old, unused data that we can delete on the fly. delete_post_meta( $post_id, '_links_to_type' ); do_action( 'page_links_to_delete_link', $post_id ); return $return; } /** * Filter for post links. * * @param string $link the URL for the post or page. * @param int|WP_Post $post post ID or object. * @return string output URL. */ public function link( $link, $post ) { if ( $this->replace ) { $post = get_post( $post ); if (! $post instanceof \WP_Post) { return $link; } $meta_link = self::get_link( $post->ID ); if ( $meta_link ) { $link = apply_filters( 'page_links_to_link', $meta_link, $post, $link ); $link = esc_url( $link ); if ( self::supports( 'new_tab' ) && ! is_admin() && ! (defined( 'REST_REQUEST' ) && REST_REQUEST ) && self::get_target( $post->ID ) ) { $link .= '#new_tab'; } } } return $link; } /** * Returns the original URL of the post. * * @param null|int|WP_Post $post The post to fetch. * @return string The post's original URL. */ function original_link( $post = null ) { $this->replace = false; $url = get_permalink( $post ); $this->replace = true; return $url; } /** * Whether the request has a flag that should halt the redirect. * * @return bool */ function has_non_redirect_flag() { return ( isset( $_GET['customize_theme'] ) || isset( $_GET['elementor-preview'] ) ); } /** * Performs a redirect. * * @return void */ function template_redirect() { $link = self::get_redirect(); if ( $link && !self::has_non_redirect_flag() ) { do_action( 'page_links_to_redirect_url', get_queried_object_id(), $link ); wp_redirect( $link, 301 ); exit; } } /** * Retrieves all posts that have a specified custom URL. * * @param string $url The URL to check. * @return array Array of post objects. */ public static function get_custom_url_posts( $url ) { $result = new WP_Query(array( 'post_type' => 'any', 'meta_key' => self::LINK_META_KEY, 'meta_value' => $url, 'posts_per_page' => -1, 'post_status' => 'any', )); return $result->posts; } /** * Retrieves all posts that have a custom URL. * * @return array Array of post objects. */ public static function get_all_custom_url_posts() { $result = new WP_Query(array( 'post_type' => 'any', 'meta_key' => self::LINK_META_KEY, 'posts_per_page' => -1, 'post_status' => 'any', )); return $result->posts; } /** * Gets the redirection URL. * * @return string|bool the redirection URL, or false. */ public static function get_redirect() { if ( ! is_singular() || ! get_queried_object_id() ) { return false; } $link = self::get_link( get_queried_object_id() ); if ( $link ) { $link = self::absolute_url( $link ); } return $link; } /** * Makes a relative URL into an absolute one. * * @param string $url The relative URL. * @return string The absolute URL. */ public static function absolute_url( $url ) { // Convert server- and protocol-relative URLs to absolute URLs. if ( '/' === $url[0] ) { // Protocol-relative. if ( '/' === $url[1] ) { $url = set_url_scheme( 'http:' . $url ); } else { // Host-relative. $url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $url ); } } if ( 'mailto' !== parse_url( $url, PHP_URL_SCHEME ) ) { $url = str_replace( '@', '%40', $url ); } return $url; } /** * Filters the list of pages to alter the links and targets. * * @param string $output the wp_list_pages() HTML block from WordPress. * @param array $_args (Unused) the arguments passed to `wp_list_pages()`. * @param array $pages Array of WP_Post objects. * @return string the modified HTML block. */ function wp_list_pages( $output, $_args = array(), $pages = array() ) { if ( empty( $pages ) ) { return $output; } $highlight = false; $this_url = esc_url_raw( set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] ) ); foreach ( (array) $pages as $page ) { $page_url = self::get_link( $page->ID ); if ( $page_url && $this_url === $page_url ) { $highlight = true; $current_page = esc_url( $page_url ); $current_page_id = $page->ID; } } if ( $highlight ) { $output = preg_replace( '|<li class="([^"]+) current_page_item"|', '<li class="$1"', $output ); // Kill default highlighting. $output = preg_replace( '|<li class="(page_item page-item-' . $current_page_id . ')"|', '<li class="$1 current_page_item"', $output ); } return $output; } /** * Filters nav menu objects and adds target=_blank to the ones that need it. * * @param array $items nav menu items. * @return array modified nav menu items. */ public static function wp_nav_menu_objects( $items ) { $new_items = array(); foreach ( $items as $item ) { if ( isset( $item->object_id ) && self::get_target( $item->object_id ) ) { $item->target = '_blank'; } $new_items[] = $item; } return $new_items; } /** * Hooks in as a post is being loaded for editing and conditionally adds a notice. * * @return void */ public function load_post() { if ( isset( $_GET['post'] ) && self::get_link( (int) $_GET['post'] ) ) { $this->hook( 'edit_form_after_title' ); $this->hook( 'admin_notices', 'notify_of_external_link' ); $this->replace = false; } } /** * Ajax handler for dismissing a notice. * * @return void */ public static function ajax_dismiss_notice() { if ( isset( $_GET['plt_notice'] ) ) { self::dismiss_notice( $_GET['plt_notice'] ); } } /** * Ajad handler for creating a page link. * * @return void */ public function ajax_quick_add() { if ( current_user_can( 'edit_pages' ) ) { check_ajax_referer( 'plt-quick-add', 'plt_nonce' ); $post = stripslashes_deep( $_POST ); $title = $post['plt_title']; $url = $post['plt_url']; $slug = $post['plt_slug']; $publish = (bool) $post['plt_publish'] && current_user_can( 'publish_pages' ); $post_id = wp_insert_post(array( 'post_type' => 'page', 'post_status' => $publish ? 'publish' : 'draft', 'post_title' => $title, 'post_name' => $slug, )); $this->set_link( $post_id, $url ); $post = get_post( $post_id ); $message = $publish ? __( 'New page link published!', 'page-links-to' ) : __( 'Page link draft saved!', 'page-links-to' ); wp_send_json_success( array( 'id' => $post->ID, 'title' => $post->post_title, 'wpUrl' => $this->original_link( $post->ID ), 'url' => self::get_link( $post->ID ), 'slug' => $post->post_name, 'status' => $post->post_status, 'message' => $message, )); } } /** * Whether a message should be displayed. * * @return bool Whether to display the message. */ public static function should_display_message() { return false; } /** * Return the notices which have been dismissed. * * @return array The list of notice IDs that have been dismissed. */ public function get_dismissed_notices() { return get_option( self::DISMISSED_NOTICES, array() ); } /** * Mark a notice as dismissed. * * @param int $id The notice ID to dismiss. * @return void */ public static function dismiss_notice( $id ) { $notices = self::get_dismissed_notices(); $notices[] = (int) $id; $notices = array_unique( $notices ); update_option( self::DISMISSED_NOTICES, $notices ); } /** * Whether anyone on this site has dismissed the given notice. * * @param int $id The ID of the notice. * @return bool Whether anyone has dismissed it. */ public static function has_dismissed_notice( $id ) { $dismissed_notices = get_option( self::DISMISSED_NOTICES, array() ); return in_array( (int) $id, $dismissed_notices ); } /** * Output the generic notice. * * @return void */ public static function notify_generic() { if ( self::is_block_editor() ) { // Nothing right now. } else { ?> <div id="page-links-to-notification" class="notice updated is-dismissible"><h3><?php _e( 'Page Links To', 'page-links-to' ); ?></h3> <p><a class="button plt-dismiss" target="_blank" href="<?php echo esc_url( self::NEWSLETTER_URL ); ?>"><?php _e( 'Give Me Updates', 'page-links-to' ); ?></a> <small><a href="javascript:void(0)" class="plt-dismiss"><?php _e( 'No thanks', 'page-links-to' ); ?></a></small></p> </div> <script> (function($){ var $plt = $('#page-links-to-notification'); $plt .on('click', '.notice-dismiss', function(e){ $.ajax( ajaxurl, { type: 'GET', data: { action: 'plt_dismiss_notice', plt_notice: <?php echo json_encode( self::MESSAGE_ID ); ?> } }); }) .on('click', '.plt-dismiss', function(e){ e.preventDefault(); $(this).parents('.notice').first().find('.notice-dismiss').click(); }); })(jQuery); </script> <?php } } /** * Whether the user is using the block editor (Gutenberg). * * @return bool */ public static function is_block_editor() { $current_screen = get_current_screen(); return method_exists( $current_screen, 'is_block_editor' ) && $current_screen->is_block_editor(); } /** * Create a block editor notification. * * @param string $text The notification. * @param string $type The type of notification. * @return void */ public static function block_editor_notification( $text, $type = 'info' ) { if ( ! in_array( $type, array( 'error', 'warning', 'info' ) ) ) { return; } $type = ucfirst( $type ); $method = "create{$type}Notice"; ?> <script> document.addEventListener('DOMContentLoaded', function() { if (wp.data !== undefined) { wp.data.dispatch('core/notices').<?php echo $method; ?>(<?php echo json_encode( $text ); ?>, {isDismissible: true, id: 'page-links-to-notice'}); } }); </script> <?php } /** * Returns the panel title. * * @return string The panel title. */ public static function get_panel_title() { return apply_filters( 'page_links_to_panel_title', _x( 'Page Links To', 'Meta box title', 'page-links-to' ) ); } /** * Outputs a notice that the current post item is pointed to a custom URL. * * @return void */ public static function notify_of_external_link() { if ( self::is_block_editor() ) { // Disabled, currently, because these notifications can block the title, which is annoying. false && self::block_editor_notification( 'Note: This content is pointing to a custom URL. Use the “Page Links To” area in the sidebar to control this.', 'info' ); } else { ?> <div class="notice updated"><p><?php printf( __( '<strong>Note</strong>: This content is pointing to a custom URL. Use the “%s” box to change this behavior.', 'page-links-to' ), self::get_panel_title() ); ?></p></div> <?php } } /** * Inserts an Edit link after the title. * * @return void */ public function edit_form_after_title() { $this->replace = true; $post = get_post(); $link = self::get_link( $post ); if ( ! $link ) { return; } echo '<div class="plt-links-to"><strong>' . __( 'Links to:', 'page-links-to' ) . '</strong> <a href="' . esc_url( $link ) . '">' . esc_html( $link ) . '</a> <button type="button" class="edit-slug button button-small hide-if-no-js">Edit</button></div>'; } /** * Adds a GitHub link to the plugin meta. * * @param array $links the current array of links. * @param string $file the current plugin being processed. * @return array the modified array of links. */ public function plugin_row_meta( $links, $file ) { if ( $file === plugin_basename( $this->file ) ) { return array_merge( $links, array( '<a href="https://github.com/markjaquith/page-links-to" target="_blank">GitHub</a>' ) ); } else { return $links; } } /** * Filter the post states to indicate which ones are linked using this plugin. * * @param array $states The existing post states. * @param WP_Post $post The current post object being displayed. * @return array The modified post states array. */ public function display_post_states( $states, $post ) { $link = self::get_link( $post ); if ( $link ) { $link = $this->absolute_url( $link ); $output = ''; $output_parts = array( 'custom' => '<a title="' . __( 'Linked URL', 'page-links-to' ) . '" href="' . esc_url( $link ) . '" class="plt-post-state-link"><span class="dashicons dashicons-admin-links"></span><span class="url"> ' . esc_url( $link ) . '</span></a>', ); $output_parts = apply_filters( 'page_links_to_post_state_parts', $output_parts, $post, $link ); $output .= '<span class="plt-post-info">' . implode( $output_parts ) . '</span>'; $states['plt'] = $output; } return $states; } /** * Returns the URL of this plugin's directory. * * @return string this plugin's directory URL. */ public function get_url() { return plugin_dir_url( $this->file ); } /** * Returns the filesystem path of this plugin's directory. * * @return string this plugin's directory filesystem path. */ public function get_path() { return plugin_dir_path( $this->file ); } }