plugin = $plugin; $this->settings = $settings; // Add Settings page link to plugin actions cell. add_filter( 'plugin_action_links_' . $this->plugin->basename, array( $this, 'plugin_settings_link' ) ); // Update links in plugin row on Plugins page. add_filter( 'plugin_row_meta', array( $this, 'add_plugin_meta_links' ), 10, 2 ); // Create menu item for settings page. add_action( 'admin_menu', array( $this, 'add_admin_menu' ) ); // add_action( 'admin_init', array( $this, 'settings_init' ) ); add_action( 'admin_init', array( $this, 'settings_register' ) ); // Plugins settings page only hooks. $current_page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS ); if ( ! empty( $current_page ) && $current_page === $this->plugin->slug ) { $this->allowed_html = Common::allowed_html(); $this->form_allowed_html = Common::form_allowed_html(); // Initiate settings section and fields. add_action( 'admin_init', array( $this, 'settings_prepare' ) ); // Add Review CTA to the footer thankyou add_filter( 'admin_footer_text', array( $this, 'custom_footer_thankyou' ) ); } } /** * Add submenu for Head & Footer code to Tools. */ public function add_admin_menu() { add_submenu_page( 'tools.php', // Parent Slug. $this->plugin->name, // Page Title. $this->plugin->name, // Menu Title. 'manage_options', // Capability. $this->plugin->slug, // Menu Slug. array( $this, 'options_page' ) // Callback. // Position. ); } /** * Register a setting and its sanitization callback. * * This is part of the Settings API, which lets you automatically generate * wp-admin settings pages by registering your settings and using a few * callbacks to control the output. * * @return void */ public function settings_register() { $homepage_blog_posts = 'posts' === get_option( 'show_on_front', false ) ? true : false; // Site-wide. register_setting( 'head_footer_code_settings', // Option group. 'auhfc_settings_sitewide', // Option name. array( 'sanitize_callback' => array( $this, 'sanitize_sitewide' ), ) ); // Blog gomepage. if ( $homepage_blog_posts ) { register_setting( 'head_footer_code_settings', // Option group. 'auhfc_settings_homepage', // Option name. array( 'sanitize_callback' => array( $this, 'sanitize_homepage' ), ) ); } // Articles register_setting( 'head_footer_code_settings', // Option group. 'auhfc_settings_article', // Option name. array( 'sanitize_callback' => array( $this, 'sanitize_article' ), ) ); } /** * Register a setting and its sanitization callback * define section and settings fields */ public function settings_prepare() { /** * Get settings from options table */ $homepage_blog_posts = 'posts' === get_option( 'show_on_front', false ) ? true : false; $head_note = $this->head_note(); $this->security_risk_notice = Common::get_security_risk_notice(); /** * Settings Sections are the groups of settings you see on WordPress settings pages * with a shared heading. In your plugin you can add new sections to existing * settings pages rather than creating a whole new page. This makes your plugin * simpler to maintain and creates less new pages for users to learn. * You just tell them to change your setting on the relevant existing page. */ add_settings_section( 'head_footer_code_settings_sitewide', // Id. __( 'Site-wide head, body and footer code', 'head-footer-code' ), // Title. array( $this, 'sitewide_settings_section_description' ), // Callback. $this->plugin->slug // Page. ); /** * Register a settings field to a settings page and section. * This is part of the Settings API, which lets you automatically generate * wp-admin settings pages by registering your settings and using a few * callbacks to control the output. */ $this->add_field( 'head', // Id. esc_html__( 'HEAD Code', 'head-footer-code' ), // Title. 'textarea_field_render', // Callback method name. 'sitewide', // Section. array( // Arguments. 'description' => $head_note . '

' . sprintf( /* translators: %s will be replaced with preformatted HTML tag */ esc_html__( 'Code to enqueue in HEAD section (before the %s).', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 7, ) ); $this->add_field( 'priority_h', esc_html__( 'HEAD Priority', 'head-footer-code' ), 'number_field_render', 'sitewide', array( 'description' => sprintf( /* translators: 1: default HEAD priority, 2: preformatted HTML tag */ esc_html__( 'Priority for enqueued HEAD code. Default is %1$d. Larger number inject code closer to %2$s.', 'head-footer-code' ), 10, Common::format_as_code( '' ) ), 'class' => 'num', 'min' => 1, 'max' => 1000, 'step' => 1, ) ); $this->add_field( 'do_shortcode_h', esc_html__( 'Process HEAD Shortcodes', 'head-footer-code' ), 'select_field_render', 'sitewide', array( 'items' => array( 'y' => __( 'Enable', 'head-footer-code' ), 'n' => __( 'Disable', 'head-footer-code' ), ), 'description' => esc_html__( 'If you wish to process shortcodes in the HEAD section, enable this option. Please note, shortcodes with malformed output in the HEAD section can break the rendering of your website!', 'head-footer-code' ), 'class' => 'regular-text', ) ); $this->add_field( 'body', esc_html__( 'BODY Code', 'head-footer-code' ), 'textarea_field_render', 'sitewide', array( 'description' => '

' . sprintf( /* translators: %s will be replaced with preformatted HTML tag */ esc_html__( 'Code to enqueue in BODY section (after the %s).', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 7, ) ); $this->add_field( 'priority_b', esc_html__( 'BODY Priority', 'head-footer-code' ), 'number_field_render', 'sitewide', array( 'description' => sprintf( /* translators: 1: default BODY priority, 2: preformatted HTML tag */ esc_html__( 'Priority for enqueued BODY code. Default is %1$d. Smaller number inject code closer to %2$s.', 'head-footer-code' ), 10, Common::format_as_code( '' ) ), 'class' => 'num', 'min' => 1, 'max' => 1000, 'step' => 1, ) ); $this->add_field( 'do_shortcode_b', esc_html__( 'Process BODY Shortcodes', 'head-footer-code' ), 'select_field_render', 'sitewide', array( 'items' => array( 'y' => __( 'Enable', 'head-footer-code' ), 'n' => __( 'Disable', 'head-footer-code' ), ), 'description' => esc_html__( 'If you wish to process shortcodes in the BODY section, enable this option.', 'head-footer-code' ), 'class' => 'regular-text', ) ); $this->add_field( 'footer', esc_html__( 'FOOTER Code', 'head-footer-code' ), 'textarea_field_render', 'sitewide', array( 'description' => '

' . sprintf( /* translators: %s will be replaced with preformatted HTML tag */ esc_html__( 'Code to enqueue in footer section (before the %s).', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 7, ) ); $this->add_field( 'priority_f', esc_html__( 'FOOTER Priority', 'head-footer-code' ), 'number_field_render', 'sitewide', array( 'description' => sprintf( /* translators: 1: default FOOTER priority, 2: preformatted HTML tag */ esc_html__( 'Priority for enqueued FOOTER code. Default is %1$d. Larger number inject code closer to %2$s.', 'head-footer-code' ), 10, Common::format_as_code( '' ) ), 'class' => 'num', 'min' => 1, 'max' => 1000, 'step' => 1, ) ); $this->add_field( 'do_shortcode_f', esc_html__( 'Process FOOTER Shortcodes', 'head-footer-code' ), 'select_field_render', 'sitewide', array( 'items' => array( 'y' => __( 'Enable', 'head-footer-code' ), 'n' => __( 'Disable', 'head-footer-code' ), ), 'description' => esc_html__( 'If you wish to process shortcodes in the FOOTER section, enable this option.', 'head-footer-code' ), 'class' => 'regular-text', ) ); /** * Add section for Homepage if show_on_front is set to Blog Posts */ if ( $homepage_blog_posts ) { /** * Settings Sections are the groups of settings you see on WordPress settings pages * with a shared heading. In your plugin you can add new sections to existing * settings pages rather than creating a whole new page. This makes your plugin * simpler to maintain and creates less new pages for users to learn. * You just tell them to change your setting on the relevant existing page. */ add_settings_section( 'head_footer_code_settings_homepage', // Id. esc_html__( 'Head, body and footer code on Homepage in Blog Posts mode', 'head-footer-code' ), // Title. array( $this, 'homepage_settings_section_description' ), // Callback. $this->plugin->slug // Page. ); /** * Register a settings field to a settings page and section. * This is part of the Settings API, which lets you automatically generate * wp-admin settings pages by registering your settings and using a few * callbacks to control the output. */ $this->add_field( 'head', // Id. esc_html__( 'Homepage HEAD Code', 'head-footer-code' ), // Title. 'textarea_field_render', // Callback name. 'homepage', // Section. array( // Arguments. 'label' => __( 'Homepage HEAD Code', 'head-footer-code' ), 'description' => $head_note . '

' . sprintf( /* translators: %s will be replaced with preformatted HTML tag */ esc_html__( 'Code to enqueue in HEAD section (before the %s) on Homepage.', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 5, ) ); $this->add_field( 'body', esc_html__( 'Homepage BODY Code', 'head-footer-code' ), 'textarea_field_render', 'homepage', array( 'label' => __( 'Homepage BODY Code', 'head-footer-code' ), 'description' => '

' . sprintf( /* translators: %s: preformatted HTML tag */ esc_html__( 'Code to enqueue in BODY section (after the %s) on Homepage.', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 5, ) ); $this->add_field( 'footer', esc_html__( 'Homepage FOOTER Code', 'head-footer-code' ), 'textarea_field_render', 'homepage', array( 'label' => __( 'Homepage FOOTER Code', 'head-footer-code' ), 'description' => '

' . sprintf( /* translators: %s will be replaced with preformatted HTML tag */ esc_html__( 'Code to enqueue in footer section (before the %s) on Homepage.', 'head-footer-code' ), Common::format_as_code( '' ) ) . '

', 'field_class' => 'widefat code codeEditor', 'rows' => 5, ) ); $this->add_field( 'behavior', esc_html__( 'Behavior', 'head-footer-code' ), 'select_field_render', 'homepage', array( 'items' => array( 'append' => __( 'Append to the site-wide code', 'head-footer-code' ), 'replace' => __( 'Replace the site-wide code', 'head-footer-code' ), ), 'description' => esc_html__( 'Chose how the Homepage specific code will be enqueued in relation to site-wide code.', 'head-footer-code' ), 'class' => 'regular-text', ) ); $this->add_field( 'paged', esc_html__( 'On paged homepage', 'head-footer-code' ), 'select_field_render', 'homepage', array( 'items' => array( 'yes' => __( 'Add on paged homepage', 'head-footer-code' ), 'no' => __( 'Do not add on paged homepage', 'head-footer-code' ), ), 'description' => esc_html__( 'Chose if the Homepage specific code will be enqueued on paged pages 2, 3, and so on.', 'head-footer-code' ), 'class' => 'regular-text', ) ); } // END condition: $homepage_blog_posts /** * Settings Sections are the groups of settings you see on WordPress settings pages * with a shared heading. In your plugin you can add new sections to existing * settings pages rather than creating a whole new page. This makes your plugin * simpler to maintain and creates less new pages for users to learn. * You just tell them to change your setting on the relevant existing page. */ add_settings_section( 'head_footer_code_settings_article', // Id. esc_html__( 'Article specific settings', 'head-footer-code' ), // Title. array( $this, 'article_settings_section_description' ), // Callback. $this->plugin->slug // Page. ); // Prepare clean list of post types w/o attachment. $public_post_types = get_post_types( array( 'public' => true ), 'objects' ); $clean_post_types = array(); foreach ( $public_post_types as $public_post_type => $public_post_object ) { if ( 'attachment' === $public_post_type ) { continue; } $clean_post_types[ $public_post_type ] = esc_html( $public_post_object->label ) . ' (' . esc_attr( $public_post_type ) . ')'; } $this->add_field( 'post_types', // Field key. esc_html__( 'Post Types', 'head-footer-code' ), // Title. 'checkbox_group_field_render', // Callback method name. 'article', // Section. array( // Arguments. 'label_for' => false, 'items' => $clean_post_types, 'description' => esc_html__( 'Choose the post types that will have an article specific section.', 'head-footer-code' ) . '
' . esc_html__( 'Please note, if you add head, body, and footer code for individual articles and then disable that post type, the article-specific code will no longer be output and only the site-wide code will be used.', 'head-footer-code' ), 'class' => 'checkbox', ) ); // Prepare list of public taxonomies, including built-in ones $public_taxonomies = get_taxonomies( array( 'public' => true ), 'objects' ); $clean_taxonomies = array(); foreach ( $public_taxonomies as $tax_slug => $tax_object ) { // Skip specific eg. nav_menu, post_format if ( in_array( $tax_slug, array( 'nav_menu', 'post_format' ), true ) ) { continue; } $clean_taxonomies[ $tax_slug ] = esc_html( $tax_object->label ) . ' (' . esc_attr( $tax_slug ) . ')'; } $this->add_field( 'taxonomies', // Field key. esc_html__( 'Taxonomies', 'head-footer-code' ), // Title. 'checkbox_group_field_render', // Callback method name. 'article', // Section. array( // Arguments. 'label_for' => false, 'items' => $clean_taxonomies, 'description' => esc_html__( 'Choose the taxonomies that will have a taxonomy specific section.', 'head-footer-code' ) . '
' . esc_html__( 'Please note, if you add head, body, and footer code for individual taxonomy and then disable that taxonomy, the txonomy-specific code will no longer be output and only the site-wide code will be used.', 'head-footer-code' ), 'class' => 'checkbox', ) ); $this->add_field( 'allowed_roles', // Field key. esc_html__( 'Allow for User Roles', 'head-footer-code' ), // Title. 'checkbox_group_field_render', // Callback method name. 'article', // Section. array( // Arguments. 'label_for' => false, 'items' => array( 'editor' => __( 'Editor', 'head-footer-code' ), 'author' => __( 'Author', 'head-footer-code' ), ), 'description' => esc_html__( 'Choose which unprivileged user roles can manage article-specific and taxonomy-specific code.', 'head-footer-code' ) . '
' . '' . esc_html__( 'Security Notice', 'head-footer-code' ) . '
' . '' . esc_html__( 'Granting access to non-administrator roles (e.g., Editors) allows users to inject raw HTML, CSS, and JavaScript into individual posts and pages, and taxonomies!', 'head-footer-code' ) . '
' . esc_html__( 'This may pose a security risk if those users are not fully trusted!', 'head-footer-code' ) . '
' . esc_html__( 'Only allow for roles you trust to handle code responsibly!', 'head-footer-code' ) . '
', 'class' => 'checkbox', ) ); } /** * Wrapper for add_settings_field * * @param string $key Field key to identify the field. * @param string $title Formatted title of the field. Shown as the label for the field during output. * @param string $callback_name Name of the function that fills the field with the desired form inputs. * @param string $section Key of the section of the settings page in which to show the box. * @param array $args { * Optional. Extra arguments that get passed to add_settingd_field $args * * @type bool $label_for If `false` the setting title will not be wrapped in a `