| 1 |
<?php |
| 2 |
|
| 3 |
/** |
| 4 |
* Suppress "error - 0 - No summary was found for this file" on phpdoc generation |
| 5 |
* |
| 6 |
* @package WPDataAccess\List_Table |
| 7 |
*/ |
| 8 |
namespace WPDataAccess\List_Table; |
| 9 |
|
| 10 |
use WPDataAccess\Connection\WPDADB; |
| 11 |
use WPDataAccess\Dashboard\WPDA_Dashboard; |
| 12 |
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist; |
| 13 |
use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Lists; |
| 14 |
use WPDataAccess\Data_Dictionary\WPDA_List_Columns; |
| 15 |
use WPDataAccess\Macro\WPDA_Macro; |
| 16 |
use WPDataAccess\Plugin_Table_Models\WPDA_CSV_Uploads_Model; |
| 17 |
use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model; |
| 18 |
use WPDataAccess\Utilities\WPDA_Import; |
| 19 |
use WPDataAccess\Utilities\WPDA_Message_Box; |
| 20 |
use WPDataAccess\Utilities\WPDA_Repository; |
| 21 |
use WPDataAccess\Wordpress_Original; |
| 22 |
use WPDataAccess\WPDA; |
| 23 |
use WPDataProjects\WPDP; |
| 24 |
use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model; |
| 25 |
use WPDataAccess\Plugin_Table_Models\WPDP_Project_Design_Table_Model; |
| 26 |
/** |
| 27 |
* Class WPDA_List_Table |
| 28 |
* |
| 29 |
* This class extends WordPress class WP_List_Table. The WordPress WP_List_Table is contained in the package as |
| 30 |
* advised by WordPress and might be updated in future releases. |
| 31 |
* |
| 32 |
* @author Peter Schulz |
| 33 |
* @since 1.0.0 |
| 34 |
*/ |
| 35 |
class WPDA_List_Table extends Wordpress_Original\WP_List_Table { |
| 36 |
/** |
| 37 |
* Base table for list of all tables |
| 38 |
*/ |
| 39 |
const LIST_BASE_TABLE = 'information_schema.tables'; |
| 40 |
|
| 41 |
/** |
| 42 |
* Default value bulk actions enabled |
| 43 |
*/ |
| 44 |
const DEFAULT_BULK_ACTIONS_ENABLED = true; |
| 45 |
|
| 46 |
/** |
| 47 |
* Default value bulk export enabled |
| 48 |
*/ |
| 49 |
const DEFAULT_BULK_EXPORT_ENABLED = true; |
| 50 |
|
| 51 |
/** |
| 52 |
* Default value bulk search enabled |
| 53 |
*/ |
| 54 |
const DEFAULT_SEARCH_BOX_ENABLED = true; |
| 55 |
|
| 56 |
/** |
| 57 |
* Table row number within the current response |
| 58 |
* |
| 59 |
* @var int |
| 60 |
*/ |
| 61 |
protected static $list_number = 0; |
| 62 |
|
| 63 |
/** |
| 64 |
* Menu slug of the current page |
| 65 |
* |
| 66 |
* @var string |
| 67 |
*/ |
| 68 |
protected $page; |
| 69 |
|
| 70 |
/** |
| 71 |
* Page title |
| 72 |
* |
| 73 |
* @var string |
| 74 |
*/ |
| 75 |
protected $title; |
| 76 |
|
| 77 |
/** |
| 78 |
* Page subtitle |
| 79 |
* |
| 80 |
* @var string |
| 81 |
*/ |
| 82 |
protected $subtitle = ''; |
| 83 |
|
| 84 |
protected $show_page_title = true; |
| 85 |
|
| 86 |
/** |
| 87 |
* Database schema name |
| 88 |
* |
| 89 |
* @var string |
| 90 |
*/ |
| 91 |
protected $schema_name = ''; |
| 92 |
|
| 93 |
/** |
| 94 |
* Database table name |
| 95 |
* |
| 96 |
* @var string |
| 97 |
*/ |
| 98 |
protected $table_name = ''; |
| 99 |
|
| 100 |
/** |
| 101 |
* Where clause |
| 102 |
* |
| 103 |
* @var string |
| 104 |
*/ |
| 105 |
protected $where = ''; |
| 106 |
|
| 107 |
/** |
| 108 |
* Order by clause |
| 109 |
* |
| 110 |
* @var string |
| 111 |
*/ |
| 112 |
protected $orderby = ''; |
| 113 |
|
| 114 |
/** |
| 115 |
* Columns in query |
| 116 |
* |
| 117 |
* @var array |
| 118 |
*/ |
| 119 |
protected $columns_queried; |
| 120 |
|
| 121 |
/** |
| 122 |
* Number of rows displayed in list box |
| 123 |
* |
| 124 |
* @var int |
| 125 |
*/ |
| 126 |
protected $items_per_page; |
| 127 |
|
| 128 |
/** |
| 129 |
* Page number |
| 130 |
* |
| 131 |
* @var int |
| 132 |
*/ |
| 133 |
protected $current_page = 1; |
| 134 |
|
| 135 |
/** |
| 136 |
* Add search box? |
| 137 |
* |
| 138 |
* @var bool |
| 139 |
*/ |
| 140 |
protected $search_box_enabled = self::DEFAULT_SEARCH_BOX_ENABLED; |
| 141 |
|
| 142 |
/** |
| 143 |
* Enable bulk actions? |
| 144 |
* |
| 145 |
* @var bool |
| 146 |
*/ |
| 147 |
protected $bulk_actions_enabled = self::DEFAULT_BULK_ACTIONS_ENABLED; |
| 148 |
|
| 149 |
/** |
| 150 |
* Enable exports? |
| 151 |
* |
| 152 |
* @var bool |
| 153 |
*/ |
| 154 |
protected $bulk_export_enabled = self::DEFAULT_BULK_EXPORT_ENABLED; |
| 155 |
|
| 156 |
/** |
| 157 |
* Show view link? |
| 158 |
* |
| 159 |
* @var string on|off |
| 160 |
*/ |
| 161 |
protected $show_view_link = null; |
| 162 |
|
| 163 |
/** |
| 164 |
* Allow inserts? |
| 165 |
* |
| 166 |
* @var string on|off |
| 167 |
*/ |
| 168 |
protected $allow_insert = null; |
| 169 |
|
| 170 |
/** |
| 171 |
* Allow updates? |
| 172 |
* |
| 173 |
* @var string on|off |
| 174 |
*/ |
| 175 |
protected $allow_update = null; |
| 176 |
|
| 177 |
/** |
| 178 |
* Allow deletes? |
| 179 |
* |
| 180 |
* @var string on|off |
| 181 |
*/ |
| 182 |
protected $allow_delete = null; |
| 183 |
|
| 184 |
/** |
| 185 |
* Hides tablenav |
| 186 |
* |
| 187 |
* @var bool |
| 188 |
*/ |
| 189 |
protected $hide_navigation = false; |
| 190 |
|
| 191 |
/** |
| 192 |
* Reference to column list |
| 193 |
* |
| 194 |
* @var WPDA_List_Columns |
| 195 |
*/ |
| 196 |
protected $wpda_list_columns; |
| 197 |
|
| 198 |
/** |
| 199 |
* Reference to dictionary object |
| 200 |
* |
| 201 |
* @var WPDA_Dictionary_Exist |
| 202 |
*/ |
| 203 |
protected $wpda_data_dictionary; |
| 204 |
|
| 205 |
/** |
| 206 |
* Column headers (labels) |
| 207 |
* |
| 208 |
* @var array |
| 209 |
*/ |
| 210 |
protected $column_headers; |
| 211 |
|
| 212 |
/** |
| 213 |
* Reference to import object |
| 214 |
* |
| 215 |
* @var WPDA_Import |
| 216 |
*/ |
| 217 |
protected $wpda_import = null; |
| 218 |
|
| 219 |
/** |
| 220 |
* Child tab clicked (used for parent child relationships only) |
| 221 |
* |
| 222 |
* @var null |
| 223 |
*/ |
| 224 |
protected $child_tab = ''; |
| 225 |
|
| 226 |
/** |
| 227 |
* Search string (entered by user or taken from cookie) |
| 228 |
* |
| 229 |
* @var null|string |
| 230 |
*/ |
| 231 |
protected $search_value = null; |
| 232 |
|
| 233 |
/** |
| 234 |
* Previous search string |
| 235 |
* |
| 236 |
* @var null|string |
| 237 |
*/ |
| 238 |
protected $search_value_old = null; |
| 239 |
|
| 240 |
/** |
| 241 |
* Page number item name (default 'page_number') |
| 242 |
* |
| 243 |
* The name can be changed for pages on multiple levels. This is needed to get back to the right page in |
| 244 |
* parent-child page. |
| 245 |
* |
| 246 |
* @var string |
| 247 |
*/ |
| 248 |
protected $page_number_item_name = 'page_number'; |
| 249 |
|
| 250 |
/** |
| 251 |
* Real page number |
| 252 |
* |
| 253 |
* @var null |
| 254 |
*/ |
| 255 |
protected $page_number_link = ''; |
| 256 |
|
| 257 |
/** |
| 258 |
* Page number text item |
| 259 |
* |
| 260 |
* @var null |
| 261 |
*/ |
| 262 |
protected $page_number_item = ''; |
| 263 |
|
| 264 |
/** |
| 265 |
* Make the default accessible to other classes |
| 266 |
*/ |
| 267 |
const SEARCH_ITEM_NAME_DEFAULT = 'wpda_s'; |
| 268 |
|
| 269 |
/** |
| 270 |
* Name of search item (WP default 's') |
| 271 |
* |
| 272 |
* @var string |
| 273 |
*/ |
| 274 |
protected $search_item_name = self::SEARCH_ITEM_NAME_DEFAULT; |
| 275 |
|
| 276 |
/** |
| 277 |
* Name of the column containing action links |
| 278 |
* |
| 279 |
* Default is the first column displayed |
| 280 |
* |
| 281 |
* @var string |
| 282 |
*/ |
| 283 |
protected $first_display_column = ''; |
| 284 |
|
| 285 |
/** |
| 286 |
* Table settings |
| 287 |
* |
| 288 |
* @var null|object |
| 289 |
*/ |
| 290 |
protected $wpda_table_settings = null; |
| 291 |
|
| 292 |
/** |
| 293 |
* Project table settings |
| 294 |
* |
| 295 |
* @var null|object |
| 296 |
*/ |
| 297 |
protected $wpda_project_table_settings = null; |
| 298 |
|
| 299 |
/** |
| 300 |
* Show help icon if help url is available |
| 301 |
* |
| 302 |
* @var null|string |
| 303 |
*/ |
| 304 |
protected $help_url = null; |
| 305 |
|
| 306 |
/** |
| 307 |
* Store columns in array with column name as index for fast access |
| 308 |
* |
| 309 |
* @var array |
| 310 |
*/ |
| 311 |
protected $columns_indexed = array(); |
| 312 |
|
| 313 |
/** |
| 314 |
* Variables used to store table estimate row count data |
| 315 |
* |
| 316 |
* @var string |
| 317 |
*/ |
| 318 |
protected $table_engine = ''; |
| 319 |
|
| 320 |
/** |
| 321 |
* Table rows |
| 322 |
* |
| 323 |
* @var mixed|string |
| 324 |
*/ |
| 325 |
protected $table_rows = ''; |
| 326 |
|
| 327 |
/** |
| 328 |
* Estimated row count |
| 329 |
* |
| 330 |
* @var array|int |
| 331 |
*/ |
| 332 |
protected $row_count_estimate = array(); |
| 333 |
|
| 334 |
/** |
| 335 |
* Project page id |
| 336 |
* |
| 337 |
* Helper to hide schema and table name in export links on web pages |
| 338 |
* |
| 339 |
* @var null |
| 340 |
*/ |
| 341 |
protected $pid = null; |
| 342 |
|
| 343 |
/** |
| 344 |
* Cache columns |
| 345 |
* |
| 346 |
* @var null |
| 347 |
*/ |
| 348 |
protected $wpda_cached_columns = null; |
| 349 |
|
| 350 |
/** |
| 351 |
* WPDA_List_Table constructor |
| 352 |
* |
| 353 |
* A table name must be provided in the constructor call. The table must be a valid MySQL database table to |
| 354 |
* which access (to the back-end) is granted. If no table name is provided, the table does not exist or access |
| 355 |
* to the back-end for the given table is not granted, processing is stopped. It makes no sense to continue |
| 356 |
* without a valid table. A check for table existence is performed to prevent SQL injection. |
| 357 |
* |
| 358 |
* There are two types of tables to build a list table on: |
| 359 |
* + List of tables in the WordPress database schema |
| 360 |
* + List of rows in a specific table |
| 361 |
* |
| 362 |
* To build a list of tables in the WordPress database schema, we query table 'information_schema.tables' |
| 363 |
* (which is in fact a view). This is the only query allowed outside the WordPress database schema. The |
| 364 |
* table/view name is stored in constant WPDA_List_Table::LIST_BASE_TABLE for validation purposes. |
| 365 |
* |
| 366 |
* A list of rows for a specific table is based on WordPress class WP_List_Table. |
| 367 |
* |
| 368 |
* WPDA_List_Table can be used to build list tables for views as well. View based list tables however, do not |
| 369 |
* support insert, update, delete, import and export actions. |
| 370 |
* |
| 371 |
* A table name is not the only thing we need to build a list table. We also need to have access to the |
| 372 |
* table columns. If no table columns are provided execution is stopped as well. |
| 373 |
* |
| 374 |
* @param array $args [ |
| 375 |
* |
| 376 |
* 'table_name' => (string) Database table name |
| 377 |
* |
| 378 |
* 'wpda_list_columns' => (object) Reference to a WPDA_List_Columns object |
| 379 |
* |
| 380 |
* 'singular' => (string) Singular object label |
| 381 |
* |
| 382 |
* 'plural' => (string) plural object label |
| 383 |
* |
| 384 |
* 'ajax' => (string) TRUE = list table support Ajax |
| 385 |
* |
| 386 |
* 'column_headers' => (array|string) Column headers |
| 387 |
* |
| 388 |
* 'title' => (string) Page title |
| 389 |
* |
| 390 |
* 'subtitle' => (string) Page subtitle |
| 391 |
* |
| 392 |
* 'bulk_export_enabled' => (boolean) |
| 393 |
* |
| 394 |
* 'search_box_enabled' => (boolean) |
| 395 |
* |
| 396 |
* 'bulk_actions_enabled' => (boolean) |
| 397 |
* |
| 398 |
* 'show_view_link' => (string) on|off |
| 399 |
* |
| 400 |
* 'allow_insert' => (string) on|off |
| 401 |
* |
| 402 |
* 'allow_update' => (string) on|off |
| 403 |
* |
| 404 |
* 'allow_delete' => (string) on|off |
| 405 |
* |
| 406 |
* 'allow_import' => (string) on|off |
| 407 |
* |
| 408 |
* 'hide_navigation' => (boolean) |
| 409 |
* |
| 410 |
* 'default_where' => (string) |
| 411 |
* |
| 412 |
* ] |
| 413 |
* @since 1.0.0 |
| 414 |
*/ |
| 415 |
public function __construct( $args = array() ) { |
| 416 |
global $wpdb; |
| 417 |
if ( !isset( $args['table_name'] ) ) { |
| 418 |
// Calling WPDA_List_Table without a table_name doesn't make sense. |
| 419 |
wp_die( __( 'ERROR: Wrong arguments [no table argument]', 'wp-data-access' ) ); |
| 420 |
} |
| 421 |
if ( !isset( $args['wpda_list_columns'] ) ) { |
| 422 |
// Calling WPDA_List_Table without a column list is not allowed. |
| 423 |
wp_die( __( 'ERROR: Wrong arguments [no columns argument]', 'wp-data-access' ) ); |
| 424 |
} |
| 425 |
parent::__construct( array( |
| 426 |
'singular' => ( isset( $args['singular'] ) ? $args['singular'] : __( 'Row', 'wp-data-access' ) ), |
| 427 |
'plural' => ( isset( $args['plural'] ) ? $args['plural'] : __( 'Rows', 'wp-data-access' ) ), |
| 428 |
'ajax' => ( isset( $args['ajax'] ) ? $args['ajax'] : false ), |
| 429 |
) ); |
| 430 |
// Set schema name is available. |
| 431 |
if ( isset( $args['wpdaschema_name'] ) ) { |
| 432 |
$this->schema_name = $args['wpdaschema_name']; |
| 433 |
} |
| 434 |
// Set table name (availability already checked). |
| 435 |
$this->table_name = $args['table_name']; |
| 436 |
if ( self::LIST_BASE_TABLE !== $this->table_name ) { |
| 437 |
// Whenever a table name is provided through a URL we are risking an SQL injection attack. Our |
| 438 |
// defence mechanism here is to check whether the table name provided exists in our database. |
| 439 |
// If it does not we'll terminate the process with an error. |
| 440 |
// Although this check is only needed when a table name is provided through the URL we will perform |
| 441 |
// it in all situations. It is a fast query which makes our application much more safe and reliable. |
| 442 |
$this->wpda_data_dictionary = new WPDA_Dictionary_Exist($this->schema_name, $this->table_name); |
| 443 |
if ( !$this->wpda_data_dictionary->table_exists() ) { |
| 444 |
wp_die( __( 'ERROR: Invalid table name or not authorized', 'wp-data-access' ) ); |
| 445 |
} |
| 446 |
} |
| 447 |
$this->pid = ( isset( $args['pid'] ) ? $args['pid'] : '' ); |
| 448 |
// Get menu slag of current page. |
| 449 |
if ( isset( $_REQUEST['page'] ) ) { |
| 450 |
$this->page = sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ); |
| 451 |
// input var okay. |
| 452 |
} else { |
| 453 |
// In order to show a list table we need a page. |
| 454 |
wp_die( __( 'ERROR: Wrong arguments [no page argument]', 'wp-data-access' ) ); |
| 455 |
} |
| 456 |
// Use column list: argument wpda_list_columns (availability already checked). |
| 457 |
$this->wpda_list_columns =& $args['wpda_list_columns']; |
| 458 |
// Set pagination. |
| 459 |
if ( is_admin() ) { |
| 460 |
$this->items_per_page = WPDA::get_option( WPDA::OPTION_BE_PAGINATION ); |
| 461 |
} else { |
| 462 |
$this->items_per_page = WPDA::get_option( WPDA::OPTION_FE_PAGINATION ); |
| 463 |
} |
| 464 |
// Overwrite column header text if column headers were provided. |
| 465 |
$this->column_headers = ( isset( $args['column_headers'] ) ? $args['column_headers'] : '' ); |
| 466 |
// Set title. |
| 467 |
if ( isset( $args['title'] ) ) { |
| 468 |
$this->title = $args['title']; |
| 469 |
} else { |
| 470 |
$this->title = __( 'Table', 'wp-data-access' ) . ' ' . strtoupper( $this->table_name ); |
| 471 |
} |
| 472 |
// Set subtitle. |
| 473 |
if ( isset( $args['subtitle'] ) ) { |
| 474 |
$this->subtitle = $args['subtitle']; |
| 475 |
} else { |
| 476 |
$wp_tables = $wpdb->tables( 'all', true ); |
| 477 |
if ( isset( $wp_tables[substr( $this->table_name, strlen( $wpdb->prefix ) )] ) ) { |
| 478 |
$this->subtitle = '<span class="dashicons dashicons-warning"></span> ' . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WP ); |
| 479 |
} elseif ( WPDA::is_wpda_table( $this->table_name ) ) { |
| 480 |
$this->subtitle = '<span class="dashicons dashicons-warning"></span> ' . WPDA::get_table_type_text( WPDA::TABLE_TYPE_WPDA ); |
| 481 |
} |
| 482 |
} |
| 483 |
if ( !(isset( $args['allow_import'] ) && 'off' === $args['allow_import']) ) { |
| 484 |
try { |
| 485 |
// Instantiate WPDA_Import. |
| 486 |
$this->wpda_import = new WPDA_Import(( is_admin() ? "?page={$this->page}" : '' ), $this->schema_name, $this->table_name); |
| 487 |
} catch ( \Exception $e ) { |
| 488 |
// If import is turned off instantiation will fail. Handle is set to null (check in future calls). |
| 489 |
$this->wpda_import = null; |
| 490 |
} |
| 491 |
} |
| 492 |
if ( isset( $args['bulk_export_enabled'] ) ) { |
| 493 |
$this->bulk_export_enabled = $args['bulk_export_enabled']; |
| 494 |
} |
| 495 |
if ( isset( $args['search_box_enabled'] ) ) { |
| 496 |
$this->search_box_enabled = $args['search_box_enabled']; |
| 497 |
} |
| 498 |
if ( isset( $args['bulk_actions_enabled'] ) ) { |
| 499 |
$this->bulk_actions_enabled = $args['bulk_actions_enabled']; |
| 500 |
} |
| 501 |
if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_VIEW_LINK ) ) { |
| 502 |
$this->show_view_link = WPDA::get_option( WPDA::OPTION_BE_VIEW_LINK ); |
| 503 |
} else { |
| 504 |
if ( isset( $args['show_view_link'] ) ) { |
| 505 |
$this->show_view_link = $args['show_view_link']; |
| 506 |
} else { |
| 507 |
$this->show_view_link = WPDA::get_option( WPDA::OPTION_BE_VIEW_LINK ); |
| 508 |
} |
| 509 |
} |
| 510 |
if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ) ) { |
| 511 |
$this->allow_insert = WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ); |
| 512 |
} else { |
| 513 |
if ( isset( $args['allow_insert'] ) ) { |
| 514 |
$this->allow_insert = $args['allow_insert']; |
| 515 |
} else { |
| 516 |
$this->allow_insert = WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ); |
| 517 |
} |
| 518 |
} |
| 519 |
if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_ALLOW_UPDATE ) ) { |
| 520 |
$this->allow_update = WPDA::get_option( WPDA::OPTION_BE_ALLOW_UPDATE ); |
| 521 |
} else { |
| 522 |
if ( isset( $args['allow_update'] ) ) { |
| 523 |
$this->allow_update = $args['allow_update']; |
| 524 |
} else { |
| 525 |
$this->allow_update = WPDA::get_option( WPDA::OPTION_BE_ALLOW_UPDATE ); |
| 526 |
} |
| 527 |
} |
| 528 |
if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_ALLOW_DELETE ) ) { |
| 529 |
$this->allow_delete = WPDA::get_option( WPDA::OPTION_BE_ALLOW_DELETE ); |
| 530 |
} else { |
| 531 |
if ( isset( $args['allow_delete'] ) ) { |
| 532 |
$this->allow_delete = $args['allow_delete']; |
| 533 |
} else { |
| 534 |
$this->allow_delete = WPDA::get_option( WPDA::OPTION_BE_ALLOW_DELETE ); |
| 535 |
} |
| 536 |
} |
| 537 |
if ( isset( $args['hide_navigation'] ) ) { |
| 538 |
$this->hide_navigation = $args['hide_navigation']; |
| 539 |
} |
| 540 |
$this->search_value = ( is_scalar( $this->get_search_value() ) ? str_replace( "\\'", '', (string) $this->get_search_value() ) : '' ); |
| 541 |
if ( isset( $_REQUEST["{$this->search_item_name}_old_value"] ) ) { |
| 542 |
$this->search_value_old = sanitize_text_field( wp_unslash( $_REQUEST["{$this->search_item_name}_old_value"] ) ); |
| 543 |
// input var okay. |
| 544 |
} else { |
| 545 |
$this->search_value_old = $this->search_value; |
| 546 |
} |
| 547 |
// Get page number(s). |
| 548 |
if ( 'page_number' !== $this->page_number_item_name ) { |
| 549 |
if ( isset( $_REQUEST['page_number'] ) ) { |
| 550 |
$requested_page_number = sanitize_text_field( wp_unslash( $_REQUEST['page_number'] ) ); |
| 551 |
// input var okay. |
| 552 |
$this->page_number_link = '&page_number=' . $requested_page_number; |
| 553 |
$this->page_number_item = "<input type='hidden' name='page_number' value='" . $requested_page_number . "' />"; |
| 554 |
} |
| 555 |
} |
| 556 |
$this->page_number_link .= '&paged=' . $this->get_pagenum(); |
| 557 |
$this->page_number_item .= "<input type='hidden' name='" . $this->page_number_item_name . "' value='" . $this->get_pagenum() . "' />"; |
| 558 |
// Add search arguments to link to return to same page. |
| 559 |
foreach ( $_REQUEST as $key => $value ) { |
| 560 |
if ( substr( $key, 0, 19 ) === 'wpda_search_column_' ) { |
| 561 |
if ( is_array( $value ) ) { |
| 562 |
foreach ( $value as $elem_key => $elem_value ) { |
| 563 |
$this->page_number_link .= "&{$elem_key}={$elem_value}"; |
| 564 |
$this->page_number_item .= "<input type='hidden' name='{$key}[]' value='{$elem_value}' />"; |
| 565 |
} |
| 566 |
} else { |
| 567 |
$this->page_number_link .= "&{$key}={$value}"; |
| 568 |
$this->page_number_item .= "<input type='hidden' name='{$key}' value='{$value}' />"; |
| 569 |
} |
| 570 |
} |
| 571 |
} |
| 572 |
// Check if a WHERE clause (filter) was defined. |
| 573 |
if ( isset( $args['default_where'] ) ) { |
| 574 |
$this->where = $args['default_where']; |
| 575 |
} |
| 576 |
// Get table settings. |
| 577 |
$wpda_table_settings = WPDA_Table_Settings_Model::query( $this->table_name, $this->schema_name ); |
| 578 |
if ( isset( $wpda_table_settings[0]['wpda_table_settings'] ) ) { |
| 579 |
$this->wpda_table_settings = json_decode( $wpda_table_settings[0]['wpda_table_settings'] ); |
| 580 |
} |
| 581 |
// Get estimated row count. |
| 582 |
$this->row_count_estimate = WPDA::get_row_count_estimate( $this->schema_name, $this->table_name, $this->wpda_table_settings ); |
| 583 |
$this->table_rows = $this->row_count_estimate['row_count']; |
| 584 |
// Get project table settings. |
| 585 |
global $wpda_project_mode; |
| 586 |
if ( is_array( $wpda_project_mode ) ) { |
| 587 |
$setname = $wpda_project_mode['setname']; |
| 588 |
$wpda_project_table_settings = null; |
| 589 |
$wpda_project_table_settings_db = WPDP_Project_Design_Table_Model::static_query( $this->schema_name, $this->table_name, $setname ); |
| 590 |
if ( isset( $wpda_project_table_settings_db->tableinfo ) ) { |
| 591 |
$this->wpda_project_table_settings = $wpda_project_table_settings_db->tableinfo; |
| 592 |
} |
| 593 |
} |
| 594 |
if ( isset( $args['show_page_title'] ) && false === $args['show_page_title'] ) { |
| 595 |
$this->show_page_title = $args['show_page_title']; |
| 596 |
} |
| 597 |
if ( isset( $args['help_url'] ) ) { |
| 598 |
$this->help_url = $args['help_url']; |
| 599 |
} |
| 600 |
foreach ( $this->wpda_list_columns->get_table_columns() as $table_columns ) { |
| 601 |
$this->columns_indexed[$table_columns['column_name']] = $table_columns; |
| 602 |
} |
| 603 |
} |
| 604 |
|
| 605 |
/** |
| 606 |
* Overwrite method |
| 607 |
* |
| 608 |
* @return int|void |
| 609 |
*/ |
| 610 |
public function get_pagenum() { |
| 611 |
if ( isset( $_REQUEST[$this->page_number_item_name] ) ) { |
| 612 |
$pagenum = ( isset( $_REQUEST[$this->page_number_item_name] ) ? absint( $_REQUEST[$this->page_number_item_name] ) : 0 ); |
| 613 |
if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) { |
| 614 |
$pagenum = $this->_pagination_args['total_pages']; |
| 615 |
} |
| 616 |
return max( 1, $pagenum ); |
| 617 |
} else { |
| 618 |
return parent::get_pagenum(); |
| 619 |
} |
| 620 |
} |
| 621 |
|
| 622 |
/** |
| 623 |
* Set columns to be queries |
| 624 |
* |
| 625 |
* Set columns to be queried and shown in the list table. |
| 626 |
* By default all columns in the table will be displayed. |
| 627 |
* |
| 628 |
* @param mixed $columns_queried Column list. |
| 629 |
* |
| 630 |
* @since 1.0.0 |
| 631 |
*/ |
| 632 |
public function set_columns_queried( $columns_queried ) { |
| 633 |
$this->columns_queried = $columns_queried; |
| 634 |
} |
| 635 |
|
| 636 |
/** |
| 637 |
* Enable or disable bulk actions |
| 638 |
* |
| 639 |
* @param boolean $bulk_actions_enabled TRUE = allowed, FALSE = not allowed. |
| 640 |
* |
| 641 |
* @since 1.0.0 |
| 642 |
*/ |
| 643 |
public function set_bulk_actions_enabled( $bulk_actions_enabled ) { |
| 644 |
$this->bulk_actions_enabled = $bulk_actions_enabled; |
| 645 |
} |
| 646 |
|
| 647 |
/** |
| 648 |
* Enable or disable bulk export options |
| 649 |
* |
| 650 |
* @param boolean $bulk_export_enabled TRUE = allowed, FALSE = not allowed. |
| 651 |
* |
| 652 |
* @since 1.0.0 |
| 653 |
*/ |
| 654 |
public function set_bulk_export_enabled( $bulk_export_enabled ) { |
| 655 |
$this->bulk_export_enabled = $bulk_export_enabled; |
| 656 |
} |
| 657 |
|
| 658 |
/** |
| 659 |
* Show or hide search box |
| 660 |
* |
| 661 |
* @param boolean $search_box_enabled TRUE = show search box, FALSE = do not show search bow. |
| 662 |
* |
| 663 |
* @since 1.0.0 |
| 664 |
*/ |
| 665 |
public function set_search_box_enabled( $search_box_enabled ) { |
| 666 |
$this->search_box_enabled = $search_box_enabled; |
| 667 |
} |
| 668 |
|
| 669 |
/** |
| 670 |
* Set page title |
| 671 |
* |
| 672 |
* @param string $title Page title. |
| 673 |
* |
| 674 |
* @since 1.0.0 |
| 675 |
*/ |
| 676 |
public function set_title( $title ) { |
| 677 |
$this->title = $title; |
| 678 |
} |
| 679 |
|
| 680 |
/** |
| 681 |
* Set page subtitle |
| 682 |
* |
| 683 |
* @param string $subtitle Page subtitle. |
| 684 |
* |
| 685 |
* @since 1.0.0 |
| 686 |
*/ |
| 687 |
public function set_subtitle( $subtitle ) { |
| 688 |
$this->subtitle = $subtitle; |
| 689 |
} |
| 690 |
|
| 691 |
/** |
| 692 |
* I18n text displayed when no data found |
| 693 |
* |
| 694 |
* @since 1.0.0 |
| 695 |
*/ |
| 696 |
public function no_items() { |
| 697 |
echo __( 'No data found', 'wp-data-access' ); |
| 698 |
} |
| 699 |
|
| 700 |
/** |
| 701 |
* Use this method to build parent child relationships. |
| 702 |
* |
| 703 |
* Overwrite this function if you want to use the list table as a child list table related to some parent |
| 704 |
* form. You can add parent arguments to calls to make sure you get back to the right parent. |
| 705 |
* |
| 706 |
* @param array $item Column info. |
| 707 |
* @return string String contains parent arguments. |
| 708 |
* @since 1.5.0 |
| 709 |
*/ |
| 710 |
protected function add_parent_args_as_string( $item ) { |
| 711 |
return ''; |
| 712 |
} |
| 713 |
|
| 714 |
/** |
| 715 |
* Render columns |
| 716 |
* |
| 717 |
* Three links are provided for every list table row: |
| 718 |
* + 'View' => Link to view form (readonly data entry form) |
| 719 |
* + 'Edit' => Link to data entry form (updatable) |
| 720 |
* + 'Delete' => Link to delete record from database table |
| 721 |
* |
| 722 |
* Links to view, edit and delete records are only available if a primary key for the table is found. Without |
| 723 |
* a primary key unique identification of records is not possible. |
| 724 |
* |
| 725 |
* Links to action are offered through hidden forms to prevent long URL's and problem when refreshing pages |
| 726 |
* manually. More information about how and why is provided in source code at place where I thought the |
| 727 |
* information could be helpful. |
| 728 |
* |
| 729 |
* @param array $item Column info. |
| 730 |
* @param string $column_name Column name. |
| 731 |
* |
| 732 |
* @return mixed Value display in list table column |
| 733 |
* @since 1.0.0 |
| 734 |
*/ |
| 735 |
public function column_default( $item, $column_name ) { |
| 736 |
if ( $this->wpda_list_columns->get_table_columns()[0]['column_name'] === $column_name || $column_name === $this->first_display_column ) { |
| 737 |
// First column: add row actions. |
| 738 |
$count = count( $this->wpda_list_columns->get_table_primary_key() ); |
| 739 |
//phpcs:ignore - 8.1 proof |
| 740 |
if ( 0 === $count ) { |
| 741 |
// No actions without a primary key! |
| 742 |
// This automatically covers view processing correctly. |
| 743 |
return $this->render_column_content( $item, $column_name ) . $this->row_actions( array( |
| 744 |
'wpda_hide_column' => '', |
| 745 |
) ); |
| 746 |
} else { |
| 747 |
// Check rights. |
| 748 |
if ( 'off' === $this->show_view_link && 'off' === $this->allow_update && 'off' === $this->allow_delete ) { |
| 749 |
// No rights! |
| 750 |
$actions = array(); |
| 751 |
$this->column_default_add_action( $item, $column_name, $actions ); |
| 752 |
if ( is_array( $actions ) && count( $actions ) > 0 ) { |
| 753 |
//phpcs:ignore - 8.1 proof |
| 754 |
return sprintf( '%1$s %2$s', $this->render_column_content( $item, $column_name ), $this->row_actions( $actions ) ); |
| 755 |
} else { |
| 756 |
return sprintf( '%1$s', $this->render_column_content( $item, $column_name ) ); |
| 757 |
} |
| 758 |
} |
| 759 |
// Check if row security is enabled. |
| 760 |
$row_security = isset( $this->wpda_table_settings->table_settings->row_level_security ) && 'true' === $this->wpda_table_settings->table_settings->row_level_security; |
| 761 |
// To prevent our URLs containing many arguments, we'll use post to submit row actions. Since our |
| 762 |
// list table is build within a form and we cannot use nested forms we'll use a container (id = |
| 763 |
// wpda_invisible_container) defined outside the list table, and add our forms to that container. |
| 764 |
// We'll use jQuery to add our forms to the container. From the links in our rows we can then just |
| 765 |
// submit any form in that container with jQuery as well. |
| 766 |
$form_id = '_' . self::$list_number++; |
| 767 |
$wp_nonce_keys = ''; |
| 768 |
$row_security_keys = ''; |
| 769 |
// We need to add keys and values for multi-column primary keys. |
| 770 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $key ) { |
| 771 |
$wp_nonce_keys .= "-{$item[$key]}"; |
| 772 |
if ( $row_security ) { |
| 773 |
$row_security_keys .= "-{$key}-{$item[$key]}"; |
| 774 |
} |
| 775 |
} |
| 776 |
if ( $row_security ) { |
| 777 |
$row_security_nonce = wp_create_nonce( "wpda-row-level-security-{$this->table_name}{$row_security_keys}" ); |
| 778 |
$row_security_nonce_field = "<input type='hidden' name='rownonce' value='" . esc_attr( $row_security_nonce ) . "' />"; |
| 779 |
} else { |
| 780 |
$row_security_nonce_field = ''; |
| 781 |
} |
| 782 |
// Prepare url. |
| 783 |
if ( is_admin() ) { |
| 784 |
$url = "?page={$this->page}"; |
| 785 |
} else { |
| 786 |
$url = ''; |
| 787 |
} |
| 788 |
if ( 'on' === $this->show_view_link ) { |
| 789 |
$wp_nonce_action = "wpda-query-{$this->table_name}{$wp_nonce_keys}"; |
| 790 |
$wp_nonce = wp_create_nonce( $wp_nonce_action ); |
| 791 |
// Build the row action. Use jQuery to add form to container. |
| 792 |
// All items escaped in create_post_form(). |
| 793 |
$view_form = $this->create_post_form( |
| 794 |
$item, |
| 795 |
"view_form{$form_id}", |
| 796 |
'view', |
| 797 |
$url, |
| 798 |
$wp_nonce, |
| 799 |
$row_security_nonce_field, |
| 800 |
$this->schema_name, |
| 801 |
$this->table_name |
| 802 |
); |
| 803 |
?> |
| 804 |
|
| 805 |
<script type='text/javascript'> |
| 806 |
jQuery("#wpda_invisible_container").append("<?php |
| 807 |
echo $view_form; |
| 808 |
// phpcs:ignore WordPress.Security.EscapeOutput |
| 809 |
?>"); |
| 810 |
</script> |
| 811 |
|
| 812 |
<?php |
| 813 |
// Add link to submit form. |
| 814 |
$actions['view'] = sprintf( |
| 815 |
'<a href="javascript:void(0)" |
| 816 |
class="edit wpda_tooltip" |
| 817 |
title="%s" |
| 818 |
onclick="jQuery(\'#%s\').submit()"> |
| 819 |
<span style="white-space: nowrap"> |
| 820 |
<i class="fas fa-eye wpda_icon_on_button"></i> |
| 821 |
%s |
| 822 |
</span> |
| 823 |
</a> |
| 824 |
', |
| 825 |
__( 'View row data', 'wp-data-access' ), |
| 826 |
"view_form{$form_id}", |
| 827 |
__( 'View', 'wp-data-access' ) |
| 828 |
); |
| 829 |
} |
| 830 |
if ( 'on' === $this->allow_update || WPDA::is_wpda_table( $this->table_name ) ) { |
| 831 |
$wp_nonce_action = "wpda-query-{$this->table_name}{$wp_nonce_keys}"; |
| 832 |
$wp_nonce = wp_create_nonce( $wp_nonce_action ); |
| 833 |
// Build the row action. Use jQuery to add form to container. |
| 834 |
// All items escaped in create_post_form(). |
| 835 |
$edit_form = $this->create_post_form( |
| 836 |
$item, |
| 837 |
"edit_form{$form_id}", |
| 838 |
'edit', |
| 839 |
$url, |
| 840 |
$wp_nonce, |
| 841 |
$row_security_nonce_field, |
| 842 |
$this->schema_name, |
| 843 |
$this->table_name |
| 844 |
); |
| 845 |
?> |
| 846 |
|
| 847 |
<script type='text/javascript'> |
| 848 |
jQuery("#wpda_invisible_container").append("<?php |
| 849 |
echo $edit_form; |
| 850 |
// phpcs:ignore WordPress.Security.EscapeOutput |
| 851 |
?>"); |
| 852 |
</script> |
| 853 |
|
| 854 |
<?php |
| 855 |
// Add link to submit form. |
| 856 |
$actions['edit'] = sprintf( |
| 857 |
'<a href="javascript:void(0)" |
| 858 |
class="edit wpda_tooltip" |
| 859 |
title="%s" |
| 860 |
onclick="jQuery(\'#%s\').submit()"> |
| 861 |
<span style="white-space: nowrap"> |
| 862 |
<i class="fas fa-pen wpda_icon_on_button"></i> |
| 863 |
%s |
| 864 |
</span> |
| 865 |
</a> |
| 866 |
', |
| 867 |
__( 'Edit row data', 'wp-data-access' ), |
| 868 |
"edit_form{$form_id}", |
| 869 |
__( 'Edit', 'wp-data-access' ) |
| 870 |
); |
| 871 |
} |
| 872 |
if ( 'on' === $this->allow_delete || WPDA::is_wpda_table( $this->table_name ) ) { |
| 873 |
$wp_nonce_action = "wpda-delete-{$this->table_name}{$wp_nonce_keys}"; |
| 874 |
$wp_nonce = wp_create_nonce( $wp_nonce_action ); |
| 875 |
// Build the row action. Use jQuery to add form to container. |
| 876 |
// All items escaped in create_post_form(). |
| 877 |
$delete_form = $this->create_post_form( |
| 878 |
$item, |
| 879 |
"delete_form{$form_id}", |
| 880 |
'delete', |
| 881 |
$url, |
| 882 |
$wp_nonce, |
| 883 |
$row_security_nonce_field, |
| 884 |
$this->schema_name, |
| 885 |
$this->table_name |
| 886 |
); |
| 887 |
?> |
| 888 |
|
| 889 |
<script type='text/javascript'> |
| 890 |
jQuery("#wpda_invisible_container").append("<?php |
| 891 |
echo $delete_form; |
| 892 |
// phpcs:ignore WordPress.Security.EscapeOutput |
| 893 |
?>"); |
| 894 |
</script> |
| 895 |
|
| 896 |
<?php |
| 897 |
// Add link to submit form. |
| 898 |
$warning = __( "You are about to permanently delete these items from your site.\\nThis action cannot be undone.\\n\\'Cancel\\' to stop, \\'OK\\' to delete.", 'wp-data-access' ); |
| 899 |
$actions['delete'] = sprintf( |
| 900 |
'<a href="javascript:void(0)" |
| 901 |
class="delete wpda_tooltip" |
| 902 |
title="%s" |
| 903 |
onclick="if (confirm(\'%s\')) jQuery(\'#%s\').submit()"> |
| 904 |
<span style="white-space: nowrap"> |
| 905 |
<i class="fas fa-trash wpda_icon_on_button"></i> |
| 906 |
%s |
| 907 |
</span> |
| 908 |
</a> |
| 909 |
', |
| 910 |
__( 'Delete row data (this cannot be undone)', 'wp-data-access' ), |
| 911 |
$warning, |
| 912 |
"delete_form{$form_id}", |
| 913 |
__( 'Delete', 'wp-data-access' ) |
| 914 |
); |
| 915 |
} |
| 916 |
// Developers can add actions by adding their own implementation of following method. |
| 917 |
$this->column_default_add_action( $item, $column_name, $actions ); |
| 918 |
if ( has_filter( 'wpda_column_default' ) ) { |
| 919 |
// Use filter. |
| 920 |
$filter = apply_filters( |
| 921 |
'wpda_column_default', |
| 922 |
'', |
| 923 |
$item, |
| 924 |
$column_name, |
| 925 |
$this->table_name, |
| 926 |
$this->schema_name, |
| 927 |
$this->wpda_list_columns, |
| 928 |
self::$list_number, |
| 929 |
$this |
| 930 |
); |
| 931 |
if ( null !== $filter ) { |
| 932 |
return sprintf( '%1$s %2$s', $filter, $this->row_actions( $actions ) ); |
| 933 |
} |
| 934 |
} |
| 935 |
return sprintf( '%1$s %2$s', $this->render_column_content( $item, $column_name ), $this->row_actions( $actions ) ); |
| 936 |
} |
| 937 |
} else { |
| 938 |
if ( substr( $column_name, 0, 15 ) === 'wpda_hyperlink_' ) { |
| 939 |
$hyperlink_no = substr( $column_name, 15 ); |
| 940 |
if ( isset( $this->wpda_table_settings->hyperlinks[$hyperlink_no] ) ) { |
| 941 |
$hyperlink = $this->wpda_table_settings->hyperlinks[$hyperlink_no]; |
| 942 |
$hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' ); |
| 943 |
if ( '' !== $hyperlink_html ) { |
| 944 |
// Substitute values. |
| 945 |
foreach ( $item as $key => $value ) { |
| 946 |
$hyperlink_html = str_replace( "\$\${$key}\$\$", str_replace( ' ', '%20', (string) $value ), $hyperlink_html ); |
| 947 |
} |
| 948 |
} |
| 949 |
$macro = new WPDA_Macro($hyperlink_html); |
| 950 |
$hyperlink_html = $macro->exe_macro(); |
| 951 |
if ( '' !== $hyperlink_html ) { |
| 952 |
// Link is not empty AFTER substitution. |
| 953 |
if ( false !== strpos( ltrim( $hyperlink_html ), '<' ) ) { |
| 954 |
return html_entity_decode( $hyperlink_html ); |
| 955 |
} else { |
| 956 |
$hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' ); |
| 957 |
$hyperlink_target = ( isset( $hyperlink->hyperlink_target ) ? $hyperlink->hyperlink_target : false ); |
| 958 |
$target = ( true === $hyperlink_target ? "target='_blank'" : '' ); |
| 959 |
return "<a href='" . str_replace( ' ', '+', trim( $hyperlink_html ) ) . "' {$target}>{$hyperlink_label}</a>"; |
| 960 |
} |
| 961 |
} else { |
| 962 |
return ''; |
| 963 |
} |
| 964 |
} |
| 965 |
return 'ERROR'; |
| 966 |
} else { |
| 967 |
// Check if column is of type media. |
| 968 |
$media_type = WPDA_Media_Model::get_column_media( $this->table_name, $column_name, $this->schema_name ); |
| 969 |
if ( 'Image' === $media_type ) { |
| 970 |
$image_ids = explode( ',', (string) $item[$column_name] ); |
| 971 |
//phpcs:ignore - 8.1 proof |
| 972 |
$image_src = ''; |
| 973 |
foreach ( $image_ids as $image_id ) { |
| 974 |
$url = wp_get_attachment_url( esc_attr( $image_id ) ); |
| 975 |
if ( false !== $url ) { |
| 976 |
$title = get_the_title( esc_attr( $image_id ) ); |
| 977 |
$image_src .= ( '' !== $image_src ? '<br/>' : '' ); |
| 978 |
$image_src .= sprintf( '<img src="%s" class="wpda_tooltip" title="%s" width="100%%">', $url, $title ); |
| 979 |
} |
| 980 |
} |
| 981 |
return $image_src; |
| 982 |
} elseif ( 'ImageURL' === $media_type ) { |
| 983 |
return sprintf( '<img src="%s" class="wpda_tooltip" width="100%%">', $item[$column_name] ); |
| 984 |
} elseif ( 'Attachment' === $media_type ) { |
| 985 |
$media_ids = explode( ',', (string) $item[$column_name] ); |
| 986 |
//phpcs:ignore - 8.1 proof |
| 987 |
$media_links = ''; |
| 988 |
foreach ( $media_ids as $media_id ) { |
| 989 |
$url = wp_get_attachment_url( esc_attr( $media_id ) ); |
| 990 |
if ( false !== $url ) { |
| 991 |
$mime_type = get_post_mime_type( $media_id ); |
| 992 |
if ( false !== $mime_type ) { |
| 993 |
$title = get_the_title( esc_attr( $media_id ) ); |
| 994 |
$media_links .= self::column_media_attachment( $url, $title, $mime_type ); |
| 995 |
} |
| 996 |
} |
| 997 |
} |
| 998 |
return $media_links; |
| 999 |
} elseif ( 'Hyperlink' === $media_type ) { |
| 1000 |
if ( null === $item[$column_name] || '' === $item[$column_name] ) { |
| 1001 |
return ''; |
| 1002 |
} else { |
| 1003 |
if ( !(isset( $this->wpda_table_settings->table_settings->hyperlink_definition ) && 'text' === $this->wpda_table_settings->table_settings->hyperlink_definition) ) { |
| 1004 |
$hyperlink = json_decode( $item[$column_name], true ); |
| 1005 |
if ( is_array( $hyperlink ) && isset( $hyperlink['label'] ) && isset( $hyperlink['url'] ) && isset( $hyperlink['target'] ) ) { |
| 1006 |
if ( '' === $hyperlink['url'] ) { |
| 1007 |
return ''; |
| 1008 |
} else { |
| 1009 |
return "<a href='{$hyperlink['url']}' target='{$hyperlink['target']}'>{$hyperlink['label']}</a>"; |
| 1010 |
} |
| 1011 |
} else { |
| 1012 |
return ''; |
| 1013 |
} |
| 1014 |
} else { |
| 1015 |
$hyperlink_label = $this->wpda_list_columns->get_column_label( $column_name ); |
| 1016 |
return "<a href='{$item[$column_name]}' target='_blank'>{$hyperlink_label}</a>"; |
| 1017 |
} |
| 1018 |
} |
| 1019 |
} elseif ( 'Audio' === $media_type ) { |
| 1020 |
$audio_ids = explode( ',', (string) $item[$column_name] ); |
| 1021 |
//phpcs:ignore - 8.1 proof |
| 1022 |
$audio_src = ''; |
| 1023 |
foreach ( $audio_ids as $audio_id ) { |
| 1024 |
if ( 'audio' === substr( get_post_mime_type( $audio_id ), 0, 5 ) ) { |
| 1025 |
$url = wp_get_attachment_url( esc_attr( $audio_id ) ); |
| 1026 |
if ( false !== $url ) { |
| 1027 |
$title = get_the_title( esc_attr( $audio_id ) ); |
| 1028 |
if ( false !== $url ) { |
| 1029 |
$audio_src .= '<div title="' . $title . '" class="wpda_tooltip">' . do_shortcode( '[audio src="' . $url . '"]' ) . '</div>'; |
| 1030 |
} |
| 1031 |
} |
| 1032 |
} |
| 1033 |
} |
| 1034 |
return $audio_src; |
| 1035 |
} elseif ( 'Video' === $media_type ) { |
| 1036 |
$video_ids = explode( ',', (string) $item[$column_name] ); |
| 1037 |
//phpcs:ignore - 8.1 proof |
| 1038 |
$video_src = ''; |
| 1039 |
foreach ( $video_ids as $video_id ) { |
| 1040 |
if ( 'video' === substr( get_post_mime_type( $video_id ), 0, 5 ) ) { |
| 1041 |
$url = wp_get_attachment_url( esc_attr( $video_id ) ); |
| 1042 |
if ( false !== $url ) { |
| 1043 |
if ( false !== $url ) { |
| 1044 |
$video_src .= do_shortcode( '[video src="' . $url . '"]' ); |
| 1045 |
} |
| 1046 |
} |
| 1047 |
} |
| 1048 |
} |
| 1049 |
return $video_src; |
| 1050 |
} |
| 1051 |
} |
| 1052 |
if ( has_filter( 'wpda_column_default' ) ) { |
| 1053 |
// Use filter. |
| 1054 |
$filter = apply_filters( |
| 1055 |
'wpda_column_default', |
| 1056 |
'', |
| 1057 |
$item, |
| 1058 |
$column_name, |
| 1059 |
$this->table_name, |
| 1060 |
$this->schema_name, |
| 1061 |
$this->wpda_list_columns, |
| 1062 |
self::$list_number, |
| 1063 |
$this |
| 1064 |
); |
| 1065 |
if ( null !== $filter ) { |
| 1066 |
return $filter; |
| 1067 |
} |
| 1068 |
} |
| 1069 |
if ( 'csv' !== WPDA::get_option( WPDA::OPTION_PLUGIN_SET_FORMAT ) && isset( $this->columns_indexed[$column_name]['data_type'] ) && 'set' === $this->columns_indexed[$column_name]['data_type'] ) { |
| 1070 |
$list = '<' . WPDA::get_option( WPDA::OPTION_PLUGIN_SET_FORMAT ) . '>'; |
| 1071 |
$listarray = explode( ',', (string) $item[$column_name] ); |
| 1072 |
//phpcs:ignore - 8.1 proof |
| 1073 |
foreach ( $listarray as $listitem ) { |
| 1074 |
$list .= "<li>{$listitem}</li>"; |
| 1075 |
} |
| 1076 |
$list .= '</' . WPDA::get_option( WPDA::OPTION_PLUGIN_SET_FORMAT ) . '>'; |
| 1077 |
return $list; |
| 1078 |
} |
| 1079 |
return $this->render_column_content( $item, $column_name ); |
| 1080 |
} |
| 1081 |
} |
| 1082 |
|
| 1083 |
/** |
| 1084 |
* Create post form which is added to the invisible container |
| 1085 |
* |
| 1086 |
* @param array $item Column info. |
| 1087 |
* @param string $form_id Form ID. |
| 1088 |
* @param string $action Form action. |
| 1089 |
* @param string $url URL admin page. |
| 1090 |
* @param string $wp_nonce Nonce. |
| 1091 |
* @param string $row_security_nonce_field Nonce for row level access security. |
| 1092 |
* @param string $schema_name Database schema name. |
| 1093 |
* @param string $table_name Database table name. |
| 1094 |
* |
| 1095 |
* @return array|string|string[] |
| 1096 |
*/ |
| 1097 |
private function create_post_form( |
| 1098 |
$item, |
| 1099 |
$form_id, |
| 1100 |
$action, |
| 1101 |
$url, |
| 1102 |
$wp_nonce, |
| 1103 |
$row_security_nonce_field, |
| 1104 |
$schema_name, |
| 1105 |
$table_name |
| 1106 |
) { |
| 1107 |
// Already escaped: $url, $row_security_nonce_field, get_key_input_fields(), add_parent_args_as_string(). |
| 1108 |
$esc_attr = 'esc_attr'; |
| 1109 |
$get_key_input_fields = $this->get_key_input_fields( $item ); |
| 1110 |
$add_parent_args_as_string = $this->add_parent_args_as_string( $item ); |
| 1111 |
$page_number_item = $this->page_number_item; |
| 1112 |
$case_sensitive_search = ( isset( $_REQUEST['wpda_c'] ) && 'true' === $_REQUEST['wpda_c'] ? "<input type='hidden' name='wpda_c' value='true'>" : '' ); |
| 1113 |
$add_schema_and_table_name = ( !is_admin() ? '' : "\n\t\t\t\t\t<input type='hidden' name='wpdaschema_name' value='{$esc_attr( $schema_name )}' />\n\t\t\t\t\t<input type='hidden' name='table_name' value='{$esc_attr( $table_name )}' />\n\t\t\t\t" ); |
| 1114 |
// Hide schema and table name on front-end |
| 1115 |
$form = <<<EOT |
| 1116 |
\t\t\t\t<form id='{$esc_attr( $form_id )}' action='{$url}' method='post'> |
| 1117 |
\t\t\t\t\t{$get_key_input_fields} |
| 1118 |
\t\t\t\t\t{$add_parent_args_as_string} |
| 1119 |
\t\t\t\t\t{$add_schema_and_table_name} |
| 1120 |
\t\t\t\t\t<input type='hidden' name='action' value='{$esc_attr( $action )}' /> |
| 1121 |
\t\t\t\t\t<input type='hidden' name='_wpnonce' value='{$esc_attr( $wp_nonce )}'> |
| 1122 |
\t\t\t\t\t{$row_security_nonce_field} |
| 1123 |
\t\t\t\t\t{$page_number_item} |
| 1124 |
\t\t\t\t\t{$case_sensitive_search} |
| 1125 |
\t\t\t\t</form> |
| 1126 |
EOT; |
| 1127 |
return str_replace( array("\n", "\r"), '', $form ); |
| 1128 |
} |
| 1129 |
|
| 1130 |
/** |
| 1131 |
* Create media link |
| 1132 |
* |
| 1133 |
* @param string $url Media URL. |
| 1134 |
* @param string $title Media title. |
| 1135 |
* @param string $mime_type Mime type. |
| 1136 |
* |
| 1137 |
* @return string |
| 1138 |
*/ |
| 1139 |
public static function column_media_attachment( $url, $title, $mime_type ) { |
| 1140 |
if ( 'image' === substr( $mime_type, 0, 5 ) ) { |
| 1141 |
$class = 'dashicons-format-image'; |
| 1142 |
} elseif ( 'audio' === substr( $mime_type, 0, 5 ) ) { |
| 1143 |
$class = 'dashicons-playlist-audio'; |
| 1144 |
} elseif ( 'video' === substr( $mime_type, 0, 5 ) ) { |
| 1145 |
$class = 'dashicons-playlist-video'; |
| 1146 |
} elseif ( 'application' === substr( $mime_type, 0, 11 ) ) { |
| 1147 |
$class = 'dashicons-media-document'; |
| 1148 |
} else { |
| 1149 |
$class = 'dashicons-external'; |
| 1150 |
} |
| 1151 |
return sprintf( |
| 1152 |
'<a href="%s" title="%s" target="_blank"><span class="dashicons %s wpda_attachment_icon"></span></a>', |
| 1153 |
$url, |
| 1154 |
$title, |
| 1155 |
$class |
| 1156 |
); |
| 1157 |
} |
| 1158 |
|
| 1159 |
/** |
| 1160 |
* Overwrite method to prevent double row actions |
| 1161 |
* |
| 1162 |
* @param object $item Table column. |
| 1163 |
* @param string $column_name Column name. |
| 1164 |
* @param string $primary Primary key. |
| 1165 |
* |
| 1166 |
* @return string |
| 1167 |
*/ |
| 1168 |
protected function handle_row_actions( $item, $column_name, $primary ) { |
| 1169 |
return ''; |
| 1170 |
} |
| 1171 |
|
| 1172 |
/** |
| 1173 |
* Render column content |
| 1174 |
* |
| 1175 |
* Strip content if too long and replace & character. |
| 1176 |
* |
| 1177 |
* @param object $item Table column. |
| 1178 |
* @param string $column_name Database column name. |
| 1179 |
* |
| 1180 |
* @return string Rendered column content |
| 1181 |
*/ |
| 1182 |
protected function render_column_content( $item, $column_name, $substitute_newlines = true ) { |
| 1183 |
$column_content = ( isset( $item["lookup_value_{$column_name}"] ) ? $item["lookup_value_{$column_name}"] : $item[$column_name] ); |
| 1184 |
if ( 'off' === WPDA::get_option( WPDA::OPTION_BE_TEXT_WRAP_SWITCH ) && WPDA::get_option( WPDA::OPTION_BE_TEXT_WRAP ) < strlen( (string) $column_content ) ) { |
| 1185 |
$title = sprintf( __( 'Output limited to %1$s characters', 'wp-data-access' ), WPDA::get_option( WPDA::OPTION_BE_TEXT_WRAP ) ); |
| 1186 |
if ( $substitute_newlines ) { |
| 1187 |
return str_replace( "\n", '<br/>', substr( esc_html( str_replace( '&', '&', (string) $column_content ) ), 0, WPDA::get_option( WPDA::OPTION_BE_TEXT_WRAP ) ) . ' <a href="javascript:void(0)" title="' . $title . '">•••</a>' ); |
| 1188 |
} else { |
| 1189 |
return substr( esc_html( str_replace( '&', '&', (string) $column_content ) ), 0, WPDA::get_option( WPDA::OPTION_BE_TEXT_WRAP ) ) . ' <a href="javascript:void(0)" title="' . $title . '">•••</a>'; |
| 1190 |
} |
| 1191 |
} else { |
| 1192 |
$column_data_type = $this->wpda_list_columns->get_column_data_type( $column_name ); |
| 1193 |
switch ( $column_data_type ) { |
| 1194 |
case 'date': |
| 1195 |
// date only. |
| 1196 |
if ( '' === $column_content || null === $column_content ) { |
| 1197 |
$column_content = ''; |
| 1198 |
} else { |
| 1199 |
$column_content = date_i18n( get_option( 'date_format' ), strtotime( $column_content ) ); |
| 1200 |
} |
| 1201 |
break; |
| 1202 |
case 'time': |
| 1203 |
// time only. |
| 1204 |
if ( '' === $column_content || null === $column_content ) { |
| 1205 |
$column_content = ''; |
| 1206 |
} else { |
| 1207 |
$column_content = date_i18n( get_option( 'time_format' ), strtotime( $column_content ) ); |
| 1208 |
} |
| 1209 |
break; |
| 1210 |
case 'datetime': |
| 1211 |
// date + time. |
| 1212 |
case 'timestamp': |
| 1213 |
if ( '' === $column_content || null === $column_content ) { |
| 1214 |
$column_content = ''; |
| 1215 |
} else { |
| 1216 |
$column_content = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $column_content ) ); |
| 1217 |
} |
| 1218 |
} |
| 1219 |
if ( $substitute_newlines ) { |
| 1220 |
return str_replace( "\n", '<br/>', esc_html( str_replace( '&', '&', (string) $column_content ) ) ); |
| 1221 |
} else { |
| 1222 |
return esc_html( str_replace( '&', '&', (string) $column_content ) ); |
| 1223 |
} |
| 1224 |
} |
| 1225 |
} |
| 1226 |
|
| 1227 |
/** |
| 1228 |
* Generate hidden fields for keys |
| 1229 |
* |
| 1230 |
* @param array $item Column info. |
| 1231 |
* |
| 1232 |
* @return string String containing key items and values. |
| 1233 |
*/ |
| 1234 |
protected function get_key_input_fields( $item ) { |
| 1235 |
$key_input_fields = ''; |
| 1236 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $key ) { |
| 1237 |
$key_name = esc_attr( $key ); |
| 1238 |
$key_value = esc_attr( $item[$key] ); |
| 1239 |
$key_input_fields .= "<input type='hidden' name='{$key_name}' value='{$key_value}' />"; |
| 1240 |
} |
| 1241 |
return $key_input_fields; |
| 1242 |
} |
| 1243 |
|
| 1244 |
/** |
| 1245 |
* Override this method to add actions to first column of row |
| 1246 |
* |
| 1247 |
* @param array $item Item information. |
| 1248 |
* @param string $column_name Column name. |
| 1249 |
* @param array $actions Array of actions to be added to row. |
| 1250 |
*/ |
| 1251 |
protected function column_default_add_action( $item, $column_name, &$actions ) { |
| 1252 |
if ( has_filter( 'wpda_column_default_add_action' ) ) { |
| 1253 |
$filter = apply_filters( |
| 1254 |
'wpda_column_default_add_action', |
| 1255 |
'', |
| 1256 |
$item, |
| 1257 |
$column_name, |
| 1258 |
$this->table_name, |
| 1259 |
$this->schema_name, |
| 1260 |
$this->wpda_list_columns, |
| 1261 |
self::$list_number, |
| 1262 |
$actions, |
| 1263 |
$this |
| 1264 |
); |
| 1265 |
if ( null !== $filter ) { |
| 1266 |
$actions = $filter; |
| 1267 |
} |
| 1268 |
} |
| 1269 |
} |
| 1270 |
|
| 1271 |
/** |
| 1272 |
* Render bulk edit checkbox |
| 1273 |
* |
| 1274 |
* @param array $item Column list. |
| 1275 |
* |
| 1276 |
* @return string Content for checkbox column. |
| 1277 |
* @since 1.0.0 |
| 1278 |
*/ |
| 1279 |
public function column_cb( $item ) { |
| 1280 |
if ( !$this->bulk_actions_enabled ) { |
| 1281 |
// Bulk actions disabled. |
| 1282 |
return ''; |
| 1283 |
} |
| 1284 |
if ( empty( $this->wpda_list_columns->get_table_primary_key() ) ) { |
| 1285 |
// Table has no primary key: no bulk actions allowed! |
| 1286 |
// Primary key is used to ensure uniqueness! |
| 1287 |
return ''; |
| 1288 |
} |
| 1289 |
// Build CB value: Use json format for multi column primary keys. |
| 1290 |
$cb_value = (object) null; |
| 1291 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $primary_key_column ) { |
| 1292 |
// JSON string key and values will be double quoted. Therefore a slash must be added to double quotes in values. |
| 1293 |
$cb_value->{$primary_key_column} = esc_attr( str_replace( '"', '\\"', $item[$primary_key_column] ) ); |
| 1294 |
} |
| 1295 |
return "<input type='checkbox' name='bulk-selected[]' value='" . wp_json_encode( $cb_value ) . "' />"; |
| 1296 |
} |
| 1297 |
|
| 1298 |
/** |
| 1299 |
* Show page title |
| 1300 |
* |
| 1301 |
* @return void |
| 1302 |
*/ |
| 1303 |
protected function show_title() { |
| 1304 |
if ( self::LIST_BASE_TABLE !== $this->table_name && (substr( $this->page, 0, 13 ) === \WP_Data_Access_Admin::PAGE_EXPLORER || \WP_Data_Access_Admin::PAGE_MAIN === $this->page) ) { |
| 1305 |
$this->subtitle = $this->title; |
| 1306 |
$this->title = 'Data Explorer'; |
| 1307 |
} |
| 1308 |
echo esc_attr( $this->title ); |
| 1309 |
} |
| 1310 |
|
| 1311 |
/** |
| 1312 |
* Show page sub title |
| 1313 |
* |
| 1314 |
* @return void |
| 1315 |
*/ |
| 1316 |
protected function show_sub_title() { |
| 1317 |
?> |
| 1318 |
<div class="wpda_subtitle"><strong><?php |
| 1319 |
echo wp_kses( $this->subtitle, array( |
| 1320 |
'span' => array( |
| 1321 |
'class' => array(), |
| 1322 |
), |
| 1323 |
) ); |
| 1324 |
?></strong></div> |
| 1325 |
<?php |
| 1326 |
} |
| 1327 |
|
| 1328 |
/** |
| 1329 |
* Show list table page |
| 1330 |
* |
| 1331 |
* Inside the list table page, the list table is shown. The necessary functionality to show the list table |
| 1332 |
* specifically is found in method {@see WPDA_List_Table::display()}. |
| 1333 |
* |
| 1334 |
* @since 1.0.0 |
| 1335 |
* |
| 1336 |
* @see WPDA_List_Table::display() |
| 1337 |
*/ |
| 1338 |
public function show() { |
| 1339 |
// Check for import requested. |
| 1340 |
if ( null !== $this->wpda_import ) { |
| 1341 |
$this->wpda_import->check_post(); |
| 1342 |
} |
| 1343 |
// Prepare list table items. |
| 1344 |
$this->prepare_items(); |
| 1345 |
// Show list table. |
| 1346 |
?> |
| 1347 |
|
| 1348 |
<div class="wrap<?php |
| 1349 |
echo ( is_admin() ? '' : ' wp-core-ui' ); |
| 1350 |
?>"> |
| 1351 |
<?php |
| 1352 |
if ( $this->show_page_title ) { |
| 1353 |
?> |
| 1354 |
<h1 class="wp-heading-inline"> |
| 1355 |
<?php |
| 1356 |
if ( self::LIST_BASE_TABLE !== $this->table_name && (WPDA::current_user_is_admin() && \WP_Data_Access_Admin::PAGE_MAIN === $this->page) ) { |
| 1357 |
?> |
| 1358 |
<a |
| 1359 |
href="?page=<?php |
| 1360 |
echo esc_attr( $this->page ); |
| 1361 |
?>" |
| 1362 |
class="dashicons dashicons-arrow-left-alt2 wpda_tooltip" |
| 1363 |
title="Data Explorer" |
| 1364 |
></a> |
| 1365 |
<?php |
| 1366 |
} |
| 1367 |
$this->show_title(); |
| 1368 |
?> |
| 1369 |
</h1> |
| 1370 |
<?php |
| 1371 |
} |
| 1372 |
?> |
| 1373 |
|
| 1374 |
<?php |
| 1375 |
if ( !is_admin() || 'wpda_wpdp_' === substr( $this->page, 0, 10 ) || WPDP::PAGE_TEMPLATES === $this->page || substr( $this->page, 0, 13 ) === \WP_Data_Access_Admin::PAGE_EXPLORER ) { |
| 1376 |
$this->add_header_button(); |
| 1377 |
} |
| 1378 |
$this->add_header_actions(); |
| 1379 |
if ( 'diehard' === $this->page ) { |
| 1380 |
$action_url = admin_url( 'admin-ajax.php' ); |
| 1381 |
} else { |
| 1382 |
$action_url = admin_url( 'admin.php' ); |
| 1383 |
} |
| 1384 |
?> |
| 1385 |
<div id="wpda_invisible_container" style="display:none;"> |
| 1386 |
<form id="wpda_main_export_form" method="post" action="<?php |
| 1387 |
echo esc_url( $action_url ); |
| 1388 |
?>?action=wpda_export" target="_blank"> |
| 1389 |
<input type="text" name="type" id="wpda_main_export_form__type" value="table" /> |
| 1390 |
<input type="text" name="wpdaschema_name" id="wpda_main_export_form__schema_name" /> |
| 1391 |
<input type="text" name="_wpnonce" id="wpda_main_export_form__wpnonce" /> |
| 1392 |
</form> |
| 1393 |
<form id="wpda_table_export_form" method="post" action="<?php |
| 1394 |
echo esc_url( $action_url ); |
| 1395 |
?>?action=wpda_export" target="_blank"> |
| 1396 |
<input type="text" name="type" id="wpda_table_export_form__type" value="table" /> |
| 1397 |
<input type="text" name="wpdaschema_name" id="wpda_table_export_form__schema_name" /> |
| 1398 |
<input type="text" name="table_names" id="wpda_table_export_form__table_names" /> |
| 1399 |
<input type="text" name="format_type" id="wpda_table_export_form__format_type" /> |
| 1400 |
<input type="text" name="include_table_settings" id="wpda_table_export_form__include_table_settings" /> |
| 1401 |
<input type="text" name="_wpnonce" id="wpda_table_export_form__wpnonce" /> |
| 1402 |
</form> |
| 1403 |
<form id="wpda_row_export_form" method="post" action="<?php |
| 1404 |
echo esc_url( $action_url ); |
| 1405 |
?>?action=wpda_export" target="_blank"> |
| 1406 |
<input type="text" name="type" id="wpda_row_export_form__type" value="row" /> |
| 1407 |
<input type="text" name="pid" id="wpda_row_export_form__pid" /> |
| 1408 |
<input type="text" name="wpdaschema_name" id="wpda_row_export_form__schema_name" /> |
| 1409 |
<input type="text" name="table_names" id="wpda_row_export_form__table_names" /> |
| 1410 |
<input type="text" name="mysql_set" id="wpda_row_export_form__mysql_set" /> |
| 1411 |
<input type="text" name="show_create" id="wpda_row_export_form__show_create" /> |
| 1412 |
<input type="text" name="show_comments" id="wpda_row_export_form__show_comments" /> |
| 1413 |
<input type="text" name="format_type" id="wpda_row_export_form__format_type" /> |
| 1414 |
<input type="text" name="_wpnonce" id="wpda_row_export_form__wpnonce" /> |
| 1415 |
</form> |
| 1416 |
</div> |
| 1417 |
<?php |
| 1418 |
// Add import container. |
| 1419 |
if ( null !== $this->wpda_import ) { |
| 1420 |
$this->wpda_import->add_container(); |
| 1421 |
} |
| 1422 |
// Add custom code before the list table. |
| 1423 |
do_action_ref_array( 'wpda_before_list_table', array($this) ); |
| 1424 |
// Prepare url. |
| 1425 |
if ( is_admin() ) { |
| 1426 |
$url = "?page={$this->page}"; |
| 1427 |
} else { |
| 1428 |
$url = ''; |
| 1429 |
} |
| 1430 |
?> |
| 1431 |
|
| 1432 |
<form id="wpda_main_form" |
| 1433 |
method="post" |
| 1434 |
action="<?php |
| 1435 |
echo esc_attr( $url ); |
| 1436 |
?>" |
| 1437 |
style=" |
| 1438 |
<?php |
| 1439 |
if ( '' !== $this->subtitle ) { |
| 1440 |
echo 'margin-top: 10px'; |
| 1441 |
} |
| 1442 |
?> |
| 1443 |
" |
| 1444 |
> |
| 1445 |
|
| 1446 |
<?php |
| 1447 |
$this->show_sub_title(); |
| 1448 |
if ( $this->search_box_enabled ) { |
| 1449 |
$this->search_box( __( 'search', 'wp-data-access' ), 'search_id' ); |
| 1450 |
} |
| 1451 |
$this->display(); |
| 1452 |
if ( '' === $this->get_bulk_actions() ) { |
| 1453 |
// Add action item containing value -1. This will allow sorting if no bulk action listbox is displayed. |
| 1454 |
?> |
| 1455 |
<input type="hidden" name="action" value="-1"/> |
| 1456 |
<?php |
| 1457 |
} |
| 1458 |
if ( self::LIST_BASE_TABLE !== $this->table_name ) { |
| 1459 |
?> |
| 1460 |
<input type="hidden" name="wpdaschema_name" |
| 1461 |
value="<?php |
| 1462 |
echo esc_attr( $this->schema_name ); |
| 1463 |
// input var okay. |
| 1464 |
?>"/> |
| 1465 |
<input type="hidden" name="table_name" |
| 1466 |
value="<?php |
| 1467 |
echo esc_attr( $this->table_name ); |
| 1468 |
// input var okay. |
| 1469 |
?>"/> |
| 1470 |
<?php |
| 1471 |
} |
| 1472 |
?> |
| 1473 |
<input id="wpda_main_form_orderby" type="hidden" name="orderby" |
| 1474 |
value="<?php |
| 1475 |
echo ( isset( $_REQUEST['orderby'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) ) : '' ); |
| 1476 |
// input var okay. |
| 1477 |
?>"/> |
| 1478 |
<input id="wpda_main_form_order" type="hidden" name="order" |
| 1479 |
value="<?php |
| 1480 |
echo ( isset( $_REQUEST['order'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) : '' ); |
| 1481 |
// input var okay. |
| 1482 |
?>"/> |
| 1483 |
<input id="wpda_main_form_post_mime_type" type="hidden" name="post_mime_type" |
| 1484 |
value="<?php |
| 1485 |
echo ( isset( $_REQUEST['post_mime_type'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['post_mime_type'] ) ) ) : '' ); |
| 1486 |
// input var okay. |
| 1487 |
?>"/> |
| 1488 |
<input id="wpda_main_form_detached" type="hidden" name="detached" |
| 1489 |
value="<?php |
| 1490 |
echo ( isset( $_REQUEST['detached'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['detached'] ) ) ) : '' ); |
| 1491 |
// input var okay. |
| 1492 |
?>"/> |
| 1493 |
<input id="wpda_main_db_schema" type="hidden" name="wpda_main_db_schema" |
| 1494 |
value="<?php |
| 1495 |
echo ( isset( $_REQUEST['wpda_main_db_schema'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_db_schema'] ) ) ) : '' ); |
| 1496 |
// input var okay. |
| 1497 |
?>"/> |
| 1498 |
<input id="wpda_main_favourites" type="hidden" name="wpda_main_favourites" |
| 1499 |
value="<?php |
| 1500 |
echo ( isset( $_REQUEST['wpda_main_favourites'] ) ? esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['wpda_main_favourites'] ) ) ) : '' ); |
| 1501 |
// input var okay. |
| 1502 |
?>"/> |
| 1503 |
<?php |
| 1504 |
wp_nonce_field( 'wpda-export-' . wp_json_encode( $this->table_name ), '_wpnonce', false ); |
| 1505 |
?> |
| 1506 |
<?php |
| 1507 |
wp_nonce_field( "wpda-delete-{$this->table_name}", '_wpnonce2', false ); |
| 1508 |
?> |
| 1509 |
<?php |
| 1510 |
if ( self::LIST_BASE_TABLE === $this->table_name ) { |
| 1511 |
wp_nonce_field( 'wpda-drop-' . WPDA::get_current_user_login(), '_wpnonce3', false ); |
| 1512 |
wp_nonce_field( 'wpda-truncate-' . WPDA::get_current_user_login(), '_wpnonce4', false ); |
| 1513 |
} |
| 1514 |
?> |
| 1515 |
<?php |
| 1516 |
foreach ( $_REQUEST as $key => $value ) { |
| 1517 |
if ( substr( $key, 0, 19 ) === 'wpda_search_column_' ) { |
| 1518 |
if ( is_array( $value ) ) { |
| 1519 |
foreach ( $value as $elem_key => $elem_value ) { |
| 1520 |
echo '<input type="hidden" name="' . esc_attr( $key ) . '[]" value="' . esc_attr( $elem_value ) . '"/>'; |
| 1521 |
} |
| 1522 |
} else { |
| 1523 |
echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '"/>'; |
| 1524 |
} |
| 1525 |
} |
| 1526 |
} |
| 1527 |
?> |
| 1528 |
</form> |
| 1529 |
</div> |
| 1530 |
<script type='text/javascript'> |
| 1531 |
jQuery(function() { |
| 1532 |
jQuery( '.wpda_tooltip' ).tooltip(); |
| 1533 |
// Add toolbar events |
| 1534 |
jQuery("#wpda_toolbar_icon_go_backup").on("click", function() { |
| 1535 |
jQuery("#wpda_goto_backup").submit(); |
| 1536 |
}); |
| 1537 |
jQuery("#wpda_toolbar_icon_add_row").on("click", function() { |
| 1538 |
jQuery("#wpda_new_row_table_name").val("<?php |
| 1539 |
echo esc_attr( $this->table_name ); |
| 1540 |
?>"); |
| 1541 |
jQuery("#wpda_new_row").submit(); |
| 1542 |
}); |
| 1543 |
jQuery("#wpda_toolbar_icon_add_publication").on("click", function() { |
| 1544 |
jQuery("#wpda_new_publication_table_name").val("<?php |
| 1545 |
echo esc_attr( $this->table_name ); |
| 1546 |
?>"); |
| 1547 |
jQuery("#wpda_new_publication").submit(); |
| 1548 |
}); |
| 1549 |
}); |
| 1550 |
</script> |
| 1551 |
<?php |
| 1552 |
$this->bind_action_buttons(); |
| 1553 |
?> |
| 1554 |
<?php |
| 1555 |
// Add custom code after the list table. |
| 1556 |
do_action_ref_array( 'wpda_after_list_table', array($this) ); |
| 1557 |
} |
| 1558 |
|
| 1559 |
/** |
| 1560 |
* Placeholder for subclasses to add additional actions |
| 1561 |
* |
| 1562 |
* @return void |
| 1563 |
*/ |
| 1564 |
protected function add_header_actions() { |
| 1565 |
} |
| 1566 |
|
| 1567 |
/** |
| 1568 |
* Bind javascript code to action buttons |
| 1569 |
* |
| 1570 |
* @since 1.6.2 |
| 1571 |
*/ |
| 1572 |
protected function bind_action_buttons() { |
| 1573 |
?> |
| 1574 |
<script type='text/javascript'> |
| 1575 |
jQuery(function () { |
| 1576 |
jQuery("#doaction").click(function () { |
| 1577 |
return wpda_action_button(); |
| 1578 |
}); |
| 1579 |
jQuery("#doaction2").click(function () { |
| 1580 |
return wpda_action_button(); |
| 1581 |
}); |
| 1582 |
}); |
| 1583 |
</script> |
| 1584 |
<?php |
| 1585 |
} |
| 1586 |
|
| 1587 |
/** |
| 1588 |
* Add button to page header |
| 1589 |
* |
| 1590 |
* By default "add new" and "import" buttons are added (depending on the settings). Overwrite this method to |
| 1591 |
* add your own buttons. |
| 1592 |
* |
| 1593 |
* @since 1.0.1 |
| 1594 |
*/ |
| 1595 |
protected function add_header_button() { |
| 1596 |
if ( 'off' === $this->allow_insert ) { |
| 1597 |
if ( null !== $this->wpda_import ) { |
| 1598 |
$this->wpda_import->add_button(); |
| 1599 |
} |
| 1600 |
} else { |
| 1601 |
//phpcs:ignore - 8.1 proof |
| 1602 |
if ( WPDA::is_wpda_table( $this->table_name ) || ('on' === WPDA::get_option( WPDA::OPTION_BE_ALLOW_INSERT ) && count( $this->wpda_list_columns->get_table_primary_key() )) > 0 ) { |
| 1603 |
$storage_type = ( WPDA::is_wpda_table( $this->table_name ) ? __( 'respository', 'wp-data-access' ) : __( 'table', 'wp-data-access' ) ); |
| 1604 |
// Prepare url. |
| 1605 |
if ( is_admin() ) { |
| 1606 |
$url = "?page={$this->page}"; |
| 1607 |
} else { |
| 1608 |
$url = ''; |
| 1609 |
} |
| 1610 |
?> |
| 1611 |
<form |
| 1612 |
method="post" |
| 1613 |
action="<?php |
| 1614 |
echo esc_attr( $url ); |
| 1615 |
?>" |
| 1616 |
style="display: inline-block; vertical-align: baseline;" |
| 1617 |
> |
| 1618 |
<div> |
| 1619 |
<input type="hidden" name="wpdaschema_name" |
| 1620 |
value="<?php |
| 1621 |
echo esc_attr( $this->schema_name ); |
| 1622 |
// input var okay. |
| 1623 |
?>"/> |
| 1624 |
<input type="hidden" name="table_name" |
| 1625 |
value="<?php |
| 1626 |
echo esc_attr( $this->table_name ); |
| 1627 |
// input var okay. |
| 1628 |
?>"/> |
| 1629 |
<input type="hidden" name="action" value="new"> |
| 1630 |
<button type="submit" class="page-title-action wpda_tooltip" |
| 1631 |
title="<?php |
| 1632 |
echo sprintf( __( 'Add new %1$s to %2$s', 'wp-data-access' ), esc_attr( $this->_args['singular'] ), esc_attr( $storage_type ) ); |
| 1633 |
?>" |
| 1634 |
> |
| 1635 |
<i class="fas fa-plus-circle wpda_icon_on_button"></i> |
| 1636 |
<?php |
| 1637 |
echo __( 'Add New', 'wp-data-access' ); |
| 1638 |
?> |
| 1639 |
</button> |
| 1640 |
<?php |
| 1641 |
// Add import button to title. |
| 1642 |
if ( null !== $this->wpda_import ) { |
| 1643 |
$this->wpda_import->add_button(); |
| 1644 |
} |
| 1645 |
?> |
| 1646 |
</div> |
| 1647 |
</form> |
| 1648 |
<?php |
| 1649 |
} else { |
| 1650 |
// Add import button to title. |
| 1651 |
if ( null !== $this->wpda_import ) { |
| 1652 |
$this->wpda_import->add_button(); |
| 1653 |
} |
| 1654 |
} |
| 1655 |
} |
| 1656 |
} |
| 1657 |
|
| 1658 |
/** |
| 1659 |
* Prepares the list of items for displaying |
| 1660 |
* |
| 1661 |
* Overwrites WP_List_Table::prepare_items() |
| 1662 |
* |
| 1663 |
* @since 1.0.0 |
| 1664 |
*/ |
| 1665 |
public function prepare_items() { |
| 1666 |
// Construct where clause with search values provided in the search box. |
| 1667 |
// Result (where clause) is written to $this->where. |
| 1668 |
$this->construct_where_clause(); |
| 1669 |
$this->process_bulk_action(); |
| 1670 |
if ( is_admin() ) { |
| 1671 |
if ( $this->table_name === self::LIST_BASE_TABLE ) { |
| 1672 |
$option = 'wpda_rows_per_page_' . str_replace( '.', '_', self::LIST_BASE_TABLE ); |
| 1673 |
} else { |
| 1674 |
$option = 'wpda_rows_per_page_' . str_replace( '.', '_', $this->schema_name . $this->table_name ); |
| 1675 |
} |
| 1676 |
$this->items_per_page = $this->get_items_per_page( $option, WPDA::get_option( WPDA::OPTION_BE_PAGINATION ) ); |
| 1677 |
} else { |
| 1678 |
$this->items_per_page = WPDA::get_option( WPDA::OPTION_FE_PAGINATION ); |
| 1679 |
} |
| 1680 |
$this->current_page = $this->get_pagenum(); |
| 1681 |
$total_items = $this->record_count(); |
| 1682 |
$total_pages = ceil( $total_items / $this->items_per_page ); |
| 1683 |
if ( $this->search_value !== $this->search_value_old ) { |
| 1684 |
$this->current_page = 1; |
| 1685 |
} |
| 1686 |
if ( $this->current_page > $total_pages ) { |
| 1687 |
$this->current_page = $total_pages; |
| 1688 |
} |
| 1689 |
$this->set_pagination_args( array( |
| 1690 |
'total_items' => $total_items, |
| 1691 |
'total_pages' => $total_pages, |
| 1692 |
'per_page' => $this->items_per_page, |
| 1693 |
) ); |
| 1694 |
$this->get_rows(); |
| 1695 |
// Written to $this->items in base class (WP_List_Table). |
| 1696 |
$columns = $this->get_columns(); |
| 1697 |
$hidden = $this->get_hidden_columns(); |
| 1698 |
if ( false === $hidden ) { |
| 1699 |
if ( is_admin() ) { |
| 1700 |
// List table in backend. |
| 1701 |
if ( self::LIST_BASE_TABLE === $this->table_name ) { |
| 1702 |
$table_name = str_replace( '.', '_', self::LIST_BASE_TABLE ); |
| 1703 |
} else { |
| 1704 |
global $wpdb; |
| 1705 |
if ( $this->schema_name === $wpdb->dbname && WPDA_CSV_Uploads_Model::get_base_table_name() === $this->table_name ) { |
| 1706 |
$table_name = $this->table_name; |
| 1707 |
// csv upload = exception. |
| 1708 |
} else { |
| 1709 |
$table_name = str_replace( '.', '_', $this->schema_name . $this->table_name ); |
| 1710 |
} |
| 1711 |
} |
| 1712 |
$hidden = get_user_option( WPDA_List_View::HIDDENCOLUMNS_PREFIX . get_current_screen()->id . $table_name ); |
| 1713 |
if ( false === $hidden ) { |
| 1714 |
$hidden = array(); |
| 1715 |
} |
| 1716 |
} |
| 1717 |
} |
| 1718 |
if ( !is_array( $hidden ) ) { |
| 1719 |
$hidden = array(); |
| 1720 |
} |
| 1721 |
$sortable = $this->get_sortable_columns(); |
| 1722 |
$primary = $this->get_primary_column(); |
| 1723 |
$this->_column_headers = array( |
| 1724 |
$columns, |
| 1725 |
$hidden, |
| 1726 |
$sortable, |
| 1727 |
$primary |
| 1728 |
); |
| 1729 |
} |
| 1730 |
|
| 1731 |
/** |
| 1732 |
* Build where clause |
| 1733 |
* |
| 1734 |
* Arguments might come from the URL so we need to check for SQL injection and use prepare. The resulting |
| 1735 |
* where clause is written directly to member $this->where. |
| 1736 |
* |
| 1737 |
* @since 1.0.0 |
| 1738 |
*/ |
| 1739 |
protected function construct_where_clause() { |
| 1740 |
$whereclause = $this->get_where_clause(); |
| 1741 |
if ( '' !== $whereclause ) { |
| 1742 |
$this->where = ( '' === $this->where ? " where ({$whereclause}) " : " {$this->where} and ({$whereclause}) " ); |
| 1743 |
} |
| 1744 |
} |
| 1745 |
|
| 1746 |
/** |
| 1747 |
* Returns the where clause (uses filters if available) |
| 1748 |
* |
| 1749 |
* @return string |
| 1750 |
*/ |
| 1751 |
public function get_where_clause() { |
| 1752 |
return WPDA::construct_where_clause( |
| 1753 |
$this->schema_name, |
| 1754 |
$this->table_name, |
| 1755 |
$this->wpda_list_columns->get_searchable_table_columns(), |
| 1756 |
$this->search_value, |
| 1757 |
isset( $_REQUEST['wpda_c'] ) && 'true' === $_REQUEST['wpda_c'] |
| 1758 |
); |
| 1759 |
} |
| 1760 |
|
| 1761 |
/** |
| 1762 |
* Process bulk actions |
| 1763 |
* |
| 1764 |
* Delete and bulk-delete actions use the primary key list as a reference. Before performing the actual delete |
| 1765 |
* statement(s) we'll check the provided column names against the data dictionary. This will protect us against |
| 1766 |
* SQL injection attacks. |
| 1767 |
* |
| 1768 |
* For export actions table names will not be checked here. They are handed over WPDA_Export where the validity |
| 1769 |
* and access rights are checked anyway (to be safe). |
| 1770 |
* |
| 1771 |
* All actions can be processed only with a valid wpnonce value. |
| 1772 |
* |
| 1773 |
* To perform actions the user must have the appropriate rights. |
| 1774 |
* |
| 1775 |
* @since 1.0.0 |
| 1776 |
*/ |
| 1777 |
public function process_bulk_action() { |
| 1778 |
switch ( $this->current_action() ) { |
| 1779 |
case 'delete': |
| 1780 |
// Check access rights. |
| 1781 |
if ( 'on' !== $this->allow_delete ) { |
| 1782 |
// Deleting records from list table is not allowed. |
| 1783 |
wp_die( __( 'ERROR: Not authorized [delete not allowed]', 'wp-data-access' ) ); |
| 1784 |
} |
| 1785 |
// Prepare wp_nonce action security check. |
| 1786 |
$wp_nonce_action = "wpda-delete-{$this->table_name}"; |
| 1787 |
$row_to_be_deleted = array(); |
| 1788 |
// Gonna hold the row to be deleted. |
| 1789 |
$i = 0; |
| 1790 |
// Index, necessary for multi column keys. |
| 1791 |
// Check all key columns. |
| 1792 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $key ) { |
| 1793 |
// Check if key is available. |
| 1794 |
if ( !isset( $_REQUEST[$key] ) ) { |
| 1795 |
// input var okay. |
| 1796 |
wp_die( __( 'ERROR: Invalid URL [missing primary key values]', 'wp-data-access' ) ); |
| 1797 |
} |
| 1798 |
// Write key value pair to array. |
| 1799 |
$row_to_be_deleted[$i]['key'] = $key; |
| 1800 |
$row_to_be_deleted[$i]['value'] = sanitize_text_field( wp_unslash( $_REQUEST[$key] ) ); |
| 1801 |
// input var okay. |
| 1802 |
$i++; |
| 1803 |
// Add key values to wp_nonce action. |
| 1804 |
$wp_nonce_action .= '-' . sanitize_text_field( wp_unslash( $_REQUEST[$key] ) ); |
| 1805 |
// input var okay. |
| 1806 |
} |
| 1807 |
// Check if delete is allowed. |
| 1808 |
$wp_nonce = ( isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '' ); |
| 1809 |
// input var okay. |
| 1810 |
if ( !wp_verify_nonce( $wp_nonce, $wp_nonce_action ) ) { |
| 1811 |
wp_die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); |
| 1812 |
} |
| 1813 |
// All key column values available: delete record. |
| 1814 |
// Prepare named array for delete operation. |
| 1815 |
$next_row_to_be_deleted = array(); |
| 1816 |
$count_rows = count( $row_to_be_deleted ); |
| 1817 |
//phpcs:ignore - 8.1 proof |
| 1818 |
for ($i = 0; $i < $count_rows; $i++) { |
| 1819 |
$next_row_to_be_deleted[$row_to_be_deleted[$i]['key']] = $row_to_be_deleted[$i]['value']; |
| 1820 |
} |
| 1821 |
$engine = WPDA::get_table_engine( $this->schema_name, $this->table_name ); |
| 1822 |
if ( $this->delete_row( $next_row_to_be_deleted, $engine ) ) { |
| 1823 |
$msg = new WPDA_Message_Box(array( |
| 1824 |
'message_text' => __( 'Row deleted', 'wp-data-access' ), |
| 1825 |
)); |
| 1826 |
$msg->box(); |
| 1827 |
} else { |
| 1828 |
$msg = new WPDA_Message_Box(array( |
| 1829 |
'message_text' => __( 'Could not delete row', 'wp-data-access' ), |
| 1830 |
'message_type' => 'error', |
| 1831 |
'message_is_dismissible' => false, |
| 1832 |
)); |
| 1833 |
$msg->box(); |
| 1834 |
} |
| 1835 |
break; |
| 1836 |
case 'bulk-delete': |
| 1837 |
// Check access rights. |
| 1838 |
if ( 'on' !== $this->allow_delete ) { |
| 1839 |
// Deleting records from list table is not allowed. |
| 1840 |
die( __( 'ERROR: Not authorized [delete not allowed]', 'wp-data-access' ) ); |
| 1841 |
} |
| 1842 |
// We first need to check if all the necessary information is available. |
| 1843 |
if ( !isset( $_REQUEST['bulk-selected'] ) ) { |
| 1844 |
// input var okay. |
| 1845 |
// Nothing to delete. |
| 1846 |
$msg = new WPDA_Message_Box(array( |
| 1847 |
'message_text' => __( 'Nothing to delete', 'wp-data-access' ), |
| 1848 |
)); |
| 1849 |
$msg->box(); |
| 1850 |
return; |
| 1851 |
} |
| 1852 |
// Check if delete is allowed. |
| 1853 |
$wp_nonce_action = "wpda-delete-{$this->table_name}"; |
| 1854 |
$wp_nonce = ( isset( $_REQUEST['_wpnonce2'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce2'] ) ) : '' ); |
| 1855 |
// input var okay. |
| 1856 |
if ( !wp_verify_nonce( $wp_nonce, $wp_nonce_action ) ) { |
| 1857 |
die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); |
| 1858 |
} |
| 1859 |
$bulk_rows = (array) $_REQUEST['bulk-selected']; |
| 1860 |
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput |
| 1861 |
$no_rows = count( $bulk_rows ); |
| 1862 |
// # rows to be deleted. //phpcs:ignore - 8.1 proof being safe |
| 1863 |
$rows_to_be_deleted = array(); |
| 1864 |
// Gonna hold rows to be deleted. |
| 1865 |
for ($i = 0; $i < $no_rows; $i++) { |
| 1866 |
// Write "json" to named array. Need to strip slashes twice. Once for the normal conversion |
| 1867 |
// and once extra for the pre-conversion of double quotes in method column_cb(). |
| 1868 |
$row_object = json_decode( stripslashes( stripslashes( $bulk_rows[$i] ) ), true ); |
| 1869 |
if ( $row_object ) { |
| 1870 |
$j = 0; |
| 1871 |
// Index used to build array. |
| 1872 |
// Check all key columns. |
| 1873 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $key ) { |
| 1874 |
// Check if key is available. |
| 1875 |
if ( !isset( $row_object[$key] ) ) { |
| 1876 |
wp_die( __( 'ERROR: Invalid URL [missing primary key values]', 'wp-data-access' ) ); |
| 1877 |
} |
| 1878 |
// Write key value pair to array. |
| 1879 |
$rows_to_be_deleted[$i][$j]['key'] = $key; |
| 1880 |
$rows_to_be_deleted[$i][$j]['value'] = $row_object[$key]; |
| 1881 |
$j++; |
| 1882 |
} |
| 1883 |
} |
| 1884 |
} |
| 1885 |
// Looks like everything is there. Delete records from table... |
| 1886 |
$no_key_cols = count( $this->wpda_list_columns->get_table_primary_key() ); |
| 1887 |
//phpcs:ignore - 8.1 proof |
| 1888 |
$rows_successfully_deleted = 0; |
| 1889 |
// Number of rows successfully deleted. |
| 1890 |
$rows_with_errors = 0; |
| 1891 |
// Number of rows that could not be deleted. |
| 1892 |
$engine = WPDA::get_table_engine( $this->schema_name, $this->table_name ); |
| 1893 |
for ($i = 0; $i < $no_rows; $i++) { |
| 1894 |
// Prepare named array for delete operation. |
| 1895 |
$next_row_to_be_deleted = array(); |
| 1896 |
$row_found = true; |
| 1897 |
for ($j = 0; $j < $no_key_cols; $j++) { |
| 1898 |
if ( isset( $rows_to_be_deleted[$i][$j]['key'] ) ) { |
| 1899 |
$next_row_to_be_deleted[$rows_to_be_deleted[$i][$j]['key']] = $rows_to_be_deleted[$i][$j]['value']; |
| 1900 |
} else { |
| 1901 |
$row_found = false; |
| 1902 |
} |
| 1903 |
} |
| 1904 |
if ( $row_found ) { |
| 1905 |
if ( $this->delete_row( $next_row_to_be_deleted, $engine ) ) { |
| 1906 |
// Row(s) successfully deleted. |
| 1907 |
$rows_successfully_deleted++; |
| 1908 |
} else { |
| 1909 |
// An error occurred during the delete operation: increase error count. |
| 1910 |
$rows_with_errors++; |
| 1911 |
} |
| 1912 |
} else { |
| 1913 |
// An error occurred during the delete operation: increase error count. |
| 1914 |
$rows_with_errors++; |
| 1915 |
} |
| 1916 |
} |
| 1917 |
// Inform user about the results of the operation. |
| 1918 |
$message = ''; |
| 1919 |
if ( 1 === $rows_successfully_deleted ) { |
| 1920 |
$message = __( 'Row deleted', 'wp-data-access' ); |
| 1921 |
} elseif ( $rows_successfully_deleted > 1 ) { |
| 1922 |
$message = "{$rows_successfully_deleted} " . __( 'rows deleted', 'wp-data-access' ); |
| 1923 |
} |
| 1924 |
if ( '' !== $message ) { |
| 1925 |
$msg = new WPDA_Message_Box(array( |
| 1926 |
'message_text' => $message, |
| 1927 |
)); |
| 1928 |
$msg->box(); |
| 1929 |
} |
| 1930 |
$message = ''; |
| 1931 |
if ( $rows_with_errors > 0 ) { |
| 1932 |
$message = __( 'Not all rows have been deleted', 'wp-data-access' ); |
| 1933 |
} |
| 1934 |
if ( '' !== $message ) { |
| 1935 |
$msg = new WPDA_Message_Box(array( |
| 1936 |
'message_text' => $message, |
| 1937 |
'message_type' => 'error', |
| 1938 |
'message_is_dismissible' => false, |
| 1939 |
)); |
| 1940 |
$msg->box(); |
| 1941 |
} |
| 1942 |
break; |
| 1943 |
case 'bulk-export': |
| 1944 |
case 'bulk-export-xml': |
| 1945 |
case 'bulk-export-json': |
| 1946 |
case 'bulk-export-excel': |
| 1947 |
case 'bulk-export-csv': |
| 1948 |
// Check access rights. |
| 1949 |
if ( !WPDA::is_wpda_table( $this->table_name ) ) { |
| 1950 |
if ( 'on' !== WPDA::get_option( WPDA::OPTION_BE_EXPORT_ROWS ) ) { |
| 1951 |
// Exporting rows from list table is not allowed. |
| 1952 |
die( __( 'ERROR: Not authorized [export not allowed]', 'wp-data-access' ) ); |
| 1953 |
} |
| 1954 |
} |
| 1955 |
// We first need to check if all the necessary information is available. |
| 1956 |
if ( !isset( $_REQUEST['bulk-selected'] ) ) { |
| 1957 |
// input var okay. |
| 1958 |
// Nothing to export. |
| 1959 |
$msg = new WPDA_Message_Box(array( |
| 1960 |
'message_text' => __( 'Nothing to export', 'wp-data-access' ), |
| 1961 |
)); |
| 1962 |
$msg->box(); |
| 1963 |
return; |
| 1964 |
} |
| 1965 |
// Check if export is allowed. |
| 1966 |
$wp_nonce = ( isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '' ); |
| 1967 |
// input var okay. |
| 1968 |
if ( !wp_verify_nonce( $wp_nonce, 'wpda-export-' . wp_json_encode( $this->table_name ) ) ) { |
| 1969 |
die( __( 'ERROR: Not authorized', 'wp-data-access' ) ); |
| 1970 |
} |
| 1971 |
$bulk_rows = (array) $_REQUEST['bulk-selected']; |
| 1972 |
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput |
| 1973 |
$no_rows = count( $bulk_rows ); |
| 1974 |
// # rows to be exported. //phpcs:ignore - 8.1 proof being safe |
| 1975 |
$format_type = ''; |
| 1976 |
switch ( $this->current_action() ) { |
| 1977 |
case 'bulk-export-xml': |
| 1978 |
$format_type = 'xml'; |
| 1979 |
break; |
| 1980 |
case 'bulk-export-json': |
| 1981 |
$format_type = 'json'; |
| 1982 |
break; |
| 1983 |
case 'bulk-export-excel': |
| 1984 |
$format_type = 'excel'; |
| 1985 |
break; |
| 1986 |
case 'bulk-export-csv': |
| 1987 |
$format_type = 'csv'; |
| 1988 |
} |
| 1989 |
if ( 'diehard' === $this->page && null !== $this->pid ) { |
| 1990 |
$wp_nonce = wp_create_nonce( "wpda-export-{$this->pid}" ); |
| 1991 |
$submit_schema_name = ''; |
| 1992 |
$submit_table_name = ''; |
| 1993 |
} else { |
| 1994 |
$submit_schema_name = $this->schema_name; |
| 1995 |
$submit_table_name = $this->table_name; |
| 1996 |
} |
| 1997 |
$j = 0; |
| 1998 |
$columns = array(); |
| 1999 |
for ($i = 0; $i < $no_rows; $i++) { |
| 2000 |
// Write "json" to named array. Need to strip slashes twice. Once for the normal conversion |
| 2001 |
// and once extra for the pre-conversion of double quotes in method column_cb(). |
| 2002 |
$row_object = json_decode( stripslashes( stripslashes( $bulk_rows[$i] ) ), true ); |
| 2003 |
if ( $row_object ) { |
| 2004 |
// Check all key columns. |
| 2005 |
foreach ( $this->wpda_list_columns->get_table_primary_key() as $key ) { |
| 2006 |
// Check if key is available. |
| 2007 |
if ( !isset( $row_object[$key] ) ) { |
| 2008 |
wp_die( __( 'ERROR: Invalid URL', 'wp-data-access' ) ); |
| 2009 |
} |
| 2010 |
if ( !isset( $columns[$key] ) ) { |
| 2011 |
$columns[$key] = array(); |
| 2012 |
} |
| 2013 |
$columns[$key][] = $row_object[$key]; |
| 2014 |
} |
| 2015 |
$j++; |
| 2016 |
} |
| 2017 |
} |
| 2018 |
?> |
| 2019 |
<script type="application/javascript"> |
| 2020 |
jQuery(function() { |
| 2021 |
wpda_row_export( |
| 2022 |
'<?php |
| 2023 |
echo esc_attr( $this->pid ); |
| 2024 |
?>', |
| 2025 |
'<?php |
| 2026 |
echo esc_attr( $submit_schema_name ); |
| 2027 |
?>', |
| 2028 |
'<?php |
| 2029 |
echo esc_attr( $submit_table_name ); |
| 2030 |
?>', |
| 2031 |
'<?php |
| 2032 |
echo esc_attr( $wp_nonce ); |
| 2033 |
?>', |
| 2034 |
'<?php |
| 2035 |
echo esc_attr( $format_type ); |
| 2036 |
?>', |
| 2037 |
'off', |
| 2038 |
'off', |
| 2039 |
'off', |
| 2040 |
'<?php |
| 2041 |
echo wp_json_encode( $columns ); |
| 2042 |
?>' |
| 2043 |
); |
| 2044 |
}); |
| 2045 |
</script> |
| 2046 |
<?php |
| 2047 |
} |
| 2048 |
} |
| 2049 |
|
| 2050 |
/** |
| 2051 |
* Delete record from database table |
| 2052 |
* |
| 2053 |
* The table must have a primary key and the values for all primary key columns must be provided in the |
| 2054 |
* request. The where clause must be a named array in format: ['column_name'] = 'value' |
| 2055 |
* |
| 2056 |
* @param string $where where clause. |
| 2057 |
* @param string $engine connect or empty. |
| 2058 |
* |
| 2059 |
* @return mixed |
| 2060 |
* @since 1.0.0 |
| 2061 |
*/ |
| 2062 |
public function delete_row( $where, $engine = '' ) { |
| 2063 |
$wpdadb = WPDADB::get_db_connection( $this->schema_name ); |
| 2064 |
if ( null === $wpdadb ) { |
| 2065 |
if ( is_admin() ) { |
| 2066 |
wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2067 |
} else { |
| 2068 |
die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2069 |
} |
| 2070 |
} |
| 2071 |
$row_deleted = $wpdadb->delete( $this->table_name, $where ); |
| 2072 |
if ( 'connect' === strtolower( $engine ) ) { |
| 2073 |
// Connect engine does not return number of rows deleted. |
| 2074 |
// Presuming delete was successful when no error message was returned. |
| 2075 |
return '' === $wpdadb->last_error; |
| 2076 |
} |
| 2077 |
return $row_deleted; |
| 2078 |
} |
| 2079 |
|
| 2080 |
/** |
| 2081 |
* Number of records in database table |
| 2082 |
* |
| 2083 |
* Returns the number of records in the database table. Where clause must be prepared in advance and written |
| 2084 |
* to $this->where ({@see WPDA_List_Table::construct_where_clause()}) |
| 2085 |
* |
| 2086 |
* @return null|string Number of rows in the current table |
| 2087 |
* @since 1.0.0 |
| 2088 |
*/ |
| 2089 |
public function record_count() { |
| 2090 |
if ( !$this->row_count_estimate['do_real_count'] && '' === $this->where ) { |
| 2091 |
// Use estimate row count. |
| 2092 |
return $this->table_rows; |
| 2093 |
} |
| 2094 |
// Get real row count. |
| 2095 |
$wpdadb = WPDADB::get_db_connection( $this->schema_name ); |
| 2096 |
if ( null === $wpdadb ) { |
| 2097 |
if ( is_admin() ) { |
| 2098 |
wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2099 |
} else { |
| 2100 |
die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2101 |
} |
| 2102 |
} |
| 2103 |
if ( '' === $this->schema_name ) { |
| 2104 |
$query = "\n\t\t\t\t\tselect count(*)\n\t\t\t\t\tfrom `{$this->table_name}`\n\t\t\t\t\t{$this->where}\n\t\t\t\t"; |
| 2105 |
} else { |
| 2106 |
if ( self::LIST_BASE_TABLE === $this->table_name ) { |
| 2107 |
$query = "\n\t\t\t\t\t\tselect count(*)\n\t\t\t\t\t\tfrom {$this->table_name}\n\t\t\t\t\t\t{$this->where}\n\t\t\t\t\t"; |
| 2108 |
} else { |
| 2109 |
$query = "\n\t\t\t\t\t\tselect count(*)\n\t\t\t\t\t\tfrom `{$wpdadb->dbname}`.`{$this->table_name}`\n\t\t\t\t\t\t{$this->where}\n\t\t\t\t\t"; |
| 2110 |
} |
| 2111 |
} |
| 2112 |
return $wpdadb->get_var( $query ); |
| 2113 |
// phpcs:ignore Standard.Category.SniffName.ErrorCode |
| 2114 |
} |
| 2115 |
|
| 2116 |
/** |
| 2117 |
* Perform query to retrieve rows from database |
| 2118 |
* |
| 2119 |
* Where clause must be prepared in advance and written to $this->where |
| 2120 |
* ({@see WPDA_List_Table::construct_where_clause()}). |
| 2121 |
* |
| 2122 |
* No return value. Result is directly written to $this->items (base class member). |
| 2123 |
* |
| 2124 |
* @since 1.0.0 |
| 2125 |
*/ |
| 2126 |
public function get_rows() { |
| 2127 |
$wpdadb = WPDADB::get_db_connection( $this->schema_name ); |
| 2128 |
if ( null === $wpdadb ) { |
| 2129 |
if ( is_admin() ) { |
| 2130 |
wp_die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2131 |
} else { |
| 2132 |
die( sprintf( __( 'ERROR - Remote database %s not available', 'wp-data-access' ), esc_attr( $this->schema_name ) ) ); |
| 2133 |
} |
| 2134 |
} |
| 2135 |
// Selected columns cannot be changed by the user at this time. No check for SQL injection needed now. |
| 2136 |
// This might change in the future when users are allowed to change or set this value. A method named |
| 2137 |
// column_exists() in WPDA_Dictionary_Checks is already available for this purpose. |
| 2138 |
$selected_columns = '*'; |
| 2139 |
if ( isset( $this->columns_queried ) ) { |
| 2140 |
$selected_columns = implode( ',', $this->columns_queried ); |
| 2141 |
} |
| 2142 |
if ( isset( $this->wpda_table_settings->hyperlinks ) ) { |
| 2143 |
$i = 0; |
| 2144 |
foreach ( $this->wpda_table_settings->hyperlinks as $hyperlink ) { |
| 2145 |
$skip_column = false; |
| 2146 |
if ( null !== $this->wpda_project_table_settings ) { |
| 2147 |
$hyperlink_label = $hyperlink->hyperlink_label; |
| 2148 |
if ( !property_exists( $this, 'is_child' ) ) { |
| 2149 |
if ( isset( $this->wpda_project_table_settings->hyperlinks_parent->{$hyperlink_label} ) && !$this->wpda_project_table_settings->hyperlinks_parent->{$hyperlink_label} ) { |
| 2150 |
$skip_column = true; |
| 2151 |
} |
| 2152 |
} else { |
| 2153 |
if ( isset( $this->wpda_project_table_settings->hyperlinks_child->{$hyperlink_label} ) && !$this->wpda_project_table_settings->hyperlinks_child->{$hyperlink_label} ) { |
| 2154 |
$skip_column = true; |
| 2155 |
} |
| 2156 |
} |
| 2157 |
} |
| 2158 |
if ( !$skip_column && isset( $hyperlink->hyperlink_list ) && true === $hyperlink->hyperlink_list ) { |
| 2159 |
$hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' ); |
| 2160 |
$hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' ); |
| 2161 |
if ( '' !== $hyperlink_label && '' !== $hyperlink_html ) { |
| 2162 |
// Add hyperlink columns (details are added in method column_default). |
| 2163 |
$selected_columns .= ", '' as wpda_hyperlink_{$i}"; |
| 2164 |
} |
| 2165 |
} |
| 2166 |
$i++; |
| 2167 |
} |
| 2168 |
} |
| 2169 |
if ( '' === $this->schema_name ) { |
| 2170 |
$query = "\n\t\t\t\t\tselect {$selected_columns}\n\t\t\t\t\tfrom `{$this->table_name}`\n\t\t\t\t\t{$this->where}\n\t\t\t\t"; |
| 2171 |
} else { |
| 2172 |
if ( self::LIST_BASE_TABLE === $this->table_name ) { |
| 2173 |
$query = "\n\t\t\t\t\t\tselect {$selected_columns}\n\t\t\t\t\t\tfrom {$this->table_name}\n\t\t\t\t\t\t{$this->where}\n\t\t\t\t\t"; |
| 2174 |
} else { |
| 2175 |
$query = "\n\t\t\t\t\t\tselect {$selected_columns}\n\t\t\t\t\t\tfrom `{$wpdadb->dbname}`.`{$this->table_name}`\n\t\t\t\t\t\t{$this->where}\n\t\t\t\t\t"; |
| 2176 |
} |
| 2177 |
} |
| 2178 |
$query .= $this->get_order_by(); |
| 2179 |
// Add order by. |
| 2180 |
$query .= " limit {$this->items_per_page}"; |
| 2181 |
$offset = ($this->current_page - 1) * $this->items_per_page; |
| 2182 |
if ( $offset > 0 ) { |
| 2183 |
$query .= " offset {$offset}"; |
| 2184 |
} |
| 2185 |
// Debug query. |
| 2186 |
// var_dump( $query ); |
| 2187 |
$this->items = $wpdadb->get_results( $query, 'ARRAY_A' ); |
| 2188 |
// phpcs:ignore Standard.Category.SniffName.ErrorCode |
| 2189 |
} |
| 2190 |
|
| 2191 |
/** |
| 2192 |
* Get order by |
| 2193 |
* |
| 2194 |
* @return string|void |
| 2195 |
*/ |
| 2196 |
protected function get_order_by() { |
| 2197 |
if ( !empty( $_REQUEST['orderby'] ) ) { |
| 2198 |
$orderby_arg = sanitize_sql_orderby( wp_unslash( $_REQUEST['orderby'] ) ); |
| 2199 |
// input var okay. |
| 2200 |
if ( !empty( $_REQUEST['order'] ) ) { |
| 2201 |
$order_arg = sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ); |
| 2202 |
// input var okay. |
| 2203 |
} else { |
| 2204 |
$order_arg = ''; |
| 2205 |
} |
| 2206 |
$columns = $this->get_sortable_columns(); |
| 2207 |
// Check column name for SQL injection. |
| 2208 |
if ( isset( $columns[$orderby_arg] ) || $this->wpda_data_dictionary->column_exists( $orderby_arg ) ) { |
| 2209 |
// Column name exists in current table, safely continue... |
| 2210 |
$orderby = " order by {$orderby_arg}"; |
| 2211 |
// Prevent SQL injection for order. If 'desc' is found result will be ordered desc. In all other |
| 2212 |
// cases we'll order asc. |
| 2213 |
$orderby .= ( strtolower( trim( $order_arg ) ) === 'desc' ? ' desc' : ' asc' ); |
| 2214 |
return $orderby; |
| 2215 |
} else { |
| 2216 |
// The user provided a column name which is not in the table. Most probably the result of a |
| 2217 |
// SQL injection attack, so let's terminate. |
| 2218 |
wp_die( __( 'ERROR: Invalid URL [invalid column name]', 'wp-data-access' ) ); |
| 2219 |
} |
| 2220 |
} else { |
| 2221 |
return ''; |
| 2222 |
} |
| 2223 |
} |
| 2224 |
|
| 2225 |
/** |
| 2226 |
* Return an associative array of columns |
| 2227 |
* |
| 2228 |
* @return array |
| 2229 |
* @since 1.0.0 |
| 2230 |
*/ |
| 2231 |
public function get_columns() { |
| 2232 |
if ( null !== $this->wpda_cached_columns && is_array( $this->wpda_cached_columns ) ) { |
| 2233 |
return $this->wpda_cached_columns; |
| 2234 |
} |
| 2235 |
$columns = array(); |
| 2236 |
if ( $this->bulk_actions_enabled ) { |
| 2237 |
if ( !empty( $this->wpda_list_columns->get_table_primary_key() ) ) { |
| 2238 |
// Tables has primary key: bulk actions allowed! |
| 2239 |
// Primary key is used to ensure uniqueness. |
| 2240 |
$actions = $this->get_bulk_actions(); |
| 2241 |
if ( is_array( $actions ) && 0 < count( $actions ) ) { |
| 2242 |
//phpcs:ignore - 8.1 proof |
| 2243 |
$columns = array( |
| 2244 |
'cb' => '<input type="checkbox" />', |
| 2245 |
); |
| 2246 |
} |
| 2247 |
} |
| 2248 |
} |
| 2249 |
$columnlist = $this->wpda_list_columns->get_table_column_headers(); |
| 2250 |
foreach ( $columnlist as $key => $value ) { |
| 2251 |
$columns[$key] = $value; |
| 2252 |
// Check for alternative column header. |
| 2253 |
if ( isset( $this->column_headers[$key] ) ) { |
| 2254 |
// Alternative header found: use it. |
| 2255 |
$columns[$key] = $this->column_headers[$key]; |
| 2256 |
} else { |
| 2257 |
// Default behaviour: get column header from generated label. |
| 2258 |
$columns[$key] = $this->wpda_list_columns->get_column_label( $key ); |
| 2259 |
} |
| 2260 |
} |
| 2261 |
if ( isset( $this->wpda_table_settings->hyperlinks ) ) { |
| 2262 |
$i = 0; |
| 2263 |
foreach ( $this->wpda_table_settings->hyperlinks as $hyperlink ) { |
| 2264 |
if ( isset( $hyperlink->hyperlink_list ) && true === $hyperlink->hyperlink_list ) { |
| 2265 |
$skip_column = false; |
| 2266 |
if ( null !== $this->wpda_project_table_settings ) { |
| 2267 |
$hyperlink_label = $hyperlink->hyperlink_label; |
| 2268 |
if ( !property_exists( $this, 'is_child' ) ) { |
| 2269 |
if ( isset( $this->wpda_project_table_settings->hyperlinks_parent->{$hyperlink_label} ) && !$this->wpda_project_table_settings->hyperlinks_parent->{$hyperlink_label} ) { |
| 2270 |
$skip_column = true; |
| 2271 |
} |
| 2272 |
} else { |
| 2273 |
if ( isset( $this->wpda_project_table_settings->hyperlinks_child->{$hyperlink_label} ) && !$this->wpda_project_table_settings->hyperlinks_child->{$hyperlink_label} ) { |
| 2274 |
$skip_column = true; |
| 2275 |
} |
| 2276 |
} |
| 2277 |
} |
| 2278 |
if ( !$skip_column ) { |
| 2279 |
$hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' ); |
| 2280 |
$columns["wpda_hyperlink_{$i}"] = $hyperlink_label; |
| 2281 |
// Add hyperlink label. |
| 2282 |
} |
| 2283 |
} |
| 2284 |
$i++; |
| 2285 |
} |
| 2286 |
} |
| 2287 |
// Cache columns. |
| 2288 |
$this->wpda_cached_columns = $columns; |
| 2289 |
return $columns; |
| 2290 |
} |
| 2291 |
|
| 2292 |
/** |
| 2293 |
* List of columns to make sortable |
| 2294 |
* |
| 2295 |
* @return array |
| 2296 |
* @since 1.0.0 |
| 2297 |
*/ |
| 2298 |
public function get_sortable_columns() { |
| 2299 |
$columns = array(); |
| 2300 |
// Get column names from result set. |
| 2301 |
if ( $this->items ) { |
| 2302 |
foreach ( $this->items[0] as $key => $value ) { |
| 2303 |
if ( 'wpda_hyperlink_' !== substr( $key, 0, 15 ) ) { |
| 2304 |
$columns[$key] = array($key, false); |
| 2305 |
} |
| 2306 |
} |
| 2307 |
} |
| 2308 |
return $columns; |
| 2309 |
} |
| 2310 |
|
| 2311 |
/** |
| 2312 |
* Display the search box |
| 2313 |
* |
| 2314 |
* @param string $text The 'submit' button label. |
| 2315 |
* @param string $input_id ID attribute value for the search input field. |
| 2316 |
* |
| 2317 |
* @since 1.0.0 |
| 2318 |
*/ |
| 2319 |
public function search_box( $text, $input_id ) { |
| 2320 |
$input_id = $input_id . '-search-input'; |
| 2321 |
// Allow external user to add search actions (like icons) to the search box. |
| 2322 |
do_action( |
| 2323 |
'wpda_add_search_actions', |
| 2324 |
$this->schema_name, |
| 2325 |
$this->table_name, |
| 2326 |
$this->wpda_table_settings, |
| 2327 |
$this->wpda_list_columns |
| 2328 |
); |
| 2329 |
?> |
| 2330 |
|
| 2331 |
<p class="search-box" <?php |
| 2332 |
echo ( !$this->has_items() ? 'style="padding-bottom:10px;"' : '' ); |
| 2333 |
?>> |
| 2334 |
<input type="search" id="<?php |
| 2335 |
echo esc_attr( $input_id ); |
| 2336 |
?>" |
| 2337 |
name="<?php |
| 2338 |
echo esc_attr( $this->search_item_name ); |
| 2339 |
?>" |
| 2340 |
value="<?php |
| 2341 |
echo esc_attr( $this->search_value ); |
| 2342 |
?>"/> |
| 2343 |
<?php |
| 2344 |
if ( is_admin() ) { |
| 2345 |
submit_button( |
| 2346 |
$text, |
| 2347 |
'', |
| 2348 |
'', |
| 2349 |
false, |
| 2350 |
array( |
| 2351 |
'id' => 'search-submit', |
| 2352 |
) |
| 2353 |
); |
| 2354 |
} else { |
| 2355 |
wpdadiehard_submit_button( |
| 2356 |
$text, |
| 2357 |
'', |
| 2358 |
'', |
| 2359 |
false, |
| 2360 |
array( |
| 2361 |
'id' => 'search-submit', |
| 2362 |
) |
| 2363 |
); |
| 2364 |
} |
| 2365 |
?> |
| 2366 |
<input type="hidden" name="<?php |
| 2367 |
echo esc_attr( $this->search_item_name ); |
| 2368 |
?>_old_value" |
| 2369 |
value="<?php |
| 2370 |
echo esc_attr( $this->search_value ); |
| 2371 |
?>"/> |
| 2372 |
</p> |
| 2373 |
|
| 2374 |
<?php |
| 2375 |
// Allow external user to add search html (like extra items) below the search box. |
| 2376 |
do_action( |
| 2377 |
'wpda_add_search_filter', |
| 2378 |
$this->schema_name, |
| 2379 |
$this->table_name, |
| 2380 |
$this->wpda_table_settings, |
| 2381 |
$this->wpda_list_columns |
| 2382 |
); |
| 2383 |
} |
| 2384 |
|
| 2385 |
/** |
| 2386 |
* Get search value (entered by the user or taken from cookie). |
| 2387 |
* |
| 2388 |
* @return string |
| 2389 |
* @since 1.5.0 |
| 2390 |
*/ |
| 2391 |
protected function get_search_value() { |
| 2392 |
if ( 'off' === WPDA::get_option( WPDA::OPTION_BE_REMEMBER_SEARCH ) ) { |
| 2393 |
if ( isset( $_REQUEST[$this->search_item_name] ) ) { |
| 2394 |
return wp_filter_nohtml_kses( wp_unslash( $_REQUEST[$this->search_item_name] ) ); |
| 2395 |
// input var okay. |
| 2396 |
} |
| 2397 |
} |
| 2398 |
if ( 'wpda_wpdp_' === substr( $this->page, 0, 10 ) ) { |
| 2399 |
$cookie_name = $this->page; |
| 2400 |
if ( isset( $_REQUEST['child_request'] ) ) { |
| 2401 |
$cookie_name = 'NOCOOKIESFORCHILDREQUESTS'; |
| 2402 |
// No search values stored for child tables. |
| 2403 |
} |
| 2404 |
foreach ( $_REQUEST as $key => $val ) { |
| 2405 |
if ( strpos( $key, 'WPDA_PARENT_KEY*' ) === 0 ) { |
| 2406 |
$cookie_name = 'NOCOOKIESFORCHILDREQUESTS'; |
| 2407 |
// No search values stored for child tables. |
| 2408 |
} |
| 2409 |
} |
| 2410 |
} else { |
| 2411 |
$cookie_name = $this->page . '_search_' . str_replace( '.', '_', $this->table_name ); |
| 2412 |
} |
| 2413 |
if ( isset( $_REQUEST[$this->search_item_name] ) && '' !== $_REQUEST[$this->search_item_name] ) { |
| 2414 |
// input var okay. |
| 2415 |
return wp_filter_nohtml_kses( wp_unslash( $_REQUEST[$this->search_item_name] ) ); |
| 2416 |
// input var okay. |
| 2417 |
} elseif ( isset( $_COOKIE[$cookie_name] ) ) { |
| 2418 |
return wp_filter_nohtml_kses( wp_unslash( $_COOKIE[$cookie_name] ) ); |
| 2419 |
// input var okay. |
| 2420 |
} else { |
| 2421 |
return null; |
| 2422 |
} |
| 2423 |
} |
| 2424 |
|
| 2425 |
/** |
| 2426 |
* Print column headers |
| 2427 |
* |
| 2428 |
* Overriding original method print_column_headers to support post instead of get. |
| 2429 |
* Changes are marked! |
| 2430 |
* |
| 2431 |
* @param boolean $with_id Whether to set the id attribute or not. |
| 2432 |
* |
| 2433 |
* @since 1.0.0 |
| 2434 |
* |
| 2435 |
* @staticvar $cb_counter int |
| 2436 |
*/ |
| 2437 |
public function print_column_headers( $with_id = true ) { |
| 2438 |
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info(); |
| 2439 |
//phpcs:ignore - 8.1 proof |
| 2440 |
// ********************* |
| 2441 |
// *** BEGIN CHANGES *** |
| 2442 |
// ********************* |
| 2443 |
// Code removed. |
| 2444 |
// ******************* |
| 2445 |
// *** END CHANGES *** |
| 2446 |
// ******************* |
| 2447 |
if ( isset( $_REQUEST['orderby'] ) ) { |
| 2448 |
$current_orderby = sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ); |
| 2449 |
// input var okay. |
| 2450 |
} else { |
| 2451 |
$current_orderby = ''; |
| 2452 |
} |
| 2453 |
if ( isset( $_REQUEST['order'] ) && 'desc' === $_REQUEST['order'] ) { |
| 2454 |
// input var okay. |
| 2455 |
$current_order = 'desc'; |
| 2456 |
} else { |
| 2457 |
$current_order = 'asc'; |
| 2458 |
} |
| 2459 |
if ( !empty( $columns['cb'] ) ) { |
| 2460 |
static $cb_counter = 1; |
| 2461 |
$columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . __( 'Select All' ) . '</label>' . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox" />'; |
| 2462 |
$cb_counter++; |
| 2463 |
} |
| 2464 |
foreach ( $columns as $column_key => $column_display_name ) { |
| 2465 |
$class = array('manage-column', "column-{$column_key}"); |
| 2466 |
if ( in_array( $column_key, (array) $hidden ) ) { |
| 2467 |
//phpcs:ignore - 8.1 proof |
| 2468 |
$class[] = 'hidden'; |
| 2469 |
} |
| 2470 |
if ( 'cb' === $column_key ) { |
| 2471 |
$class[] = 'check-column'; |
| 2472 |
} elseif ( in_array( $column_key, array('posts', 'comments', 'links') ) ) { |
| 2473 |
$class[] = 'num'; |
| 2474 |
} |
| 2475 |
if ( $column_key === $primary ) { |
| 2476 |
$class[] = 'column-primary'; |
| 2477 |
} |
| 2478 |
if ( isset( $sortable[$column_key] ) ) { |
| 2479 |
list( $orderby, $desc_first ) = (array) $sortable[$column_key]; |
| 2480 |
//phpcs:ignore - 8.1 proof |
| 2481 |
if ( $current_orderby === $orderby ) { |
| 2482 |
$order = ( 'asc' === $current_order ? 'desc' : 'asc' ); |
| 2483 |
$class[] = 'sorted'; |
| 2484 |
$class[] = $current_order; |
| 2485 |
} else { |
| 2486 |
$order = ( $desc_first ? 'desc' : 'asc' ); |
| 2487 |
$class[] = 'sortable'; |
| 2488 |
$class[] = ( $desc_first ? 'asc' : 'desc' ); |
| 2489 |
} |
| 2490 |
// ********************* |
| 2491 |
// *** BEGIN CHANGES *** |
| 2492 |
// ********************* |
| 2493 |
// Code removed. |
| 2494 |
// ******************* |
| 2495 |
// *** END CHANGES *** |
| 2496 |
// ******************* |
| 2497 |
} |
| 2498 |
$tag = ( 'cb' === $column_key ? 'td' : 'th' ); |
| 2499 |
$scope = ( 'th' === $tag ? 'scope="col"' : '' ); |
| 2500 |
$id = ( $with_id ? "id='{$column_key}'" : '' ); |
| 2501 |
if ( !empty( $class ) ) { |
| 2502 |
$class = "class='" . join( ' ', $class ) . "'"; |
| 2503 |
} |
| 2504 |
// ********************* |
| 2505 |
// *** BEGIN CHANGES *** |
| 2506 |
// ********************* |
| 2507 |
echo '<' . esc_attr( $tag ) . ' ' . wp_kses_data( $scope ) . ' ' . wp_kses_data( $id ) . ' ' . wp_kses_data( $class ) . '>'; |
| 2508 |
if ( isset( $sortable[$column_key] ) ) { |
| 2509 |
?> |
| 2510 |
<a href="javascript:void(0)" |
| 2511 |
onclick="jQuery('#wpda_main_form_orderby').val('<?php |
| 2512 |
echo esc_attr( $orderby ); |
| 2513 |
?>'); jQuery('#wpda_main_form_order').val('<?php |
| 2514 |
echo esc_attr( $order ); |
| 2515 |
?>'); jQuery('#wpda_main_form').submit();"> |
| 2516 |
<span><?php |
| 2517 |
echo wp_kses_data( $column_display_name ); |
| 2518 |
?></span><span |
| 2519 |
class="sorting-indicator"></span> |
| 2520 |
</a> |
| 2521 |
<?php |
| 2522 |
} else { |
| 2523 |
echo wp_kses( $column_display_name, array( |
| 2524 |
'input' => array( |
| 2525 |
'id' => array(), |
| 2526 |
'type' => array(), |
| 2527 |
), |
| 2528 |
'label' => array( |
| 2529 |
'class' => array(), |
| 2530 |
'for' => array(), |
| 2531 |
), |
| 2532 |
) ); |
| 2533 |
} |
| 2534 |
echo '</' . esc_attr( $tag ) . '>'; |
| 2535 |
// ******************* |
| 2536 |
// *** END CHANGES *** |
| 2537 |
// ******************* |
| 2538 |
} |
| 2539 |
} |
| 2540 |
|
| 2541 |
/** |
| 2542 |
* Returns an associative array containing the bulk action |
| 2543 |
* |
| 2544 |
* @return array |
| 2545 |
* @since 1.0.0 |
| 2546 |
*/ |
| 2547 |
public function get_bulk_actions() { |
| 2548 |
if ( !$this->bulk_actions_enabled ) { |
| 2549 |
// Bulk actions disabled. |
| 2550 |
return ''; |
| 2551 |
} |
| 2552 |
if ( empty( $this->wpda_list_columns->get_table_primary_key() ) ) { |
| 2553 |
// Tables has no primary key: no bulk actions allowed! |
| 2554 |
// Primary key is necessary to ensure uniqueness. |
| 2555 |
return ''; |
| 2556 |
} |
| 2557 |
$actions = array(); |
| 2558 |
if ( 'on' === $this->allow_delete ) { |
| 2559 |
$actions = array( |
| 2560 |
'bulk-delete' => __( 'Delete Permanently', 'wp-data-access' ), |
| 2561 |
); |
| 2562 |
} |
| 2563 |
if ( $this->bulk_export_enabled && (WPDA::is_wpda_table( $this->table_name ) || WPDA::get_option( WPDA::OPTION_BE_EXPORT_ROWS ) === 'on') ) { |
| 2564 |
if ( 'diehard' !== $this->page ) { |
| 2565 |
// Not allowed on web page. |
| 2566 |
$actions['bulk-export'] = __( 'Export to SQL', 'wp-data-access' ); |
| 2567 |
} |
| 2568 |
$actions['bulk-export-xml'] = __( 'Export to XML', 'wp-data-access' ); |
| 2569 |
$actions['bulk-export-json'] = __( 'Export to JSON', 'wp-data-access' ); |
| 2570 |
$actions['bulk-export-excel'] = __( 'Export to Excel', 'wp-data-access' ); |
| 2571 |
$actions['bulk-export-csv'] = __( 'Export to CSV', 'wp-data-access' ); |
| 2572 |
} |
| 2573 |
return $actions; |
| 2574 |
} |
| 2575 |
|
| 2576 |
/** |
| 2577 |
* Generates the table navigation |
| 2578 |
* |
| 2579 |
* Generates the table navigation above or bellow the table and removes the |
| 2580 |
* _wp_http_referrer and _wpnonce because it generates a error about URL too large. |
| 2581 |
* |
| 2582 |
* @param string $which CSS Class name. |
| 2583 |
* |
| 2584 |
* @return void |
| 2585 |
* @since 1.0.0 |
| 2586 |
*/ |
| 2587 |
protected function display_tablenav( $which ) { |
| 2588 |
if ( !$this->hide_navigation && $this->items ) { |
| 2589 |
?> |
| 2590 |
<div class="tablenav <?php |
| 2591 |
echo esc_attr( $which ); |
| 2592 |
?>"> |
| 2593 |
<div class="alignleft actions"> |
| 2594 |
<?php |
| 2595 |
$this->bulk_actions( $which ); |
| 2596 |
?> |
| 2597 |
</div> |
| 2598 |
<span id="wpda_row_export_anchor"></span> |
| 2599 |
<?php |
| 2600 |
$this->add_full_table_downloads(); |
| 2601 |
$this->extra_tablenav( $which ); |
| 2602 |
$this->pagination( $which ); |
| 2603 |
?> |
| 2604 |
<br class="clear"/> |
| 2605 |
</div> |
| 2606 |
<?php |
| 2607 |
} else { |
| 2608 |
?> |
| 2609 |
<br class="clear"/> |
| 2610 |
<?php |
| 2611 |
} |
| 2612 |
} |
| 2613 |
|
| 2614 |
/** |
| 2615 |
* Add full export to CSV and JSON buttons |
| 2616 |
* Needs to be granted in project page configuration |
| 2617 |
*/ |
| 2618 |
protected function add_full_table_downloads() { |
| 2619 |
} |
| 2620 |
|
| 2621 |
// Override to add arguments to CSV and JSON full table exports. |
| 2622 |
protected function add_full_table_downloads_add_args() { |
| 2623 |
} |
| 2624 |
|
| 2625 |
/** |
| 2626 |
* Display the pagination |
| 2627 |
* |
| 2628 |
* Overriding original method pagination to support post instead of get. |
| 2629 |
* Changes are marked! |
| 2630 |
* |
| 2631 |
* @param string $which CSS Class name. |
| 2632 |
* |
| 2633 |
* @since 1.0.0 |
| 2634 |
*/ |
| 2635 |
protected function pagination( $which ) { |
| 2636 |
if ( empty( $this->_pagination_args ) ) { |
| 2637 |
return; |
| 2638 |
} |
| 2639 |
$total_items = $this->_pagination_args['total_items']; |
| 2640 |
$total_pages = $this->_pagination_args['total_pages']; |
| 2641 |
$infinite_scroll = false; |
| 2642 |
if ( isset( $this->_pagination_args['infinite_scroll'] ) ) { |
| 2643 |
$infinite_scroll = $this->_pagination_args['infinite_scroll']; |
| 2644 |
} |
| 2645 |
if ( 'top' === $which && $total_pages > 1 ) { |
| 2646 |
$this->screen->render_screen_reader_content( 'heading_pagination' ); |
| 2647 |
} |
| 2648 |
// Add estimate character if row_count_estimate is enabled. |
| 2649 |
$estimate = ( $this->row_count_estimate['is_estimate'] ? '~' : '' ); |
| 2650 |
/* translators: %s: number of items (2x) */ |
| 2651 |
$output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items ), $estimate . number_format_i18n( $total_items ) ) . '</span>'; |
| 2652 |
$current = $this->get_pagenum(); |
| 2653 |
if ( $this->search_value !== $this->search_value_old ) { |
| 2654 |
$current = 1; |
| 2655 |
} |
| 2656 |
// ********************* |
| 2657 |
// *** BEGIN CHANGES *** |
| 2658 |
// ********************* |
| 2659 |
// Code removed. |
| 2660 |
// ******************* |
| 2661 |
// *** END CHANGES *** |
| 2662 |
// ******************* |
| 2663 |
$page_links = array(); |
| 2664 |
$total_pages_before = '<span class="paging-input">'; |
| 2665 |
$total_pages_after = '</span></span>'; |
| 2666 |
$disable_first = $disable_last = $disable_prev = $disable_next = false; |
| 2667 |
if ( 1 === (int) $current ) { |
| 2668 |
$disable_first = true; |
| 2669 |
$disable_prev = true; |
| 2670 |
} |
| 2671 |
if ( 2 === (int) $current ) { |
| 2672 |
$disable_first = true; |
| 2673 |
} |
| 2674 |
if ( (int) $current === (int) $total_pages ) { |
| 2675 |
$disable_last = true; |
| 2676 |
$disable_next = true; |
| 2677 |
} |
| 2678 |
if ( (int) $current === (int) $total_pages - 1 ) { |
| 2679 |
$disable_last = true; |
| 2680 |
} |
| 2681 |
// ********************* |
| 2682 |
// *** BEGIN CHANGES *** |
| 2683 |
// ********************* |
| 2684 |
$link_with_post_support = "\n <a class='%s'\n href='javascript:void(0)'\n onclick='jQuery(\"#current-page-selector\").val(\"%s\"); jQuery(\"#wpda_main_form\").submit();'>\n <span class='screen-reader-text'>%s</span>\n <span aria-hidden='true'>%s</span>\n </a>"; |
| 2685 |
// ******************* |
| 2686 |
// *** END CHANGES *** |
| 2687 |
// ******************* |
| 2688 |
if ( $disable_first ) { |
| 2689 |
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>'; |
| 2690 |
} else { |
| 2691 |
// ********************* |
| 2692 |
// *** BEGIN CHANGES *** |
| 2693 |
// ********************* |
| 2694 |
$page_links[] = sprintf( |
| 2695 |
$link_with_post_support, |
| 2696 |
'first-page button', |
| 2697 |
'', |
| 2698 |
__( 'First page' ), |
| 2699 |
'«' |
| 2700 |
); |
| 2701 |
// ******************* |
| 2702 |
// *** END CHANGES *** |
| 2703 |
// ******************* |
| 2704 |
} |
| 2705 |
if ( $disable_prev ) { |
| 2706 |
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">‹</span>'; |
| 2707 |
} else { |
| 2708 |
// ********************* |
| 2709 |
// *** BEGIN CHANGES *** |
| 2710 |
// ********************* |
| 2711 |
$page_links[] = sprintf( |
| 2712 |
$link_with_post_support, |
| 2713 |
'prev-page button', |
| 2714 |
max( 1, $current - 1 ), |
| 2715 |
__( 'Previous page' ), |
| 2716 |
'‹' |
| 2717 |
); |
| 2718 |
// ******************* |
| 2719 |
// *** END CHANGES *** |
| 2720 |
// ******************* |
| 2721 |
} |
| 2722 |
if ( 'bottom' === $which ) { |
| 2723 |
$html_current_page = $current; |
| 2724 |
$total_pages_before = '<span class="screen-reader-text">' . __( 'Current Page' ) . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">'; |
| 2725 |
} else { |
| 2726 |
$html_current_page = sprintf( |
| 2727 |
"%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>", |
| 2728 |
'<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page' ) . '</label>', |
| 2729 |
$current, |
| 2730 |
strlen( (string) $total_pages ) |
| 2731 |
); |
| 2732 |
} |
| 2733 |
$html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) ); |
| 2734 |
/* translators: %s: current page/total pages */ |
| 2735 |
$page_links[] = $total_pages_before . sprintf( _x( '%1$s of %2$s', 'paging' ), $html_current_page, $html_total_pages ) . $total_pages_after; |
| 2736 |
if ( $disable_next ) { |
| 2737 |
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">›</span>'; |
| 2738 |
} else { |
| 2739 |
// ********************* |
| 2740 |
// *** BEGIN CHANGES *** |
| 2741 |
// ********************* |
| 2742 |
$page_links[] = sprintf( |
| 2743 |
$link_with_post_support, |
| 2744 |
'next-page button', |
| 2745 |
min( $total_pages, $current + 1 ), |
| 2746 |
__( 'Next page' ), |
| 2747 |
'›' |
| 2748 |
); |
| 2749 |
// ******************* |
| 2750 |
// *** END CHANGES *** |
| 2751 |
// ******************* |
| 2752 |
} |
| 2753 |
if ( $disable_last ) { |
| 2754 |
$page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>'; |
| 2755 |
} else { |
| 2756 |
// ********************* |
| 2757 |
// *** BEGIN CHANGES *** |
| 2758 |
// ********************* |
| 2759 |
$page_links[] = sprintf( |
| 2760 |
$link_with_post_support, |
| 2761 |
'last-page button', |
| 2762 |
$total_pages, |
| 2763 |
__( 'Last page' ), |
| 2764 |
'»' |
| 2765 |
); |
| 2766 |
// ******************* |
| 2767 |
// *** END CHANGES *** |
| 2768 |
// ******************* |
| 2769 |
} |
| 2770 |
$pagination_links_class = 'pagination-links'; |
| 2771 |
if ( !empty( $infinite_scroll ) ) { |
| 2772 |
$pagination_links_class = ' hide-if-js'; |
| 2773 |
} |
| 2774 |
$output .= "\n<span class='{$pagination_links_class}'>" . join( "\n", $page_links ) . '</span>'; |
| 2775 |
if ( $total_pages ) { |
| 2776 |
$page_class = ( $total_pages < 2 ? ' one-page' : '' ); |
| 2777 |
} else { |
| 2778 |
$page_class = ' no-pages'; |
| 2779 |
} |
| 2780 |
$this->_pagination = "<div class='tablenav-pages{$page_class}'>{$output}</div>"; |
| 2781 |
echo $this->_pagination; |
| 2782 |
// phpcs:ignore WordPress.Security.EscapeOutput |
| 2783 |
} |
| 2784 |
|
| 2785 |
} |
| 2786 |
|