array of panel ids). /** * Class constructor * * @return void */ function init() { $this->registered_panels = array(); $this->page_panels = array(); add_action( 'current_screen', array( $this, 'populate_page_panels' ) ); add_filter( 'screen_settings', array( &$this, 'append_screen_settings' ), 10, 2 ); add_action( 'admin_print_scripts', array( &$this, 'add_autosave_script' ) ); } /** * Add a new settings panel to the "Screen Options" box. * * @param string $id String to use in the 'id' attribute of the settings panel. Should be unique. * @param string $title Title of the settings panel. Set to an empty string to omit title. * @param callback $callback Function that fills the panel with the desired content. Should return its output. * @param string|array $page The page(s) on which to show the panel (similar to add_meta_box()). * @param callback $save_callback Optional. Function that saves the settings. * @param bool $autosave Optional. If set, settings will be automatically saved (via AJAX) when the value of any input element in the panel changes. Defaults to false. * @return void */ function add_screen_options_panel( $id, $title, $callback, $page, $save_callback = null, $autosave = false ) { if ( ! is_array( $page ) ) { $page = array( $page ); } $new_panel = array( 'title' => $title, 'callback' => $callback, 'page' => $page, 'save_callback' => $save_callback, 'autosave' => $autosave, ); $this->registered_panels[ $id ] = $new_panel; if ( $save_callback ) { add_action( 'wp_ajax_save_settings-' . $id, array( $this, 'ajax_save_callback' ) ); } } /** * Populate a lookup array for screen -> panels queries. * * This is a callback for the "current_screen" action. We have to do it in this hook or WordPress will * complain about "doing it wrong" and incorrectly suggest using the "add_meta_boxes" action. * * "add_meta_boxes" doesn't work here because it only gets called on CPT pages and we want the ability * to add screen options to any page. */ function populate_page_panels() { foreach ( $this->registered_panels as $id => $panel ) { $page = $panel['page']; //Convert page hooks/slugs to screen IDs $page = array_map( array( $this, 'page_to_screen_id' ), $page ); $page = array_unique( $page ); //Store the panel ID in each relevant page's list foreach ( $page as $page_id ) { if ( ! isset( $this->page_panels[ $page_id ] ) ) { $this->page_panels[ $page_id ] = array(); } $this->page_panels[ $page_id ][] = $id; } } } /** * Convert a page hook name to a screen ID. * * @uses convert_to_screen() * @access private * * @param string $page * @return string */ function page_to_screen_id( $page ) { if ( function_exists( 'convert_to_screen' ) ) { $screen = convert_to_screen( $page ); if ( isset( $screen->id ) ) { return $screen->id; } else { return ''; } } else { return str_replace( array( '.php', '-new', '-add' ), '', $page ); } } /** * Append custom panel HTML to the "Screen Options" box of the current page. * Callback for the 'screen_settings' filter (available in WP 3.0 and up). * * @access private * * @param string $current * @param string $screen Screen object (undocumented). * @return string The HTML code to append to "Screen Options" */ function append_screen_settings( $current, $screen ) { global $hook_suffix; //Sanity check if ( ! isset( $screen->id ) ) { return $current; } //Are there any panels that want to appear on this page? $panels = $this->get_panels_for_screen( $screen->id, $hook_suffix ); if ( empty( $panels ) ) { return $current; } //Append all panels registered for this screen foreach ( $panels as $panel_id ) { $panel = $this->registered_panels[ $panel_id ]; //Add panel title if ( ! empty( $panel['title'] ) ) { $current .= "\n
" . $panel['title'] . "
\n"; } //Generate panel contents if ( is_callable( $panel['callback'] ) ) { $contents = call_user_func( $panel['callback'] ); $classes = array( 'custom-options-panel', ); if ( $panel['autosave'] ) { $classes[] = 'requires-autosave'; } $contents = sprintf( '
%s
', esc_attr( $panel_id ), implode( ' ', $classes ), esc_attr( $panel_id ), wp_create_nonce( 'save_settings-' . $panel_id ), $contents ); $current .= $contents; } } return $current; } /** * AJAX callback for the "Screen Options" autosave. * * @access private * @return void */ function ajax_save_callback() { if ( empty( $_POST['action'] ) ) { die( '0' ); } //The 'action' argument is in the form "save_settings-panel_id" $id = end( explode( '-', $_POST['action'], 2 ) ); //Basic security check. check_ajax_referer( 'save_settings-' . $id, '_wpnonce-' . $id ); //Hand the request to the registered callback, if any if ( ! isset( $this->registered_panels[ $id ] ) ) { exit( '0' ); } $panel = $this->registered_panels[ $id ]; if ( is_callable( $panel['save_callback'] ) ) { call_user_func( $panel['save_callback'], $_POST ); die( '1' ); } else { die( '0' ); } } /** * Add/enqueue supporting JavaScript for the autosave function of custom "Screen Options" panels. * * Checks if the current page is supposed to contain any autosave-enabled * panels and adds the script only if that's the case. * * @return void */ function add_autosave_script() { //Get the page id/hook/slug/whatever. global $hook_suffix; //Check if we have some panels with autosave registered for this page. $panels = $this->get_panels_for_screen( '', $hook_suffix ); if ( empty( $panels ) ) { return; } $got_autosave = false; foreach ( $panels as $panel_id ) { if ( $this->registered_panels[ $panel_id ]['autosave'] ) { $got_autosave = true; break; } } if ( $got_autosave ) { //Enqueue the script itself $url = plugins_url( 'screen-options.js', __FILE__ ); wp_enqueue_script( 'screen-options-custom-autosave', $url, array( 'jquery' ) ); } } /** * Get custom panels registered for a particular screen and/or page. * * @param string $screen_id Screen ID. * @param string $page Optional. Page filename or hook name. * @return array Array of custom panels. */ function get_panels_for_screen( $screen_id, $page = '' ) { if ( isset( $this->page_panels[ $screen_id ] ) && ! empty( $this->page_panels[ $screen_id ] ) ) { $panels = $this->page_panels[ $screen_id ]; } else { $panels = array(); } if ( ! empty( $page ) ) { $page_as_screen = $this->page_to_screen_id( $page ); if ( isset( $this->page_panels[ $page_as_screen ] ) && ! empty( $this->page_panels[ $page_as_screen ] ) ) { $panels = array_merge( $panels, $this->page_panels[ $page_as_screen ] ); } } return array_unique( $panels ); } } //All versions of the class are stored in a global array //and only the latest version is actually used. global $ws_screen_options_versions; if ( ! isset( $ws_screen_options_versions ) ) { $ws_screen_options_versions = array(); } $ws_screen_options_versions['1.3'] = 'wsScreenOptions13'; endif; if ( ! function_exists( 'add_screen_options_panel' ) ) { /** * Add a new settings panel to the "Screen Options" box. * * @see wsScreenOptions10::add_screen_options_panel() * * @param string $id String to use in the 'id' attribute of the settings panel. Should be unique. * @param string $title Title of the settings panel. Set to an empty string to omit title. * @param callback $callback Function that fills the panel with the desired content. Should return its output. * @param string|array $page The page(s) on which to show the panel (similar to add_meta_box()). * @param callback $save_callback Optional. Function that saves the settings contained in the panel. * @param bool $autosave Optional. If set, settings will be automatically saved (via AJAX) when the value of any input element in the panel changes. Defaults to false. * @return void */ function add_screen_options_panel( $id, $title, $callback, $page, $save_callback = null, $autosave = false ) { global $ws_screen_options_versions; static $instance = null; /** @var wsScreenOptions13 $instance */ if ( is_null( $instance ) ) { //Instantiate the latest version of the wsScreenOptions class uksort( $ws_screen_options_versions, 'version_compare' ); $className = end( $ws_screen_options_versions ); $instance = new $className; $instance->init(); } $instance->add_screen_options_panel( $id, $title, $callback, $page, $save_callback, $autosave ); } }