PluginProbe
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts / 2.3.1
Woody Code Snippets – Insert PHP, CSS, JS, and Header/Footer Scripts v2.3.1
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
insert-php / admin / includes / class.snippets.table.php

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

572 lines 22.8 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 * @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 add_thickbox();
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 'preview':
135 case 'datetime':
136 case 'insert':
137 case 'delete':
138 return $item[ $column_name ];
139 default:
140 return print_r( $item, true ); // Show the whole array for troubleshooting purposes
141 }
142 }
143
144 /** ************************************************************************
145 * Recommended. This is a custom column method and is responsible for what
146 * is rendered in any column with a name/slug of 'title'. Every time the class
147 * needs to render a column, it first looks for a method named
148 * column_{$column_title} - if it exists, that method is run. If it doesn't
149 * exist, column_default() is called instead.
150 *
151 * This example also illustrates how to implement rollover actions. Actions
152 * should be an associative array formatted as 'slug'=>'link html' - and you
153 * will need to generate the URLs yourself. You could even ensure the links
154 *
155 *
156 * @param array $item A singular item (one full row's worth of data)
157 *
158 * @return string Text to be placed inside the column <td> (movie title only)
159 **************************************************************************@see WP_List_Table::::single_row_columns()
160 */
161 public function column_title( $item ) {
162 //Build row actions
163 $actions = [/*'edit' => sprintf( '<a href="?page=%s&action=%s&movie=%s">Edit</a>', $_REQUEST['page'], 'edit', $item['ID'] ),
164 'delete' => sprintf( '<a href="?page=%s&action=%s&movie=%s">Delete</a>', $_REQUEST['page'], 'delete', $item['ID'] ),*/
165 ];
166
167 $url = admin_url() . 'post-new.php?post_type=' . WINP_SNIPPETS_POST_TYPE . '&winp_item=' . $item['type'] . '&snippet_id=' . $item['ID'] . ( $this->common ? '&common=1' : '' );
168
169 //Return the title contents
170 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 ) );
171 }
172
173 /** ************************************************************************
174 * REQUIRED if displaying checkboxes or using bulk actions! The 'cb' column
175 * is given special treatment when columns are processed. It ALWAYS needs to
176 * have it's own method.
177 *
178 * @param array $item A singular item (one full row's worth of data)
179 *
180 * @return string Text to be placed inside the column <td> (movie title only)
181 **************************************************************************@see WP_List_Table::::single_row_columns()
182 */
183 public function column_cb( $item ) {
184 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")
185 /*$2%s*/ esc_attr( $item['ID'] ) //The value of the checkbox should be the record's id
186 );
187 }
188
189 /** ************************************************************************
190 * REQUIRED! This method dictates the table's columns and titles. This should
191 * return an array where the key is the column slug (and class) and the value
192 * is the column's title text. If you need a checkbox for bulk actions, refer
193 * to the $columns array below.
194 *
195 * The 'cb' column is treated differently than the rest. If including a checkbox
196 * column in your table you must create a column_cb() method. If you don't need
197 * bulk actions or checkboxes, simply leave the 'cb' entry out of your array.
198 *
199 * @return array An associative array containing column information: 'slugs'=>'Visible Titles'
200 **************************************************************************@see WP_List_Table::::single_row_columns()
201 */
202 public function get_columns() {
203 $columns = [// 'cb' => '<input type="checkbox" />', //Render a checkbox instead of text
204 ];
205 $columns['type'] = __( 'Type', 'insert-php' );
206 $columns['title'] = __( 'Title', 'insert-php' );
207
208 if ( ! $this->modal && $this->common ) {
209 $columns['preview'] = __( 'Preview', 'insert-php' );
210 }
211
212 $columns['desc'] = __( 'Description', 'insert-php' );
213 $columns['datetime'] = __( 'Date', 'insert-php' );
214 $columns['insert'] = __( 'Insert', 'insert-php' );
215
216 if ( ! $this->modal && ! $this->common ) {
217 $columns['delete'] = __( 'Delete', 'insert-php' );
218 }
219
220 return $columns;
221 }
222
223 /** ************************************************************************
224 * Optional. If you want one or more columns to be sortable (ASC/DESC toggle),
225 * you will need to register it here. This should return an array where the
226 * key is the column that needs to be sortable, and the value is db column to
227 * sort by. Often, the key and value will be the same, but this is not always
228 * the case (as the value is a column name from the database, not the list table).
229 *
230 * This method merely defines which columns should be sortable and makes them
231 * clickable - it does not handle the actual sorting. You still need to detect
232 * the ORDERBY and ORDER querystring variables within prepare_items() and sort
233 * your data accordingly (usually by modifying your query).
234 *
235 * @return array An associative array containing all the columns that should be sortable: 'slugs'=>array('data_values',bool)
236 **************************************************************************/
237 public function get_sortable_columns() {
238 $sortable_columns = [
239 'title' => [ 'title', false ], //true means it's already sorted
240 'type' => [ 'type', false ],
241 'datetime' => [ 'datetime', false ],
242 ];
243
244 return $sortable_columns;
245 }
246
247 /** ************************************************************************
248 * Optional. If you need to include bulk actions in your list table, this is
249 * the place to define them. Bulk actions are an associative array in the format
250 * 'slug'=>'Visible Title'
251 *
252 * If this method returns an empty value, no bulk action will be rendered. If
253 * you specify any bulk actions, the bulk actions box will be rendered with
254 * the table automatically on display().
255 *
256 * Also note that list tables are not automatically wrapped in <form> elements,
257 * so you will need to create those manually in order for bulk actions to function.
258 *
259 * @return array An associative array containing all the bulk actions: 'slugs'=>'Visible Titles'
260 **************************************************************************/
261 public function get_bulk_actions() {
262 $actions = [//'sync' => __( 'Synchronization', 'insert-php' ),
263 ];
264
265 return $actions;
266 }
267
268 /** ************************************************************************
269 * Optional. You can handle your bulk actions anywhere or anyhow you prefer.
270 * For this example package, we will handle it in the class to keep things
271 * clean and organized.
272 *
273 * @see $this->prepare_items()
274 **************************************************************************/
275 public function process_bulk_action() {
276
277 //Detect when a bulk action is being triggered...
278 /*if ( 'sync' === $this->current_action() ) {
279 wp_die( 'Synchronization' );
280 }*/
281 }
282
283 /**
284 * Возвращает id youtube видео
285 *
286 * @param $video_link - ссылка на видео
287 *
288 * @return bool|string - если id сниппета не найден, то вернёт false
289 */
290 private function get_video_id( $video_link ) {
291 // youtube regex
292 preg_match( "#([\/|\?|&]vi?[\/|=]|youtu\.be\/|embed\/)([a-zA-Z0-9_-]+)#", $video_link, $matches );
293
294 return ! empty( $matches ) ? end( $matches ) : false;
295 }
296
297 /**
298 * Get snippets data
299 *
300 * @return array
301 */
302 public function get_data() {
303 $data = [];
304 $saved_data = [];
305
306 $orderby = WINP_Plugin::app()->request->request( 'orderby', 'datetime', true );
307 $order = WINP_Plugin::app()->request->request( 'order', 'desc', true );
308 $paged = WINP_Plugin::app()->request->request( 'paged', 1, 'intval' );
309
310 $order_tags = [
311 'title' => 'title',
312 'type' => 'type_id',
313 'datetime' => 'updated_at',
314 ];
315
316 $args = [
317 'per-page=' . $this->per_page,
318 'page=' . $paged,
319 'sort=' . ( 'asc' == $order ? '' : '-' ) . ( $order_tags[ $orderby ] ),
320 ];
321
322 $snippets = WINP_Plugin::app()->get_api_object()->get_all_snippets( $this->common, $args );
323
324 if ( ! empty( $snippets ) ) {
325 foreach ( (array) $snippets as $snippet ) {
326 $_data = [
327 'ID' => (int) $snippet->id,
328 'title' => esc_html( $snippet->title ),
329 'desc' => esc_html( $snippet->description ),
330 'type' => $snippet->type->title,
331 'datetime' => date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $snippet->updated_at ),
332 'insert' => '<a class="wbcr-inp-enable-snippet-button button" data-snippet="' . esc_attr( $snippet->id ) . '" data-common="' . ( $this->common ? 1 : 0 ) . '" href="javascript: void(0)"><span class="dashicons dashicons-plus"></span></a>',
333 '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>',
334 ];
335
336 if ( $this->common ) {
337 $_data['preview'] = '';
338 }
339
340 $video_id = $this->get_video_id( $snippet->video_link );
341
342 if ( $video_id ) {
343 $_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="' . __( 'View the video', 'insert-php' ) . '">' . '</a>';
344 }
345
346 $data[] = $_data;
347
348 $saved_data[ $snippet->id ] = [
349 'title' => esc_html( $snippet->title ),
350 'desc' => esc_html( $snippet->description ),
351 'type' => $snippet->type->slug,
352 'content' => $snippet->content,
353 'type_id' => (int) $snippet->type_id,
354 'scope' => $snippet->execute_everywhere ? 'evrywhere' : 'shortcode',
355 ];
356 }
357
358 update_user_meta( get_current_user_id(), WINP_Plugin::app()->getPrefix() . 'current_snippets', $saved_data );
359 }
360
361 return $data;
362 }
363
364 /**
365 * Get total items for last query
366 *
367 * @return int
368 */
369 public function get_total_items() {
370 return WINP_Plugin::app()->get_api_object()->get_total_items();
371 }
372
373 /** ************************************************************************
374 * REQUIRED! This is where you prepare your data for display. This method will
375 * usually be used to query the database, sort and filter the data, and generally
376 * get it ready to be displayed. At a minimum, we should set $this->items and
377 * $this->set_pagination_args(), although the following properties and methods
378 * are frequently interacted with here...
379 *
380 * @param bool $common - если true, то выводить общие сниппеты без привязки к пользователю
381 *
382 * @global WPDB $wpdb
383 * @uses $this->_column_headers
384 * @uses $this->items
385 * @uses $this->get_columns()
386 * @uses $this->get_sortable_columns()
387 * @uses $this->get_pagenum()
388 * @uses $this->set_pagination_args()
389 * *************************************************************************/
390 public function prepare_items( $common = false ) {
391 /**
392 * First, lets decide how many records per page to show
393 */
394 $this->per_page = 10;
395
396 /**
397 * @param bool $common - если true, то выводить общие сниппеты без привязки к пользователю
398 */
399 $this->common = $common;
400
401 /**
402 * REQUIRED. Now we need to define our column headers. This includes a complete
403 * array of columns to be displayed (slugs & titles), a list of columns
404 * to keep hidden, and a list of columns that are sortable. Each of these
405 * can be defined in another method (as we've done here) before being
406 * used to build the value for our _column_headers property.
407 */
408 $columns = $this->get_columns();
409 $hidden = $this->hidden_columns;
410 $sortable = $this->get_sortable_columns();
411
412 /**
413 * REQUIRED. Finally, we build an array to be used by the class for column
414 * headers. The $this->_column_headers property takes an array which contains
415 * 3 other arrays. One for all columns, one for hidden columns, and one
416 * for sortable columns.
417 */
418 $this->_column_headers = [ $columns, $hidden, $sortable ];
419
420 /**
421 * Optional. You can handle your bulk actions however you see fit. In this
422 * case, we'll handle them within our package just to keep things clean.
423 */
424 $this->process_bulk_action();
425
426 /**
427 * Instead of querying a database, we're going to fetch the example data
428 * property we created for use in this plugin. This makes this example
429 * package slightly different than one you might build on your own. In
430 * this example, we'll be using array manipulation to sort and paginate
431 * our data. In a real-world implementation, you will probably want to
432 * use sort and pagination data to build a custom query instead, as you'll
433 * be able to use your precisely-queried data immediately.
434 */
435 $data = $this->get_data();
436
437 /**
438 * This checks for sorting input and sorts the data in our array accordingly.
439 *
440 * In a real-world situation involving a database, you would probably want
441 * to handle sorting by passing the 'orderby' and 'order' values directly
442 * to a custom query. The returned data will be pre-sorted, and this array
443 * sorting technique would be unnecessary.
444 *
445 * @param $a
446 * @param $b
447 *
448 * @return int
449 */ /*function usort_reorder( $a, $b ) {
450 $orderby = ( ! empty( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : 'title'; // If no sort, default to title
451 $order = ( ! empty( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : 'asc'; // If no order, default to asc
452 $result = strcmp( $a[ $orderby ], $b[ $orderby ] ); // Determine sort order
453
454 return ( 'asc' === $order ) ? $result : - $result; // Send final sort direction to usort
455 }
456
457 usort( $data, 'usort_reorder' );*/
458
459 /***********************************************************************
460 * ---------------------------------------------------------------------
461 * vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
462 *
463 * In a real-world situation, this is where you would place your query.
464 *
465 * For information on making queries in WordPress, see this Codex entry:
466 * http://codex.wordpress.org/Class_Reference/wpdb
467 *
468 * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
469 * ---------------------------------------------------------------------
470 **********************************************************************/
471
472 /**
473 * REQUIRED for pagination. Let's figure out what page the user is currently
474 * looking at. We'll need this later, so you should always include it in
475 * your own package classes.
476 */ // $current_page = $this->get_current_page();
477
478 /**
479 * REQUIRED for pagination. Let's check how many items are in our data array.
480 * In real-world use, this would be the total number of items in your database,
481 * without filtering. We'll need this later, so you should always include it
482 * in your own package classes.
483 */
484 $total_items = $this->get_total_items();
485
486 /**
487 * The WP_List_Table class does not handle pagination for us, so we need
488 * to ensure that the data is trimmed to only the current page. We can use
489 * array_slice() to
490 */ // $data = array_slice( $data, ( ( $current_page - 1 ) * $this->per_page ), $this->per_page );
491
492 /**
493 * REQUIRED. Now we can add our *sorted* data to the items property, where
494 * it can be used by the rest of the class.
495 */
496 $this->items = $data;
497
498 /**
499 * REQUIRED. We also have to register our pagination options & calculations.
500 */
501 $this->set_pagination_args( [
502 'total_items' => $total_items,
503 'per_page' => $this->per_page,
504 'total_pages' => ceil( $total_items / $this->per_page ),
505 'orderby' => WINP_Plugin::app()->request->request( 'orderby', 'title', true ),
506 'order' => WINP_Plugin::app()->request->request( 'order', 'asc', true ),
507 ] );
508 }
509
510 /**
511 * @Override of display method
512 */
513 public function display() {
514 /**
515 * Adds a nonce field
516 */
517 wp_nonce_field( 'winp-ajax-custom-list-nonce', 'winp_ajax_custom_list_nonce' );
518
519 if ( ! empty( $this->items ) && ! $this->common ) {
520 foreach ( $this->items as $item ) {
521 wp_nonce_field( 'winp-ajax-snippet-delete-' . $item['ID'], 'winp_ajax_snippet_delete_' . $item['ID'] );
522 }
523 }
524
525 /**
526 * Adds field order and orderby
527 */
528 echo '<input type="hidden" id="order" name="order" value="' . $this->_pagination_args['order'] . '" />';
529 echo '<input type="hidden" id="orderby" name="orderby" value="' . $this->_pagination_args['orderby'] . '" />';
530 parent::display();
531 }
532
533 /**
534 * @Override ajax_response method
535 */
536 public function ajax_response() {
537
538 $this->prepare_items();
539 extract( $this->_args );
540 extract( $this->_pagination_args, EXTR_SKIP );
541 ob_start();
542 $no_placeholder = WINP_Plugin::app()->request->request( 'no_placeholder', '' );
543 if ( ! empty( $no_placeholder ) ) {
544 $this->display_rows();
545 } else {
546 $this->display_rows_or_placeholder();
547 }
548 $rows = ob_get_clean();
549 ob_start();
550 $this->print_column_headers();
551 $headers = ob_get_clean();
552 ob_start();
553 $this->pagination( 'top' );
554 $pagination_top = ob_get_clean();
555 ob_start();
556 $this->pagination( 'bottom' );
557 $pagination_bottom = ob_get_clean();
558 $response = [ 'rows' => $rows ];
559 $response['pagination']['top'] = $pagination_top;
560 $response['pagination']['bottom'] = $pagination_bottom;
561 $response['column_headers'] = $headers;
562 if ( isset( $total_items ) ) {
563 $response['total_items_i18n'] = sprintf( _n( '1 item', '%s items', $total_items ), number_format_i18n( $total_items ) );
564 }
565 if ( isset( $total_pages ) ) {
566 $response['total_pages'] = $total_pages;
567 $response['total_pages_i18n'] = number_format_i18n( $total_pages );
568 }
569 die( json_encode( $response ) );
570 }
571
572 }