PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / trunk
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts vtrunk
2.7.6 2.7.5 2.7.4 trunk 1.3 2.0.4 2.0.6 2.1.91 2.2.4 2.2.7 2.2.9 2.3.1 2.3.10 2.4.10 2.4.2 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.6.0 2.6.1 2.7.0 2.7.1 All 27 releases
insert-php / admin / includes / class.snippets.table.php

class.snippets.table.php in Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts trunk, at admin/includes/class.snippets.table.php

635 lines 25.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This class is implemented page: snippet table
4 *
5 * @since 1.0.0
6 * @package core
7 */
8
9 // Exit if accessed directly
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit;
12 }
13
14 if ( ! class_exists( 'WP_List_Table' ) ) {
15 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
16 }
17
18 /************************** CREATE A PACKAGE CLASS *****************************
19 * ******************************************************************************
20 * Create a new list table package that extends the core WP_List_Table class.
21 * WP_List_Table contains most of the framework for generating the table, but we
22 * need to define and override some methods so that our data can be displayed
23 * exactly the way we need it to be.
24 *
25 * To display this example on a page, you will first need to instantiate the class,
26 * then call $yourInstance->prepare_items() to handle any data manipulation, then
27 * finally call $yourInstance->display() to render the table to the page.
28 *
29 * Our theme for this list table is going to be movies.
30 */
31 class WINP_Snippet_Library_Table extends WP_List_Table {
32
33 /** ************************************************************************
34 * Normally we would be querying data from a database and manipulating that
35 * for use in your list table. For this example, we're going to simplify it
36 * slightly and create a pre-built array. Think of this as the data that might
37 * be returned by $wpdb->query()
38 *
39 * In a real-world scenario, you would make your own custom query inside
40 * this class' prepare_items() method.
41 *
42 * @var array
43 **************************************************************************/
44 var $example_data = [];
45
46 /**
47 * Is modal window
48 *
49 * @var bool
50 */
51 private $modal;
52
53 /**
54 * Если true, то выводить общие сниппеты без привязки к пользователю
55 *
56 * @var bool
57 */
58 private $common;
59
60 /**
61 * @var array
62 *
63 * Array contains slug columns that you want hidden
64 */
65 private $hidden_columns = [
66 'id',
67 ];
68
69 /**
70 * @var integer
71 */
72 private $per_page = 10;
73
74 /** ************************************************************************
75 * REQUIRED. Set up a constructor that references the parent constructor. We
76 * use the parent reference to set some default configs.
77 ***************************************************************************/
78 /**
79 * WINP_Snippet_Library_Table constructor.
80 *
81 * @param bool $modal
82 */
83 function __construct( $modal = false ) {
84 global $status, $page;
85 add_thickbox();
86 $this->modal = $modal;
87 $this->common = true;
88
89 // Set parent defaults
90 parent::__construct(
91 [
92 'singular' => 'snippet', // singular name of the listed records
93 'plural' => 'snippets', // plural name of the listed records
94 'ajax' => true, // does this table support ajax?
95 ]
96 );
97 }
98
99 /** ************************************************************************
100 * Recommended. This method is called when the parent class can't find a method
101 * specifically build for a given column. Generally, it's recommended to include
102 * one method for each column you want to render, keeping your package class
103 * neat and organized. For example, if the class needs to process a column
104 * named 'title', it would first see if a method named $this->column_title()
105 * exists - if it does, that method will be used. If it doesn't, this one will
106 * be used. Generally, you should try to use custom column methods as much as
107 * possible.
108 *
109 * Since we have defined a column_title() method later on, this method doesn't
110 * need to concern itself with any column with a name of 'title'. Instead, it
111 * needs to handle everything else.
112 *
113 * For more detailed insight into how columns are handled, take a look at
114 * WP_List_Table::single_row_columns()
115 *
116 * @param array $item A singular item (one full row's worth of data)
117 * @param string $column_name The name/slug of the column to be processed
118 *
119 * @return string Text or HTML to be placed inside the column <td>
120 **************************************************************************/
121 public function column_default( $item, $column_name ) {
122 switch ( $column_name ) {
123 case 'type':
124 $class = 'wbcr-inp-type-' . esc_attr( $item[ $column_name ] );
125 $type = 'universal' == $item[ $column_name ] ? 'uni' : esc_attr( $item[ $column_name ] );
126
127 return '<div class="wbcr-inp-snippet-type-label ' . $class . '">' . esc_html( $type ) . '</div>';
128 case 'desc':
129 $desc = strlen( $item[ $column_name ] ) > 500 ? substr( $item[ $column_name ], 0, 500 ) : $item[ $column_name ];
130
131 return '<div class="wbcr-inp-snippet-description" title="' . esc_attr( $desc ) . '">' . esc_html( $desc ) . '</div>';
132 case 'preview':
133 case 'datetime':
134 case 'insert':
135 case 'delete':
136 return $item[ $column_name ];
137 default:
138 return print_r( $item, true ); // Show the whole array for troubleshooting purposes
139 }
140 }
141
142 /** ************************************************************************
143 * Recommended. This is a custom column method and is responsible for what
144 * is rendered in any column with a name/slug of 'title'. Every time the class
145 * needs to render a column, it first looks for a method named
146 * column_{$column_title} - if it exists, that method is run. If it doesn't
147 * exist, column_default() is called instead.
148 *
149 * This example also illustrates how to implement rollover actions. Actions
150 * should be an associative array formatted as 'slug'=>'link html' - and you
151 * will need to generate the URLs yourself. You could even ensure the links
152 *
153 * @param array $item A singular item (one full row's worth of data)
154 *
155 * @return string Text to be placed inside the column <td> (movie title only)
156 * *************************************************************************@see WP_List_Table::::single_row_columns()
157 */
158 public function column_title( $item ) {
159 // Build row actions
160 $actions = [/*
161 'edit' => sprintf( '<a href="?page=%s&action=%s&movie=%s">Edit</a>', $_REQUEST['page'], 'edit', $item['ID'] ),
162 'delete' => sprintf( '<a href="?page=%s&action=%s&movie=%s">Delete</a>', $_REQUEST['page'], 'delete', $item['ID'] ),*/
163 ];
164
165 $url = admin_url() . 'post-new.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&winp_item=' . $item['type'] . '&snippet_id=' . $item['ID'] . ( $this->common ? '&common=1' : '' );
166
167 // Add premium badge if snippet is locked.
168 $premium_badge = '';
169 $is_locked = ! empty( $item['is_premium_locked'] );
170
171 if ( $is_locked ) {
172 $premium_badge = ' <span style="display:inline-block;background:#6366f1;color:#fff;font-size:11px;padding:2px 8px;border-radius:3px;font-weight:600;margin-left:6px;">PRO</span>';
173 }
174
175 // Return the title contents - no link for locked premium snippets.
176 if ( $is_locked ) {
177 return sprintf( '<b>%1$s</b>%2$s%3$s', /*$1%s*/ esc_html( $item['title'] ), /*$2%s*/ $premium_badge, /*$3%s*/ $this->row_actions( $actions ) );
178 }
179
180 return sprintf( '<a href="%1$s"><b>%2$s</b></a>%3$s%4$s', /*$1%s*/ esc_url( $url ), /*$2%s*/ esc_html( $item['title'] ), /*$3%s*/ $premium_badge, /*$4%s*/ $this->row_actions( $actions ) );
181 }
182
183 /** ************************************************************************
184 * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column
185 * is given special treatment when columns are processed. It ALWAYS needs to
186 * have it's own method.
187 *
188 * @param array $item A singular item (one full row's worth of data)
189 *
190 * @return string Text to be placed inside the column <td> (movie title only)
191 * *************************************************************************@see WP_List_Table::::single_row_columns()
192 */
193 public function column_cb( $item ) {
194 return sprintf(
195 '<input type="checkbox" name="%1$s[]" value="%2$s" />', /*$1%s*/
196 esc_attr( $this->_args['singular'] ), // Let's simply repurpose the table's singular label ("movie")
197 /*$2%s*/ esc_attr( $item['ID'] ) // The value of the checkbox should be the record's id
198 );
199 }
200
201 /** ************************************************************************
202 * REQUIRED! This method dictates the table's columns and titles. This should
203 * return an array where the key is the column slug (and class) and the value
204 * is the column's title text. If you need a checkbox for bulk actions, refer
205 * to the $columns array below.
206 *
207 * The 'cb' column is treated differently than the rest. If including a checkbox
208 * column in your table you must create a column_cb() method. If you don't need
209 * bulk actions or checkboxes, simply leave the 'cb' entry out of your array.
210 *
211 * @return array An associative array containing column information: 'slugs'=>'Visible Titles'
212 * *************************************************************************@see WP_List_Table::::single_row_columns()
213 */
214 public function get_columns() {
215 $columns = [// 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
216 ];
217 $columns['type'] = __( 'Type', 'insert-php' );
218 $columns['title'] = __( 'Title', 'insert-php' );
219
220 if ( ! $this->modal && $this->common ) {
221 $columns['preview'] = __( 'Preview', 'insert-php' );
222 }
223
224 $columns['desc'] = __( 'Description', 'insert-php' );
225 $columns['datetime'] = __( 'Date', 'insert-php' );
226 $columns['insert'] = __( 'Insert', 'insert-php' );
227
228 if ( ! $this->modal && ! $this->common ) {
229 $columns['delete'] = __( 'Delete', 'insert-php' );
230 }
231
232 return $columns;
233 }
234
235 /** ************************************************************************
236 * Optional. If you want one or more columns to be sortable (ASC/DESC toggle),
237 * you will need to register it here. This should return an array where the
238 * key is the column that needs to be sortable, and the value is db column to
239 * sort by. Often, the key and value will be the same, but this is not always
240 * the case (as the value is a column name from the database, not the list table).
241 *
242 * This method merely defines which columns should be sortable and makes them
243 * clickable - it does not handle the actual sorting. You still need to detect
244 * the ORDERBY and ORDER querystring variables within prepare_items() and sort
245 * your data accordingly (usually by modifying your query).
246 *
247 * @return array An associative array containing all the columns that should be sortable: 'slugs'=>array('data_values',bool)
248 **************************************************************************/
249 public function get_sortable_columns() {
250 $sortable_columns = [
251 'title' => [ 'title', false ], // true means it's already sorted
252 'type' => [ 'type', false ],
253 'datetime' => [ 'datetime', false ],
254 ];
255
256 return $sortable_columns;
257 }
258
259 /** ************************************************************************
260 * Optional. If you need to include bulk actions in your list table, this is
261 * the place to define them. Bulk actions are an associative array in the format
262 * 'slug'=>'Visible Title'
263 *
264 * If this method returns an empty value, no bulk action will be rendered. If
265 * you specify any bulk actions, the bulk actions box will be rendered with
266 * the table automatically on display().
267 *
268 * Also note that list tables are not automatically wrapped in <form> elements,
269 * so you will need to create those manually in order for bulk actions to function.
270 *
271 * @return array An associative array containing all the bulk actions: 'slugs'=>'Visible Titles'
272 **************************************************************************/
273 public function get_bulk_actions() {
274 $actions = [// 'sync' => __( 'Synchronization', 'insert-php' ),
275 ];
276
277 return $actions;
278 }
279
280 /** ************************************************************************
281 * Optional. You can handle your bulk actions anywhere or anyhow you prefer.
282 * For this example package, we will handle it in the class to keep things
283 * clean and organized.
284 *
285 * @see $this->prepare_items()
286 **************************************************************************/
287 public function process_bulk_action() {
288
289 // Detect when a bulk action is being triggered...
290 /*
291 if ( 'sync' === $this->current_action() ) {
292 wp_die( 'Synchronization' );
293 }*/
294 }
295
296 /**
297 * Возвращает id youtube видео
298 *
299 * @param $video_link - ссылка на видео
300 *
301 * @return bool|string - если id сниппета не найден, то вернёт false
302 */
303 private function get_video_id( $video_link ) {
304 // youtube regex
305 preg_match( '#([\/|\?|&]vi?[\/|=]|youtu\.be\/|embed\/)([a-zA-Z0-9_-]+)#', $video_link, $matches );
306
307 return ! empty( $matches ) ? end( $matches ) : false;
308 }
309
310 /**
311 * Get snippets data
312 *
313 * @return array
314 */
315 public function get_data() {
316 $data = [];
317 $saved_data = [];
318
319 $orderby = WINP_HTTP::request( 'orderby', 'datetime', true );
320 $order = WINP_HTTP::request( 'order', 'desc', true );
321 $paged = WINP_HTTP::request( 'paged', 1, 'intval' );
322
323 $order_tags = [
324 'title' => 'title',
325 'type' => 'type_id',
326 'datetime' => 'updated_at',
327 ];
328
329 $args = [
330 'per-page=' . $this->per_page,
331 'page=' . $paged,
332 'sort=' . ( 'asc' == $order ? '' : '-' ) . ( $order_tags[ $orderby ] ),
333 ];
334
335 $snippets = WINP_Plugin::app()->get_api_object()->get_all_snippets( $this->common, $args );
336
337 if ( ! empty( $snippets ) ) {
338 foreach ( (array) $snippets as $snippet ) {
339 // Check if snippet is premium and user doesn't have license.
340 $is_premium_locked = $this->common &&
341 isset( $snippet->is_premium ) &&
342 $snippet->is_premium &&
343 ! WINP_Plugin::app()->get_api_object()->is_key();
344
345 // Build Insert button - use different class for premium locked snippets.
346 if ( $is_premium_locked ) {
347 $insert_button = '<a class="wbcr-inp-premium-snippet-button button" href="javascript: void(0)" style="display:inline-flex;align-items:center;justify-content:center;"><span class="dashicons dashicons-plus"></span></a>';
348 } else {
349 $insert_button = '<a class="wbcr-inp-enable-snippet-button button" data-snippet="' . esc_attr( $snippet->id ) . '" data-common="' . ( $this->common ? 1 : 0 ) . '" href="javascript: void(0)" style="display:inline-flex;align-items:center;justify-content:center;"><span class="dashicons dashicons-plus"></span></a>';
350 }
351
352 $_data = [
353 'ID' => (int) $snippet->id,
354 'title' => esc_html( $snippet->title ),
355 'desc' => esc_html( $snippet->description ),
356 'type' => $snippet->type->title,
357 'datetime' => gmdate( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $snippet->updated_at ),
358 'insert' => $insert_button,
359 'delete' => '<a class="wbcr-inp-delete-snippet-button button" data-snippet="' . esc_attr( $snippet->id ) . '" href="javascript: void(0)"><span class="dashicons dashicons-no"></span></a>',
360 'is_premium_locked' => $is_premium_locked,
361 ];
362
363 if ( $this->common ) {
364 $_data['preview'] = '';
365 }
366
367 $video_id = $this->get_video_id( $snippet->video_link );
368
369 if ( $video_id ) {
370 $_data['preview'] = '<a class="thickbox" href="https://www.youtube.com/embed/' . esc_attr( $video_id ) . '?autoplay=1&rel=0&TB_iframe=true"><img src="' . WINP_PLUGIN_URL . '/admin/assets/img/video.png" class="winp-library-image-preview" data-videoid="' . esc_attr( $video_id ) . '" alt="' . __( 'Watch Tutorial Video', 'insert-php' ) . '"></a>';
371 }
372
373 $data[] = $_data;
374
375 $saved_data[ $snippet->id ] = [
376 'title' => esc_html( $snippet->title ),
377 'desc' => esc_html( $snippet->description ),
378 'type' => $snippet->type->slug,
379 'content' => $snippet->content,
380 'type_id' => (int) $snippet->type_id,
381 'scope' => $snippet->execute_everywhere ? 'evrywhere' : 'shortcode',
382 ];
383 }
384
385 update_user_meta( get_current_user_id(), 'wbcr_inp_current_snippets', $saved_data );
386 }
387
388 return $data;
389 }
390
391 /**
392 * Get total items for last query
393 *
394 * @return int
395 */
396 public function get_total_items() {
397 return WINP_Plugin::app()->get_api_object()->get_total_items();
398 }
399
400 /** ************************************************************************
401 * REQUIRED! This is where you prepare your data for display. This method will
402 * usually be used to query the database, sort and filter the data, and generally
403 * get it ready to be displayed. At a minimum, we should set $this->items and
404 * $this->set_pagination_args(), although the following properties and methods
405 * are frequently interacted with here...
406 *
407 * @param bool $common - если true, то выводить общие сниппеты без привязки к пользователю
408 *
409 * @global WPDB $wpdb
410 * @uses $this->_column_headers
411 * @uses $this->items
412 * @uses $this->get_columns()
413 * @uses $this->get_sortable_columns()
414 * @uses $this->get_pagenum()
415 * @uses $this->set_pagination_args()
416 * *************************************************************************/
417 public function prepare_items( $common = false ) {
418 /**
419 * First, lets decide how many records per page to show
420 */
421 $this->per_page = 10;
422
423 /**
424 * @param bool $common - если true, то выводить общие сниппеты без привязки к пользователю
425 */
426 $this->common = $common;
427
428 /**
429 * REQUIRED. Now we need to define our column headers. This includes a complete
430 * array of columns to be displayed (slugs & titles), a list of columns
431 * to keep hidden, and a list of columns that are sortable. Each of these
432 * can be defined in another method (as we've done here) before being
433 * used to build the value for our _column_headers property.
434 */
435 $columns = $this->get_columns();
436 $hidden = $this->hidden_columns;
437 $sortable = $this->get_sortable_columns();
438
439 /**
440 * REQUIRED. Finally, we build an array to be used by the class for column
441 * headers. The $this->_column_headers property takes an array which contains
442 * 3 other arrays. One for all columns, one for hidden columns, and one
443 * for sortable columns.
444 */
445 $this->_column_headers = [ $columns, $hidden, $sortable ];
446
447 /**
448 * Optional. You can handle your bulk actions however you see fit. In this
449 * case, we'll handle them within our package just to keep things clean.
450 */
451 $this->process_bulk_action();
452
453 /**
454 * Instead of querying a database, we're going to fetch the example data
455 * property we created for use in this plugin. This makes this example
456 * package slightly different than one you might build on your own. In
457 * this example, we'll be using array manipulation to sort and paginate
458 * our data. In a real-world implementation, you will probably want to
459 * use sort and pagination data to build a custom query instead, as you'll
460 * be able to use your precisely-queried data immediately.
461 */
462 $data = $this->get_data();
463
464 /**
465 * This checks for sorting input and sorts the data in our array accordingly.
466 *
467 * In a real-world situation involving a database, you would probably want
468 * to handle sorting by passing the 'orderby' and 'order' values directly
469 * to a custom query. The returned data will be pre-sorted, and this array
470 * sorting technique would be unnecessary.
471 *
472 * @param $a
473 * @param $b
474 *
475 * @return int
476 */ /*
477 function usort_reorder( $a, $b ) {
478 $orderby = ( ! empty( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : 'title'; // If no sort, default to title
479 $order = ( ! empty( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : 'asc'; // If no order, default to asc
480 $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // Determine sort order
481
482 return ( 'asc' === $order ) ? $result : - $result; // Send final sort direction to usort
483 }
484
485 usort( $data, 'usort_reorder' );*/
486
487 /***********************************************************************
488 * ---------------------------------------------------------------------
489 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
490 *
491 * In a real-world situation, this is where you would place your query.
492 *
493 * For information on making queries in WordPress, see this Codex entry:
494 * http://codex.wordpress.org/Class_Reference/wpdb
495 *
496 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
497 * ---------------------------------------------------------------------
498 */
499
500 /**
501 * REQUIRED for pagination. Let's figure out what page the user is currently
502 * looking at. We'll need this later, so you should always include it in
503 * your own package classes.
504 */ // $current_page = $this->get_current_page();
505
506 /**
507 * REQUIRED for pagination. Let's check how many items are in our data array.
508 * In real-world use, this would be the total number of items in your database,
509 * without filtering. We'll need this later, so you should always include it
510 * in your own package classes.
511 */
512 $total_items = $this->get_total_items();
513
514 /**
515 * The WP_List_Table class does not handle pagination for us, so we need
516 * to ensure that the data is trimmed to only the current page. We can use
517 * array_slice() to
518 */ // $data = array_slice( $data, ( ( $current_page - 1 ) * $this->per_page ), $this->per_page );
519
520 /**
521 * REQUIRED. Now we can add our *sorted* data to the items property, where
522 * it can be used by the rest of the class.
523 */
524 $this->items = $data;
525
526 /**
527 * REQUIRED. We also have to register our pagination options & calculations.
528 */
529 $this->set_pagination_args(
530 [
531 'total_items' => $total_items,
532 'per_page' => $this->per_page,
533 'total_pages' => ceil( $total_items / $this->per_page ),
534 'orderby' => WINP_HTTP::request( 'orderby', 'title', true ),
535 'order' => WINP_HTTP::request( 'order', 'asc', true ),
536 ]
537 );
538 }
539
540 /**
541 * @Override of display method
542 */
543 public function display() {
544 /**
545 * Adds a nonce field
546 */
547 wp_nonce_field( 'winp-ajax-custom-list-nonce', 'winp_ajax_custom_list_nonce' );
548
549 if ( ! empty( $this->items ) && ! $this->common ) {
550 foreach ( $this->items as $item ) {
551 wp_nonce_field( 'winp-ajax-snippet-delete-' . $item['ID'], 'winp_ajax_snippet_delete_' . $item['ID'] );
552 }
553 }
554
555 /**
556 * Adds field order and orderby
557 */
558 echo '<input type="hidden" id="order" name="order" value="' . $this->_pagination_args['order'] . '" />';
559 echo '<input type="hidden" id="orderby" name="orderby" value="' . $this->_pagination_args['orderby'] . '" />';
560 parent::display();
561
562 // Add premium upsell modal.
563 if ( $this->common ) {
564 ?>
565 <div id="winp-premium-snippet-modal" style="display:none;">
566 <div style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.7);z-index:100000;display:flex;align-items:center;justify-content:center;">
567 <div style="background:#fff;border-radius:8px;padding:0;max-width:500px;width:90%;position:relative;">
568 <button id="winp-modal-close" style="position:absolute;top:15px;right:15px;background:none;border:none;font-size:24px;cursor:pointer;color:#666;line-height:1;padding:0;width:30px;height:30px;">&times;</button>
569 <div class="winp-upsell-container" style="margin:0;padding:0;">
570 <div class="winp-upsell-card" style="box-shadow:none;">
571 <div class="winp-upsell-icon">
572 <span class="dashicons dashicons-star-filled"></span>
573 </div>
574 <div class="winp-upsell-title">
575 <?php esc_html_e( 'Premium Snippet', 'insert-php' ); ?>
576 </div>
577 <p class="winp-upsell-badge">
578 <?php esc_html_e( 'Pro feature', 'insert-php' ); ?>
579 </p>
580 <p class="winp-upsell-description">
581 <?php esc_html_e( 'This is a premium snippet available only in the Pro version. Upgrade to unlock access to all premium code snippets and advanced features.', 'insert-php' ); ?>
582 </p>
583 <a href="<?php echo esc_url( tsdk_utmify( WINP_UPGRADE, 'snippet_library', 'premium_snippet_upsell' ) ); ?>" class="button button-primary button-large winp-upsell-button" target="_blank">
584 <?php esc_html_e( 'Upgrade to Pro', 'insert-php' ); ?>
585 </a>
586 </div>
587 </div>
588 </div>
589 </div>
590 </div>
591 <?php
592 }
593 }
594
595 /**
596 * @Override ajax_response method
597 */
598 public function ajax_response() {
599
600 $this->prepare_items();
601 extract( $this->_args );
602 extract( $this->_pagination_args, EXTR_SKIP );
603 ob_start();
604 $no_placeholder = WINP_HTTP::request( 'no_placeholder', '' );
605 if ( ! empty( $no_placeholder ) ) {
606 $this->display_rows();
607 } else {
608 $this->display_rows_or_placeholder();
609 }
610 $rows = ob_get_clean();
611 ob_start();
612 $this->print_column_headers();
613 $headers = ob_get_clean();
614 ob_start();
615 $this->pagination( 'top' );
616 $pagination_top = ob_get_clean();
617 ob_start();
618 $this->pagination( 'bottom' );
619 $pagination_bottom = ob_get_clean();
620 $response = [ 'rows' => $rows ];
621 $response['pagination']['top'] = $pagination_top;
622 $response['pagination']['bottom'] = $pagination_bottom;
623 $response['column_headers'] = $headers;
624 if ( isset( $total_items ) ) {
625 /* translators: %s: Number of items */
626 $response['total_items_i18n'] = sprintf( _n( '%s item', '%s items', $total_items, 'insert-php' ), number_format_i18n( $total_items ) );
627 }
628 if ( isset( $total_pages ) ) {
629 $response['total_pages'] = $total_pages;
630 $response['total_pages_i18n'] = number_format_i18n( $total_pages );
631 }
632 die( json_encode( $response ) );
633 }
634 }
635