PluginProbe
TablePress – Tables in WordPress made easy / 2.0.4
TablePress – Tables in WordPress made easy v2.0.4
3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 2.4.4 All 44 releases
tablepress / classes / class-view.php

class-view.php in TablePress – Tables in WordPress made easy 2.0.4, at classes/class-view.php

495 lines 16.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * TablePress Base View with members and methods for all views
4 *
5 * @package TablePress
6 * @subpackage Views
7 * @author Tobias Bäthge
8 * @since 1.0.0
9 */
10
11 // Prohibit direct script loading.
12 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13
14 /**
15 * TablePress Base View class
16 *
17 * @package TablePress
18 * @subpackage Views
19 * @author Tobias Bäthge
20 * @since 1.0.0
21 */
22 abstract class TablePress_View {
23
24 /**
25 * Data for the view.
26 *
27 * @since 1.0.0
28 * @var array
29 */
30 protected $data = array();
31
32 /**
33 * Number of screen columns for post boxes.
34 *
35 * @since 1.0.0
36 * @var int
37 */
38 protected $screen_columns = 0;
39
40 /**
41 * User action for this screen.
42 *
43 * @since 1.0.0
44 * @var string
45 */
46 protected $action = '';
47
48 /**
49 * Instance of the Admin Page Helper Class, with necessary functions.
50 *
51 * @since 1.0.0
52 * @var TablePress_Admin_Page
53 */
54 protected $admin_page;
55
56 /**
57 * List of text boxes (similar to post boxes, but just with text and without extra functionality).
58 *
59 * @since 1.0.0
60 * @var array
61 */
62 protected $textboxes = array();
63
64 /**
65 * List of messages that are to be displayed as boxes below the page title.
66 *
67 * @since 1.0.0
68 * @var array
69 */
70 protected $header_messages = array();
71
72 /**
73 * Whether there are post boxes registered for this screen,
74 * is automatically set to true, when a meta box is added.
75 *
76 * @since 1.0.0
77 * @var bool
78 */
79 protected $has_meta_boxes = false;
80
81 /**
82 * List of WP feature pointers for this view.
83 *
84 * @since 1.0.0
85 * @var array
86 */
87 protected $wp_pointers = array();
88
89 /**
90 * Initialize the View class, by setting the correct screen columns and adding help texts.
91 *
92 * @since 1.0.0
93 */
94 public function __construct() {
95 $screen = get_current_screen();
96 if ( 0 !== $this->screen_columns ) {
97 $screen->add_option( 'layout_columns', array( 'max' => $this->screen_columns ) );
98 }
99 // Enable two column layout.
100 add_filter( "get_user_option_screen_layout_{$screen->id}", array( $this, 'set_current_screen_layout_columns' ) );
101
102 $common_content = '<p>' . sprintf( __( 'More information about TablePress can be found on the <a href="%1$s">plugin website</a> or on its page in the <a href="%2$s">WordPress Plugin Directory</a>.', 'tablepress' ), 'https://tablepress.org/', 'https://wordpress.org/plugins/tablepress/' ) . '</p>';
103 $common_content .= '<p>' . sprintf( __( 'For technical information, please see the <a href="%s">Documentation</a>.', 'tablepress' ), 'https://tablepress.org/documentation/' ) . ' ' . sprintf( __( 'Common questions are answered in the <a href="%s">FAQ</a>.', 'tablepress' ), 'https://tablepress.org/faq/' ) . '</p>';
104
105 if ( tb_tp_fs()->is_free_plan() ) {
106 $common_content .= '<p>' . sprintf( __( '<a href="%1$s">Support</a> is provided through the <a href="%2$s">WordPress Support Forums</a>.', 'tablepress' ), 'https://tablepress.org/support/', 'https://wordpress.org/tags/tablepress' ) . ' '
107 . sprintf( __( 'Before asking for support, please carefully read the <a href="%s">Frequently Asked Questions</a>, where you will find answers to the most common questions, and search through the forums.', 'tablepress' ), 'https://tablepress.org/faq/' ) . '</p>';
108 $common_content .= '<p><strong>' . sprintf( __( 'More great features for you and your site’s visitors and priority email support are available with a Premium license plan of TablePress. <a href="%s">Go check them out!</a>', 'tablepress' ), 'https://tablepress.org/premium/' ) . '</strong></p>';
109 }
110
111 $screen->add_help_tab( array(
112 'id' => 'tablepress-help', // This should be unique for the screen.
113 'title' => __( 'TablePress Help', 'tablepress' ),
114 'content' => '<p>' . $this->help_tab_content() . '</p>' . $common_content,
115 ) );
116 // "Sidebar" in the help tab.
117 $screen->set_help_sidebar(
118 '<p><strong>' . __( 'For more information:', 'tablepress' ) . '</strong></p>'
119 . '<p><a href="https://tablepress.org/">TablePress Website</a></p>'
120 . '<p><a href="https://tablepress.org/faq/">TablePress FAQ</a></p>'
121 . '<p><a href="https://tablepress.org/documentation/">TablePress Documentation</a></p>'
122 . '<p><a href="https://tablepress.org/support/">TablePress Support</a></p>'
123 );
124 }
125
126 /**
127 * Change the value of the user option "screen_layout_{$screen->id}" through a filter.
128 *
129 * @since 1.0.0
130 *
131 * @param int|false $result Current value of the user option.
132 * @return int New value for the user option.
133 */
134 public function set_current_screen_layout_columns( $result ) {
135 if ( false === $result ) {
136 // The user option does not yet exist.
137 $result = $this->screen_columns;
138 } elseif ( $result > $this->screen_columns ) {
139 // 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).
140 $result = $this->screen_columns;
141 }
142 return $result;
143 }
144
145 /**
146 * Set up the view with data and do things that are necessary for all views.
147 *
148 * @since 1.0.0
149 *
150 * @param string $action Action for this view.
151 * @param array $data Data for this view.
152 */
153 public function setup( $action, array $data ) {
154 $this->action = $action;
155 $this->data = $data;
156
157 // Set page title.
158 $GLOBALS['title'] = sprintf( __( '%1$s &lsaquo; %2$s', 'tablepress' ), $this->data['view_actions'][ $this->action ]['page_title'], 'TablePress' );
159
160 // Admin page helpers, like script/style loading, could be moved to view.
161 $this->admin_page = TablePress::load_class( 'TablePress_Admin_Page', 'class-admin-page-helper.php', 'classes' );
162 $this->admin_page->enqueue_style( 'common' );
163 // RTL styles for the admin interface.
164 if ( is_rtl() ) {
165 $this->admin_page->enqueue_style( 'common-rtl', array( 'tablepress-common' ) );
166 }
167 $this->admin_page->enqueue_script( 'common', array( 'postbox' ) );
168
169 $this->admin_page->add_admin_footer_text();
170
171 // Initialize WP feature pointers for TablePress.
172 $this->_init_wp_pointers();
173
174 // Necessary fields for all views.
175 $this->add_text_box( 'default_nonce_fields', array( $this, 'default_nonce_fields' ), 'header', false );
176 $this->add_text_box( 'action_nonce_field', array( $this, 'action_nonce_field' ), 'header', false );
177 $this->add_text_box( 'action_field', array( $this, 'action_field' ), 'header', false );
178 }
179
180 /**
181 * Register a header message for the view.
182 *
183 * @since 1.0.0
184 *
185 * @param string $text Text for the header message.
186 * @param string $css_class Optional. Additional CSS class for the header message.
187 * @param string $title Optional. Text for the header title.
188 */
189 protected function add_header_message( $text, $css_class = 'notice-success', $title = '' ) {
190 if ( ! strpos( $css_class, 'not-dismissible' ) ) {
191 $css_class .= ' is-dismissible';
192 }
193 if ( '' !== $title ) {
194 $title = "<h3>{$title}</h3>";
195 }
196 // Wrap the message text in HTML <p> tags if it does not already start with one (potentially with attributes), indicating custom message HTML.
197 if ( '' !== $text && 0 !== strpos( $text, '<p' ) ) {
198 $text = "<p>{$text}</p>";
199 }
200 $this->header_messages[] = "<div class=\"notice {$css_class}\">{$title}{$text}</div>\n";
201 }
202
203 /**
204 * Process header action messages, i.e. check if a message should be added to the page.
205 *
206 * @since 1.0.0
207 *
208 * @param array $action_messages Action messages for the screen.
209 */
210 protected function process_action_messages( array $action_messages ) {
211 if ( $this->data['message'] && isset( $action_messages[ $this->data['message'] ] ) ) {
212 $class = ( 0 === strpos( $this->data['message'], 'error' ) ) ? 'notice-error' : 'notice-success';
213
214 if ( '' !== $this->data['error_details'] ) {
215 $this->data['error_details'] = '</p><p>' . sprintf( __( 'Error code: %s', 'tablepress' ), '<code>' . esc_html( $this->data['error_details'] ) . '</code>' );
216 }
217
218 $this->add_header_message( "<strong>{$action_messages[ $this->data['message'] ]}</strong>{$this->data['error_details']}", $class );
219 }
220 }
221
222 /**
223 * Register a text box for the view.
224 *
225 * @since 1.0.0
226 *
227 * @param string $id Unique HTML ID for the text box container (only visible with $wrap = true).
228 * @param callback $callback Callback that prints the contents of the text box.
229 * @param string $context Optional. Context/position of the text box (normal, side, additional, header, submit).
230 * @param bool $wrap Whether the content of the text box shall be wrapped in a <div> container.
231 */
232 protected function add_text_box( $id, $callback, $context = 'normal', $wrap = false ) {
233 if ( ! isset( $this->textboxes[ $context ] ) ) {
234 $this->textboxes[ $context ] = array();
235 }
236
237 $long_id = "tablepress_{$this->action}-{$id}";
238 $this->textboxes[ $context ][ $id ] = array(
239 'id' => $long_id,
240 'callback' => $callback,
241 'context' => $context,
242 'wrap' => $wrap,
243 );
244 }
245
246 /**
247 * Register a post meta box for the view, that is drag/droppable with WordPress functionality.
248 *
249 * @since 1.0.0
250 *
251 * @param string $id Unique ID for the meta box.
252 * @param string $title Title for the meta box.
253 * @param callback $callback Callback that prints the contents of the post meta box.
254 * @param string $context Optional. Context/position of the post meta box (normal, side, additional).
255 * @param string $priority Optional. Order of the post meta box for the $context position (high, default, low).
256 * @param array $callback_args Optional. Additional data for the callback function (e.g. useful when in different class).
257 */
258 protected function add_meta_box( $id, $title, $callback, $context = 'normal', $priority = 'default', $callback_args = null ) {
259 $this->has_meta_boxes = true;
260 add_meta_box( "tablepress_{$this->action}-{$id}", $title, $callback, null, $context, $priority, $callback_args );
261 }
262
263 /**
264 * Render all text boxes for the given context.
265 *
266 * @since 1.0.0
267 *
268 * @param string $context Context (normal, side, additional, header, submit) for which registered text boxes shall be rendered.
269 */
270 protected function do_text_boxes( $context ) {
271 if ( empty( $this->textboxes[ $context ] ) ) {
272 return;
273 }
274
275 foreach ( $this->textboxes[ $context ] as $box ) {
276 if ( $box['wrap'] ) {
277 echo "<div id=\"{$box['id']}\" class=\"textbox\">\n";
278 }
279 call_user_func( $box['callback'], $this->data, $box );
280 if ( $box['wrap'] ) {
281 echo "</div>\n";
282 }
283 }
284 }
285
286 /**
287 * Render all post meta boxes for the given context, if there are post meta boxes.
288 *
289 * @since 1.0.0
290 *
291 * @param string $context Context (normal, side, additional) for which registered post meta boxes shall be rendered.
292 */
293 protected function do_meta_boxes( $context ) {
294 if ( ! $this->has_meta_boxes ) {
295 return;
296 }
297 do_meta_boxes( null, $context, $this->data );
298 }
299
300 /**
301 * Print hidden fields with nonces for post meta box AJAX handling, if there are post meta boxes on the screen.
302 *
303 * The check is possible as this function is executed after post meta boxes have to be registered.
304 *
305 * @since 1.0.0
306 *
307 * @param array $data Data for this screen.
308 * @param array $box Information about the text box.
309 */
310 protected function default_nonce_fields( array $data, array $box ) {
311 if ( ! $this->has_meta_boxes ) {
312 return;
313 }
314 wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
315 echo "\n";
316 wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
317 echo "\n";
318 }
319
320 /**
321 * Print hidden field with a nonce for the screen's action, to be transmitted in HTTP requests.
322 *
323 * @since 1.0.0
324 *
325 * @param array $data Data for this screen.
326 * @param array $box Information about the text box.
327 */
328 protected function action_nonce_field( array $data, array $box ) {
329 wp_nonce_field( TablePress::nonce( $this->action ) );
330 echo "\n";
331 }
332
333 /**
334 * Print hidden field with the screen action.
335 *
336 * @since 1.0.0
337 *
338 * @param array $data Data for this screen.
339 * @param array $box Information about the text box.
340 */
341 protected function action_field( array $data, array $box ) {
342 echo "<input type=\"hidden\" name=\"action\" value=\"tablepress_{$this->action}\" />\n";
343 }
344
345 /**
346 * Render the current view.
347 *
348 * @since 1.0.0
349 */
350 public function render() {
351 ?>
352 <div id="tablepress-page" class="wrap">
353 <?php
354 $this->print_nav_tab_menu();
355 ?>
356 <div id="tablepress-body">
357 <hr class="wp-header-end" />
358 <?php
359 // Print all header messages.
360 foreach ( $this->header_messages as $message ) {
361 echo $message;
362 }
363 // "Import" screen has file upload.
364 $enctype = ( 'import' === $this->action ) ? ' enctype="multipart/form-data"' : '';
365 ?>
366 <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post"<?php echo $enctype; ?>>
367 <?php
368 $this->do_text_boxes( 'header' );
369 ?>
370 <div id="poststuff">
371 <div id="post-body" class="metabox-holder columns-<?php echo ( isset( $GLOBALS['screen_layout_columns'] ) && ( 2 === $GLOBALS['screen_layout_columns'] ) ) ? '2' : '1'; ?>">
372 <div id="postbox-container-2" class="postbox-container">
373 <?php
374 $this->do_text_boxes( 'normal' );
375 $this->do_meta_boxes( 'normal' );
376
377 $this->do_text_boxes( 'additional' );
378 $this->do_meta_boxes( 'additional' );
379
380 // Print all submit buttons.
381 $this->do_text_boxes( 'submit' );
382 ?>
383 </div>
384 <div id="postbox-container-1" class="postbox-container">
385 <?php
386 // Print all boxes in the sidebar.
387 $this->do_text_boxes( 'side' );
388 $this->do_meta_boxes( 'side' );
389 ?>
390 </div>
391 </div>
392 <br class="clear" />
393 </div>
394 </form>
395 </div>
396 </div>
397 <?php
398 }
399
400 /**
401 * Render the navigation menu with links to the possible actions, highlighting the current one.
402 *
403 * @since 1.0.0
404 */
405 protected function print_nav_tab_menu() {
406 ?>
407 <div id="tablepress-header" class="header">
408 <h1 class="name"><img src="<?php echo plugins_url( 'admin/img/tablepress-icon.png', TABLEPRESS__FILE__ ); ?>" class="tablepress-icon" alt="<?php esc_attr_e( 'TablePress plugin logo', 'tablepress' ); ?>" /><?php _e( 'TablePress', 'tablepress' ); ?><?php echo tb_tp_fs()->is_plan_or_trial( 'pro', true ) ? ' Pro' : ( tb_tp_fs()->is_plan_or_trial( 'max', true ) ? ' Max' : '' ); ?></h1>
409 <?php if ( tb_tp_fs()->is_free_plan() ) : ?>
410 <div class="buttons">
411 <a href="<?php echo 'https://tablepress.org/premium/'; ?>" class="tablepress-button">
412 <span><?php _e( 'Upgrade to Premium', 'tablepress' ); ?></span>
413 <span class="dashicons dashicons-arrow-right-alt"></span>
414 </a>
415 </div>
416 <?php endif; ?>
417 </div>
418 <nav id="tablepress-nav">
419 <ul class="nav-menu">
420 <?php
421 foreach ( $this->data['view_actions'] as $action => $entry ) {
422 if ( '' === $entry['nav_tab_title'] ) {
423 continue;
424 }
425 if ( ! current_user_can( $entry['required_cap'] ) ) {
426 continue;
427 }
428
429 $url = esc_url( TablePress::url( array( 'action' => $action ) ) );
430 $active = ( $action === $this->action ) ? ' active' : '';
431 $separator = ( 'export' === $action ) ? ' separator' : ''; // Make the "Export" entry a separator, for some spacing.
432 echo "<li class=\"nav-item\"><a id=\"tablepress-nav-item-{$action}\" class=\"nav-link{$active}{$separator}\" href=\"{$url}\">{$entry['nav_tab_title']}</a></li>";
433 }
434 ?>
435 </ul>
436 </nav>
437 <?php
438 }
439
440 /**
441 * Print a submit button (only done when function is used as a callback for a text box).
442 *
443 * @since 1.0.0
444 *
445 * @param array $data Data for this screen.
446 * @param array $box Information about the text box.
447 */
448 protected function textbox_submit_button( array $data, array $box ) {
449 $caption = isset( $data['submit_button_caption'] ) ? $data['submit_button_caption'] : __( 'Save Changes', 'tablepress' );
450 ?>
451 <p class="submit"><input type="submit" value="<?php echo esc_attr( $caption ); ?>" class="button button-primary button-large" /></p>
452 <?php
453 }
454
455 /**
456 * Return the content for the help tab for this screen.
457 *
458 * Has to be implemented for every view that is visible in the WP Dashboard!
459 *
460 * @since 1.0.0
461 */
462 protected function help_tab_content() {
463 // Has to be implemented for every view that is visible in the WP Dashboard!
464 return '';
465 }
466
467 /**
468 * Initialize the WP feature pointers for TablePress.
469 *
470 * @since 1.0.0
471 */
472 protected function _init_wp_pointers() {
473 // Check if there are WP pointers for this view.
474 if ( empty( $this->wp_pointers ) ) {
475 return;
476 }
477
478 // Get dismissed pointers.
479 $dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
480
481 $pointers_on_page = false;
482 foreach ( array_diff( $this->wp_pointers, $dismissed ) as $pointer ) {
483 // Bind pointer print function.
484 add_action( "admin_footer-{$GLOBALS['hook_suffix']}", array( $this, 'wp_pointer_' . $pointer ) );
485 $pointers_on_page = true;
486 }
487
488 if ( $pointers_on_page ) {
489 wp_enqueue_style( 'wp-pointer' );
490 wp_enqueue_script( 'wp-pointer' );
491 }
492 }
493
494 } // class TablePress_View
495