*/
protected $data = array();
/**
* Number of screen columns for post boxes.
*
* @since 1.0.0
* @var int
*/
protected $screen_columns = 0;
/**
* User action for this screen.
*
* @since 1.0.0
* @var string
*/
protected $action = '';
/**
* Instance of the Admin Page Helper Class, with necessary functions.
*
* @since 1.0.0
* @var TablePress_Admin_Page
*/
protected $admin_page;
/**
* List of text boxes (similar to post boxes, but just with text and without extra functionality).
*
* @since 1.0.0
* @var array>>
*/
protected $textboxes = array();
/**
* List of messages that are to be displayed as boxes below the page title.
*
* @since 1.0.0
* @var string[]
*/
protected $header_messages = array();
/**
* Whether there are post boxes registered for this screen,
* is automatically set to true, when a meta box is added.
*
* @since 1.0.0
* @var bool
*/
protected $has_meta_boxes = false;
/**
* List of WP feature pointers for this view.
*
* @since 1.0.0
* @var string[]
*/
protected $wp_pointers = array();
/**
* Initialize the View class, by setting the correct screen columns and adding help texts.
*
* @since 1.0.0
*/
public function __construct() {
$screen = get_current_screen();
if ( 0 !== $this->screen_columns ) {
$screen->add_option( 'layout_columns', array( 'max' => $this->screen_columns ) );
}
// Enable two column layout.
add_filter( "get_user_option_screen_layout_{$screen->id}", array( $this, 'set_current_screen_layout_columns' ) );
$common_content = '
' . sprintf( __( 'More information about TablePress can be found on the plugin website or on its page in the WordPress Plugin Directory.', 'tablepress' ), 'https://tablepress.org/', 'https://wordpress.org/plugins/tablepress/' ) . '
';
$common_content .= '
' . sprintf( __( 'For technical information, please see the Documentation.', 'tablepress' ), 'https://tablepress.org/documentation/' ) . ' ' . sprintf( __( 'Common questions are answered in the FAQ.', 'tablepress' ), 'https://tablepress.org/faq/' ) . '
';
if ( tb_tp_fs()->is_free_plan() ) {
$common_content .= '
'
. sprintf( __( 'Support is provided through the WordPress Support Forums.', 'tablepress' ), 'https://tablepress.org/support/', 'https://wordpress.org/tags/tablepress' )
. ' '
. sprintf( __( 'Before asking for support, please carefully read the Frequently Asked Questions, where you will find answers to the most common questions, and search through the forums.', 'tablepress' ), 'https://tablepress.org/faq/' )
. '
';
$common_content .= '
' . sprintf( __( 'More great features for you and your site’s visitors and priority email support are available with a Premium license plan of TablePress. Go check them out!', 'tablepress' ), 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=help-tab' ) . '
';
}
$screen->add_help_tab( array(
'id' => 'tablepress-help', // This should be unique for the screen.
'title' => __( 'TablePress Help', 'tablepress' ),
'content' => '
' . $this->help_tab_content() . '
' . $common_content,
) );
// "Sidebar" in the help tab.
$screen->set_help_sidebar(
'
' . __( 'For more information:', 'tablepress' ) . '
'
);
}
/**
* Change the value of the user option "screen_layout_{$screen->id}" through a filter.
*
* @since 1.0.0
*
* @param int|false $result Current value of the user option.
* @return int New value for the user option.
*/
public function set_current_screen_layout_columns( /* int|false */ $result ): int {
if ( false === $result ) {
// The user option does not yet exist.
$result = $this->screen_columns;
} elseif ( $result > $this->screen_columns ) {
// The value of the user option is bigger than what is possible on this screen (e.g. because the number of columns was reduced in an update).
$result = $this->screen_columns;
}
return $result;
}
/**
* Set up the view with data and do things that are necessary for all views.
*
* @since 1.0.0
*
* @param string $action Action for this view.
* @param array $data Data for this view.
*/
public function setup( /* string */ $action, array $data ) /* : void */ {
// Don't use type hints (except array $data) in method declaration, as the method is extended in some TablePress Extensions which are no longer updated.
$this->action = $action;
$this->data = $data;
// Set page title.
$GLOBALS['title'] = sprintf( __( '%1$s ‹ %2$s', 'tablepress' ), $this->data['view_actions'][ $this->action ]['page_title'], 'TablePress' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
// Admin page helpers, like script/style loading, could be moved to view.
$this->admin_page = TablePress::load_class( 'TablePress_Admin_Page', 'class-admin-page-helper.php', 'classes' );
$this->admin_page->enqueue_style( 'common' );
// RTL styles for the admin interface.
if ( is_rtl() ) {
$this->admin_page->enqueue_style( 'common-rtl', array( 'tablepress-common' ) );
}
$this->admin_page->enqueue_script( 'common', array( 'jquery-core', 'postbox' ) );
$this->admin_page->add_admin_footer_text();
// Initialize WP feature pointers for TablePress.
$this->_init_wp_pointers();
// Necessary fields for all views.
$this->add_text_box( 'default_nonce_fields', array( $this, 'default_nonce_fields' ), 'header', false );
$this->add_text_box( 'action_nonce_field', array( $this, 'action_nonce_field' ), 'header', false );
$this->add_text_box( 'action_field', array( $this, 'action_field' ), 'header', false );
}
/**
* Register a header message for the view.
*
* @since 1.0.0
*
* @param string $text Text for the header message.
* @param string $css_class Optional. Additional CSS class for the header message.
* @param string $title Optional. Text for the header title.
*/
protected function add_header_message( string $text, string $css_class = 'notice-success', string $title = '' ): void {
if ( ! str_contains( $css_class, 'not-dismissible' ) ) {
$css_class .= ' is-dismissible';
}
if ( '' !== $title ) {
$title = "
{$title}
";
}
// Wrap the message text in HTML
tags if it does not already start with one (potentially with attributes), indicating custom message HTML.
if ( '' !== $text && ! str_starts_with( $text, '
{$text}
";
}
$this->header_messages[] = "
{$title}{$text}
\n";
}
/**
* Process header action messages, i.e. check if a message should be added to the page.
*
* @since 1.0.0
*
* @param array $action_messages Action messages for the screen.
*/
protected function process_action_messages( array $action_messages ): void {
if ( $this->data['message'] && isset( $action_messages[ $this->data['message'] ] ) ) {
$class = ( str_starts_with( $this->data['message'], 'error' ) ) ? 'notice-error' : 'notice-success';
if ( '' !== $this->data['error_details'] ) {
$this->data['error_details'] = '
' . sprintf( __( 'Error code: %s', 'tablepress' ), '' . esc_html( $this->data['error_details'] ) . '' );
}
$this->add_header_message( "{$action_messages[ $this->data['message'] ]}{$this->data['error_details']}", $class );
}
}
/**
* Register a text box for the view.
*
* @since 1.0.0
*
* @param string $id Unique HTML ID for the text box container (only visible with $wrap = true).
* @param callable $callback Callback that prints the contents of the text box.
* @param string $context Optional. Context/position of the text box (normal, side, additional, header, submit).
* @param bool $wrap Whether the content of the text box shall be wrapped in a
container.
*/
protected function add_text_box( string $id, callable $callback, string $context = 'normal', bool $wrap = false ): void {
if ( ! isset( $this->textboxes[ $context ] ) ) {
$this->textboxes[ $context ] = array();
}
$long_id = "tablepress_{$this->action}-{$id}";
$this->textboxes[ $context ][ $id ] = array(
'id' => $long_id,
'callback' => $callback,
'context' => $context,
'wrap' => $wrap,
);
}
/**
* Register a post meta box for the view, that is drag/droppable with WordPress functionality.
*
* @since 1.0.0
*
* @param string $id Unique ID for the meta box.
* @param string $title Title for the meta box.
* @param callable $callback Callback that prints the contents of the post meta box.
* @param 'normal'|'side'|'additional' $context Optional. Context/position of the post meta box (normal, side, additional).
* @param 'core'|'default'|'high'|'low' $priority Optional. Order of the post meta box for the $context position (high, default, low).
* @param mixed[]|null $callback_args Optional. Additional data for the callback function (e.g. useful when in different class).
*/
protected function add_meta_box( string $id, string $title, callable $callback, string $context = 'normal', string $priority = 'default', ?array $callback_args = null ): void {
$this->has_meta_boxes = true;
add_meta_box( "tablepress_{$this->action}-{$id}", $title, $callback, null, $context, $priority, $callback_args );
}
/**
* Render all text boxes for the given context.
*
* @since 1.0.0
*
* @param string $context Context (normal, side, additional, header, submit) for which registered text boxes shall be rendered.
*/
protected function do_text_boxes( string $context ): void {
if ( empty( $this->textboxes[ $context ] ) ) {
return;
}
foreach ( $this->textboxes[ $context ] as $box ) {
if ( $box['wrap'] ) {
echo "
\n";
}
}
}
/**
* Render all post meta boxes for the given context, if there are post meta boxes.
*
* @since 1.0.0
*
* @param string $context Context (normal, side, additional) for which registered post meta boxes shall be rendered.
*/
protected function do_meta_boxes( string $context ): void {
if ( $this->has_meta_boxes ) {
do_meta_boxes( get_current_screen(), $context, $this->data ); // @phpstan-ignore-line
}
}
/**
* Print hidden fields with nonces for post meta box AJAX handling, if there are post meta boxes on the screen.
*
* The check is possible as this function is executed after post meta boxes have to be registered.
*
* @since 1.0.0
*
* @param array $data Data for this screen.
* @param array $box Information about the text box.
*/
protected function default_nonce_fields( array $data, array $box ): void {
if ( ! $this->has_meta_boxes ) {
return;
}
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
echo "\n";
wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
echo "\n";
}
/**
* Print hidden field with a nonce for the screen's action, to be transmitted in HTTP requests.
*
* @since 1.0.0
*
* @param array $data Data for this screen.
* @param array $box Information about the text box.
*/
protected function action_nonce_field( array $data, array $box ): void {
wp_nonce_field( TablePress::nonce( $this->action ) );
echo "\n";
}
/**
* Print hidden field with the screen action.
*
* @since 1.0.0
*
* @param array $data Data for this screen.
* @param array $box Information about the text box.
*/
protected function action_field( array $data, array $box ): void {
echo "action}\" />\n";
}
/**
* Render the current view.
*
* @since 1.0.0
*/
public function render(): void {
?>
$data Data for this screen.
* @param array $box Information about the text box.
*/
public function textbox_no_javascript( array $data, array $box ): void {
?>
the instructions on how to enable JavaScript in your browser.', 'tablepress' ); ?>
'list' ) ) . '">' . __( 'Back to the List of Tables', 'tablepress' ) . ''; ?>
$data Data for this screen.
* @param array $box Information about the text box.
*/
protected function textbox_submit_button( array $data, array $box ): void {
$caption = $data['submit_button_caption'] ?? __( 'Save Changes', 'tablepress' );
?>
wp_pointers ) ) {
return;
}
// Get dismissed pointers.
$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
$pointers_on_page = false;
foreach ( array_diff( $this->wp_pointers, $dismissed ) as $pointer ) {
// Bind pointer print function.
add_action( "admin_footer-{$GLOBALS['hook_suffix']}", array( $this, 'wp_pointer_' . $pointer ) ); // @phpstan-ignore-line
$pointers_on_page = true;
}
if ( $pointers_on_page ) {
wp_enqueue_style( 'wp-pointer' );
wp_enqueue_script( 'wp-pointer' );
}
}
} // class TablePress_View