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