| @@ -12,8 +12,9 @@ | ||
| 12 | 12 | defined( 'ABSPATH' ) || die( 'No direct script access allowed!' ); |
| 13 | 13 | |
| 14 | 14 | /** |
| 15 | 15 | * Table Model class |
| 16 | + * | |
| 16 | 17 | * @package TablePress |
| 17 | 18 | * @subpackage Models |
| 18 | 19 | * @author Tobias Bäthge |
| 19 | 20 | * @since 1.0.0 |
| @@ -23,38 +24,35 @@ | ||
| 23 | 24 | /** |
| 24 | 25 | * Instance of the Post Type Model. |
| 25 | 26 | * |
| 26 | 27 | * @since 1.0.0 |
| 27 | - * @var TablePress_Post_Model | |
| 28 | 28 | */ |
| 29 | - protected $model_post; | |
| 29 | + protected \TablePress_Post_Model $model_post; | |
| 30 | 30 | |
| 31 | 31 | /** |
| 32 | 32 | * Name of the Post Meta Field for table options. |
| 33 | 33 | * |
| 34 | 34 | * @since 1.0.0 |
| 35 | - * @var string | |
| 36 | 35 | */ |
| 37 | - protected $table_options_field_name = '_tablepress_table_options'; | |
| 36 | + protected string $table_options_field_name = '_tablepress_table_options'; | |
| 38 | 37 | |
| 39 | 38 | /** |
| 40 | 39 | * Name of the Post Meta Field for table visibility. |
| 41 | 40 | * |
| 42 | 41 | * @since 1.0.0 |
| 43 | - * @var string | |
| 44 | 42 | */ |
| 45 | - protected $table_visibility_field_name = '_tablepress_table_visibility'; | |
| 43 | + protected string $table_visibility_field_name = '_tablepress_table_visibility'; | |
| 46 | 44 | |
| 47 | 45 | /** |
| 48 | 46 | * Default set of tables. |
| 49 | 47 | * |
| 50 | 48 | * @since 1.0.0 |
| 51 | - * @var array $args { | |
| 52 | - * @type int $last_id Last table ID that was given to a new table. | |
| 53 | - * @type array $table_post Connections between table ID and post ID (key: table ID, value: post ID). | |
| 49 | + * @var array{last_id: int, table_post: array<string, int>} { | |
| 50 | + * @type int $last_id Last table ID that was given to a new table. | |
| 51 | + * @type array<string, int> $table_post Connections between table ID and post ID (key: table ID, value: post ID). | |
| 54 | 52 | * } |
| 55 | 53 | */ |
| 56 | - protected $default_tables = array( | |
| 54 | + protected array $default_tables = array( | |
| 57 | 55 | 'last_id' => 0, |
| 58 | 56 | 'table_post' => array(), |
| 59 | 57 | ); |
| 60 | 58 | |
| @@ -61,121 +59,12 @@ | ||
| 61 | 59 | /** |
| 62 | 60 | * Instance of WP_Option class for the list of tables. |
| 63 | 61 | * |
| 64 | 62 | * @since 1.0.0 |
| 65 | - * @var TablePress_WP_Option | |
| 66 | 63 | */ |
| 67 | - protected $tables; | |
| 64 | + protected \TablePress_WP_Option $tables; | |
| 68 | 65 | |
| 69 | 66 | /** |
| 70 | - * Mappings for old to new parameter names for DataTables. | |
| 71 | - * DataTables 1.9 used Hungarian notation, while DataTables 1.10+ uses camelCase notation. | |
| 72 | - * | |
| 73 | - * As this array is used in strtr(), it's pre-sorted for descending string length of the array keys. | |
| 74 | - * | |
| 75 | - * @since 1.5.0 | |
| 76 | - * @var array | |
| 77 | - * @link https://www.datatables.net/upgrade/1.10-convert | |
| 78 | - */ | |
| 79 | - protected $datatables_parameter_mappings = array( | |
| 80 | - 'fnStateSaveParams' => 'stateSaveParams', | |
| 81 | - 'fnStateLoadParams' => 'stateLoadParams', | |
| 82 | - 'fnPreDrawCallback' => 'preDrawCallback', | |
| 83 | - 'fnHeaderCallback' => 'headerCallback', | |
| 84 | - 'fnFooterCallback' => 'footerCallback', | |
| 85 | - 'sSortDescending' => 'sortDescending', | |
| 86 | - 'sPaginationType' => 'pagingType', | |
| 87 | - 'sLoadingRecords' => 'loadingRecords', | |
| 88 | - 'sDefaultContent' => 'defaultContent', | |
| 89 | - 'sContentPadding' => 'contentPadding', | |
| 90 | - 'iCookieDuration' => 'stateDuration', | |
| 91 | - 'bScrollCollapse' => 'scrollCollapse', | |
| 92 | - 'asStripeClasses' => 'stripeClasses', | |
| 93 | - 'sSortAscending' => 'sortAscending', | |
| 94 | - 'sInfoThousands' => 'thousands', | |
| 95 | - 'iDisplayLength' => 'pageLength', | |
| 96 | - 'fnServerParams' => 'ajax', | |
| 97 | - 'fnInitComplete' => 'initComplete', | |
| 98 | - 'fnInfoCallback' => 'infoCallback', | |
| 99 | - 'fnFormatNumber' => 'formatNumber', | |
| 100 | - 'fnDrawCallback' => 'drawCallback', | |
| 101 | - 'aaSortingFixed' => 'orderFixed', | |
| 102 | - 'sSortDataType' => 'orderDataType', | |
| 103 | - 'sServerMethod' => 'ajax', | |
| 104 | - 'sScrollXInner' => 'scrollXInner', | |
| 105 | - 'sInfoFiltered' => 'infoFiltered', | |
| 106 | - 'sAjaxDataProp' => 'dataSrc', | |
| 107 | - 'iDisplayStart' => 'displayStart', | |
| 108 | - 'iDeferLoading' => 'deferLoading', | |
| 109 | - 'fnStateLoaded' => 'stateLoaded', | |
| 110 | - 'fnRowCallback' => 'rowCallback', | |
| 111 | - 'fnCreatedCell' => 'createdCell', | |
| 112 | - 'bSortCellsTop' => 'orderCellsTop', | |
| 113 | - 'bLengthChange' => 'lengthChange', | |
| 114 | - 'sZeroRecords' => 'zeroRecords', | |
| 115 | - 'sInfoPostFix' => 'infoPostFix', | |
| 116 | - 'fnServerData' => 'ajax', | |
| 117 | - 'fnCreatedRow' => 'createdRow', | |
| 118 | - 'bSortClasses' => 'orderClasses', | |
| 119 | - 'bDeferRender' => 'deferRender', | |
| 120 | - 'aoSearchCols' => 'searchCols', | |
| 121 | - 'aoColumnDefs' => 'columnDefs', | |
| 122 | - 'sProcessing' => 'processing', | |
| 123 | - 'sLengthMenu' => 'lengthMenu', | |
| 124 | - 'sEmptyTable' => 'emptyTable', | |
| 125 | - 'sAjaxSource' => 'ajax', | |
| 126 | - 'fnStateSave' => 'stateSaveCallback', | |
| 127 | - 'fnStateLoad' => 'stateLoadCallback', | |
| 128 | - 'bServerSide' => 'serverSide', | |
| 129 | - 'bSearchable' => 'searchable', | |
| 130 | - 'bProcessing' => 'processing', | |
| 131 | - 'aLengthMenu' => 'lengthMenu', | |
| 132 | - 'sInfoEmpty' => 'infoEmpty', | |
| 133 | - 'bStateSave' => 'stateSave', | |
| 134 | - 'bAutoWidth' => 'autoWidth', | |
| 135 | - 'className' => 'className', // Replace "className" with itself, to avoid that the replacement for "sName" breaks it. | |
| 136 | - 'sPrevious' => 'previous', | |
| 137 | - 'sCellType' => 'cellType', | |
| 138 | - 'oPaginate' => 'paginate', | |
| 139 | - 'oLanguage' => 'language', | |
| 140 | - 'iTabIndex' => 'tabIndex', | |
| 141 | - 'iDataSort' => 'orderData', | |
| 142 | - 'bSortable' => 'orderable', | |
| 143 | - 'bRetrieve' => 'retrieve', | |
| 144 | - 'bPaginate' => 'paging', | |
| 145 | - 'bJQueryUI' => 'jQueryUI', | |
| 146 | - 'asSorting' => 'orderSequence', | |
| 147 | - 'aoColumns' => 'columns', | |
| 148 | - 'aaSorting' => 'order', | |
| 149 | - 'aDataSort' => 'orderData', | |
| 150 | - 'sScrollY' => 'scrollY', | |
| 151 | - 'sScrollX' => 'scrollX', | |
| 152 | - 'bVisible' => 'visible', | |
| 153 | - 'bDestroy' => 'destroy', | |
| 154 | - 'aTargets' => 'targets', | |
| 155 | - 'sSearch' => 'search', | |
| 156 | - 'oSearch' => 'search', | |
| 157 | - 'mRender' => 'render', | |
| 158 | - 'bFilter' => 'searching', | |
| 159 | - 'sWidth' => 'width', | |
| 160 | - 'sTitle' => 'title', | |
| 161 | - 'sFirst' => 'first', | |
| 162 | - 'sClass' => 'className', | |
| 163 | - 'aaData' => 'data', | |
| 164 | - 'sType' => 'type', | |
| 165 | - 'sNext' => 'next', | |
| 166 | - 'sName' => 'name', | |
| 167 | - 'sLast' => 'last', | |
| 168 | - 'sInfo' => 'info', | |
| 169 | - 'oAria' => 'aria', | |
| 170 | - 'mData' => 'data', | |
| 171 | - 'bSort' => 'ordering', | |
| 172 | - 'bInfo' => 'info', | |
| 173 | - 'sUrl' => 'url', | |
| 174 | - 'sDom' => 'dom', | |
| 175 | - ); | |
| 176 | - | |
| 177 | - /** | |
| 178 | 67 | * Init the Table model by instantiating a Post model and loading the list of tables option. |
| 179 | 68 | * |
| 180 | 69 | * @since 1.0.0 |
| 181 | 70 | */ |
| @@ -194,11 +83,11 @@ | ||
| 194 | 83 | * Get the tables option, which holds the connection between table ID and post ID. |
| 195 | 84 | * |
| 196 | 85 | * @since 1.0.0 |
| 197 | 86 | * |
| 198 | - * @return array Current set of tables. | |
| 87 | + * @return mixed[] Current set of tables. | |
| 199 | 88 | */ |
| 200 | - public function _debug_get_tables() { | |
| 89 | + public function _debug_get_tables(): array { | |
| 201 | 90 | return $this->tables->get(); |
| 202 | 91 | } |
| 203 | 92 | |
| 204 | 93 | /** |
| @@ -205,11 +94,11 @@ | ||
| 205 | 94 | * Update the tables option, which holds the connection between table ID and post ID. |
| 206 | 95 | * |
| 207 | 96 | * @since 1.0.0 |
| 208 | 97 | * |
| 209 | - * @param array $tables New set of tables. | |
| 98 | + * @param mixed[] $tables New set of tables. | |
| 210 | 99 | */ |
| 211 | - public function _debug_update_tables( array $tables ) { | |
| 100 | + public function _debug_update_tables( array $tables ): void { | |
| 212 | 101 | $this->tables->update( $tables ); |
| 213 | 102 | } |
| 214 | 103 | |
| 215 | 104 | /** |
| @@ -216,16 +105,13 @@ | ||
| 216 | 105 | * Convert a table to a post, which can be stored in the database. |
| 217 | 106 | * |
| 218 | 107 | * @since 1.0.0 |
| 219 | 108 | * |
| 220 | - * @param array $table Table. | |
| 221 | - * @param int $post_id Post ID of an existing table, or -1 for a new table. | |
| 222 | - * @return array Post. | |
| 109 | + * @param array<string, mixed> $table Table. | |
| 110 | + * @param int $post_id Post ID of an existing table, or -1 for a new table. | |
| 111 | + * @return array<string, mixed> Post. | |
| 223 | 112 | */ |
| 224 | - protected function _table_to_post( array $table, $post_id ) { | |
| 225 | - // Run filters on content in each cell and other fields. | |
| 226 | - $table = $this->filter_content( $table ); | |
| 227 | - | |
| 113 | + protected function _table_to_post( array $table, int $post_id ): array { | |
| 228 | 114 | // Sanitize each cell, table name, and table description, if the user is not allowed to work with unfiltered HTML. |
| 229 | 115 | if ( ! current_user_can( 'unfiltered_html' ) ) { |
| 230 | 116 | $table = $this->sanitize( $table ); |
| 231 | 117 | } |
| @@ -237,9 +123,8 @@ | ||
| 237 | 123 | |
| 238 | 124 | $post = array( |
| 239 | 125 | 'ID' => $post_id, |
| 240 | 126 | 'post_title' => $table['name'], |
| 241 | - // 'post_author' => $table['author'], | |
| 242 | 127 | 'post_excerpt' => $table['description'], |
| 243 | 128 | 'post_content' => wp_json_encode( $table['data'], TABLEPRESS_JSON_OPTIONS ), |
| 244 | 129 | 'post_mime_type' => 'application/json', |
| 245 | 130 | ); |
| @@ -254,11 +139,11 @@ | ||
| 254 | 139 | * |
| 255 | 140 | * @param WP_Post $post Post. |
| 256 | 141 | * @param string $table_id Table ID. |
| 257 | 142 | * @param bool $load_data Whether the table data shall be loaded. |
| 258 | - * @return array Table. | |
| 143 | + * @return array<string, mixed> Table. | |
| 259 | 144 | */ |
| 260 | - protected function _post_to_table( $post, $table_id, $load_data ) { | |
| 145 | + protected function _post_to_table( WP_Post $post, string $table_id, bool $load_data ): array { | |
| 261 | 146 | $table = array( |
| 262 | 147 | 'id' => $table_id, |
| 263 | 148 | 'name' => $post->post_title, |
| 264 | 149 | 'description' => $post->post_excerpt, |
| @@ -274,20 +159,11 @@ | ||
| 274 | 159 | $table['data'] = json_decode( $post->post_content, true ); |
| 275 | 160 | |
| 276 | 161 | // Check if JSON could be decoded. |
| 277 | 162 | if ( is_null( $table['data'] ) ) { |
| 278 | - // Set a single cell as the default. | |
| 279 | - $table['data'] = array( array( "The internal data of table {$table_id} is corrupted." ) ); | |
| 280 | - // Mark table as corrupted. | |
| 163 | + $table['data'] = array( array( "The internal data of table {$table_id} is corrupted." ) ); // Set a single cell as the cell content. | |
| 281 | 164 | $table['is_corrupted'] = true; |
| 282 | - | |
| 283 | - // If possible, try to find out what error prevented the JSON from being decoded. | |
| 284 | - $table['json_error'] = 'The error could not be determined.'; | |
| 285 | - $json_error_msg = json_last_error_msg(); | |
| 286 | - if ( false !== $json_error_msg ) { | |
| 287 | - $table['json_error'] = $json_error_msg; | |
| 288 | - } | |
| 289 | - | |
| 165 | + $table['json_error'] = json_last_error_msg(); | |
| 290 | 166 | $table['description'] = "[ERROR] TABLE IS CORRUPTED (JSON error: {$table['json_error']})! DO NOT EDIT THIS TABLE NOW!\nInstead, please see https://tablepress.org/faq/corrupted-tables/ for instructions.\n-\n{$table['description']}"; |
| 291 | 167 | } else { |
| 292 | 168 | // Specifically cast to an array again. |
| 293 | 169 | $table['data'] = (array) $table['data']; |
| @@ -303,11 +179,11 @@ | ||
| 303 | 179 | * |
| 304 | 180 | * @param string $table_id Table ID. |
| 305 | 181 | * @param bool $load_data Whether the table data shall be loaded. |
| 306 | 182 | * @param bool $load_options_visibility Whether the table options and table visibility shall be loaded. |
| 307 | - * @return array|WP_Error Table as an array on success, WP_Error on error. | |
| 183 | + * @return array<string, mixed>|WP_Error Table as an array on success, WP_Error on error. | |
| 308 | 184 | */ |
| 309 | - public function load( $table_id, $load_data = true, $load_options_visibility = true ) { | |
| 185 | + public function load( string $table_id, bool $load_data = true, bool $load_options_visibility = true ) /* : array|WP_Error */ { | |
| 310 | 186 | if ( empty( $table_id ) ) { |
| 311 | 187 | return new WP_Error( 'table_load_empty_table_id' ); |
| 312 | 188 | } |
| 313 | 189 | |
| @@ -335,11 +211,11 @@ | ||
| 335 | 211 | * @since 1.0.0 |
| 336 | 212 | * |
| 337 | 213 | * @param bool $prime_meta_cache Optional. Whether the prime the post meta cache when loading the posts. |
| 338 | 214 | * @param bool $run_filter Optional. Whether to run a filter on the list of table IDs. |
| 339 | - * @return array Array of table IDs. | |
| 215 | + * @return string[] Array of table IDs. | |
| 340 | 216 | */ |
| 341 | - public function load_all( $prime_meta_cache = true, $run_filter = true ) { | |
| 217 | + public function load_all( bool $prime_meta_cache = true, bool $run_filter = true ): array { | |
| 342 | 218 | $table_post = $this->tables->get( 'table_post' ); |
| 343 | 219 | if ( empty( $table_post ) ) { |
| 344 | 220 | return array(); |
| 345 | 221 | } |
| @@ -349,11 +225,13 @@ | ||
| 349 | 225 | |
| 350 | 226 | // This loop now uses the WP cache. |
| 351 | 227 | $table_ids = array(); |
| 352 | 228 | foreach ( $table_post as $table_id => $post_id ) { |
| 353 | - $table_id = (string) $table_id; | |
| 229 | + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers. | |
| 230 | + | |
| 354 | 231 | // Load table without data and options to save memory. |
| 355 | 232 | $table = $this->load( $table_id, false, false ); |
| 233 | + | |
| 356 | 234 | // Skip tables that could not be loaded properly. |
| 357 | 235 | if ( ! is_wp_error( $table ) ) { |
| 358 | 236 | $table_ids[] = $table_id; |
| 359 | 237 | } |
| @@ -360,13 +238,13 @@ | ||
| 360 | 238 | } |
| 361 | 239 | |
| 362 | 240 | if ( $run_filter ) { |
| 363 | 241 | /** |
| 364 | - * Filter all table IDs that are loaded. | |
| 242 | + * Filters all table IDs that are loaded. | |
| 365 | 243 | * |
| 366 | 244 | * @since 1.4.0 |
| 367 | 245 | * |
| 368 | - * @param array $table_ids The table IDs that are loaded. | |
| 246 | + * @param string[] $table_ids The table IDs that are loaded. | |
| 369 | 247 | */ |
| 370 | 248 | $table_ids = apply_filters( 'tablepress_load_all_tables', $table_ids ); |
| 371 | 249 | } |
| 372 | 250 | |
| @@ -377,12 +255,12 @@ | ||
| 377 | 255 | * Sanitize the table to remove undesired HTML code using KSES. |
| 378 | 256 | * |
| 379 | 257 | * @since 1.8.0 |
| 380 | 258 | * |
| 381 | - * @param array $table Table. | |
| 382 | - * @return array Sanitized table. | |
| 259 | + * @param array<string, mixed> $table Table. | |
| 260 | + * @return array<string, mixed> Sanitized table. | |
| 383 | 261 | */ |
| 384 | - public function sanitize( array $table ) { | |
| 262 | + public function sanitize( array $table ): array { | |
| 385 | 263 | // Sanitize the table name and description. |
| 386 | 264 | $fields = array( 'name', 'description' ); |
| 387 | 265 | foreach ( $fields as $field ) { |
| 388 | 266 | $table[ $field ] = wp_kses_post( $table[ $field ] ); |
| @@ -390,9 +268,9 @@ | ||
| 390 | 268 | |
| 391 | 269 | // Sanitize each cell. |
| 392 | 270 | foreach ( $table['data'] as $row_idx => $row ) { |
| 393 | 271 | foreach ( $row as $column_idx => $cell_content ) { |
| 394 | - $table['data'][ $row_idx ][ $column_idx ] = wp_kses_post( $cell_content ); // equals wp_filter_post_kses(), but without the unncessary slashes handling | |
| 272 | + $table['data'][ $row_idx ][ $column_idx ] = wp_kses_post( $cell_content ); // Equals wp_filter_post_kses(), but without the unnecessary slashes handling. | |
| 395 | 273 | } |
| 396 | 274 | } |
| 397 | 275 | |
| 398 | 276 | return $table; |
| @@ -398,54 +276,16 @@ | ||
| 398 | 276 | return $table; |
| 399 | 277 | } |
| 400 | 278 | |
| 401 | 279 | /** |
| 402 | - * Filter/modify the content of table cells and other fields, e.g. for security hardening. | |
| 403 | - * | |
| 404 | - * This is similar to the `sanitize()` method, but executed for all users. | |
| 405 | - * In 1.10.0, adding `rel="noopener noreferrer"` to all HTML link elements like `<a target=` was added. See https://core.trac.wordpress.org/ticket/43187. | |
| 406 | - * | |
| 407 | - * @since 1.10.0 | |
| 408 | - * | |
| 409 | - * @param array $table Table. | |
| 410 | - * @return array Filtered/modified table. | |
| 411 | - */ | |
| 412 | - public function filter_content( array $table ) { | |
| 413 | - /** | |
| 414 | - * Filter whether the contents of table cells and fields should be filtered/modified. | |
| 415 | - * | |
| 416 | - * @since 1.10.0 | |
| 417 | - * | |
| 418 | - * @param bool $filter Whether to filter the content of table cells and other fields. Default true. | |
| 419 | - */ | |
| 420 | - if ( ! apply_filters( 'tablepress_filter_table_cell_content', true ) ) { | |
| 421 | - return; | |
| 422 | - } | |
| 423 | - | |
| 424 | - // Filter the table name and description. | |
| 425 | - $fields = array( 'name', 'description' ); | |
| 426 | - foreach ( $fields as $field ) { | |
| 427 | - $table[ $field ] = wp_targeted_link_rel( $table[ $field ] ); | |
| 428 | - } | |
| 429 | - | |
| 430 | - foreach ( $table['data'] as $row_idx => $row ) { | |
| 431 | - foreach ( $row as $column_idx => $cell_content ) { | |
| 432 | - $table['data'][ $row_idx ][ $column_idx ] = wp_targeted_link_rel( $cell_content ); | |
| 433 | - } | |
| 434 | - } | |
| 435 | - | |
| 436 | - return $table; | |
| 437 | - } | |
| 438 | - | |
| 439 | - /** | |
| 440 | 280 | * Save a table. |
| 441 | 281 | * |
| 442 | 282 | * @since 1.0.0 |
| 443 | 283 | * |
| 444 | - * @param array $table Table (needs to have $table['id']!). | |
| 284 | + * @param array<string, mixed> $table Table (needs to have $table['id']!). | |
| 445 | 285 | * @return string|WP_Error WP_Error on error, string table ID on success. |
| 446 | 286 | */ |
| 447 | - public function save( array $table ) { | |
| 287 | + public function save( array $table ) /* : string|WP_Error */ { | |
| 448 | 288 | if ( empty( $table['id'] ) ) { |
| 449 | 289 | return new WP_Error( 'table_save_empty_table_id' ); |
| 450 | 290 | } |
| 451 | 291 | |
| @@ -456,11 +296,11 @@ | ||
| 456 | 296 | |
| 457 | 297 | $post = $this->_table_to_post( $table, $post_id ); |
| 458 | 298 | $new_post_id = $this->model_post->update( $post ); |
| 459 | 299 | if ( is_wp_error( $new_post_id ) ) { |
| 460 | - // Add an error code to the existing WP_Error. | |
| 461 | - $new_post_id->add( 'table_save_post_update', '', $post_id ); | |
| 462 | - return $new_post_id; | |
| 300 | + $error = new WP_Error( 'table_save_post_update', '', $post_id ); | |
| 301 | + $error->merge_from( $new_post_id ); | |
| 302 | + return $error; | |
| 463 | 303 | } |
| 464 | 304 | if ( $post_id !== $new_post_id ) { |
| 465 | 305 | return new WP_Error( 'table_save_new_post_id_does_not_match', '', $new_post_id ); |
| 466 | 306 | } |
| @@ -498,20 +338,20 @@ | ||
| 498 | 338 | * Add a new table. |
| 499 | 339 | * |
| 500 | 340 | * @since 1.0.0 |
| 501 | 341 | * |
| 502 | - * @param array $table Table ($table['id'] is not necessary). | |
| 503 | - * @param string $copy_or_add Optional. 'copy' if the table is copied, 'add' if it is a new table. Default 'add'. | |
| 342 | + * @param array<string, mixed> $table Table ($table['id'] is not necessary). | |
| 343 | + * @param string $copy_or_add Optional. 'copy' if the table is copied, 'add' if it is a new table. Default 'add'. | |
| 504 | 344 | * @return string|WP_Error WP_Error on error, string table ID of the new table on success. |
| 505 | 345 | */ |
| 506 | - public function add( array $table, $copy_or_add = 'add' ) { | |
| 507 | - $post_id = -1; // to insert table | |
| 346 | + public function add( array $table, string $copy_or_add = 'add' ) /* : string|WP_Error */ { | |
| 347 | + $post_id = -1; // To insert table. | |
| 508 | 348 | $post = $this->_table_to_post( $table, $post_id ); |
| 509 | 349 | $new_post_id = $this->model_post->insert( $post ); |
| 510 | 350 | if ( is_wp_error( $new_post_id ) ) { |
| 511 | - // Add an error code to the existing WP_Error. | |
| 512 | - $new_post_id->add( 'table_add_post_insert', '' ); | |
| 513 | - return $new_post_id; | |
| 351 | + $error = new WP_Error( 'table_add_post_insert', '' ); | |
| 352 | + $error->merge_from( $new_post_id ); | |
| 353 | + return $error; | |
| 514 | 354 | } |
| 515 | 355 | |
| 516 | 356 | $options_saved = $this->_add_table_options( $new_post_id, $table['options'] ); |
| 517 | 357 | if ( ! $options_saved ) { |
| @@ -548,14 +388,14 @@ | ||
| 548 | 388 | * |
| 549 | 389 | * @param string $table_id ID of the table to be copied. |
| 550 | 390 | * @return string|WP_Error WP_Error on error, string table ID of the new table on success. |
| 551 | 391 | */ |
| 552 | - public function copy( $table_id ) { | |
| 392 | + public function copy( string $table_id ) /* : string|WP_Error */ { | |
| 553 | 393 | $table = $this->load( $table_id, true, true ); |
| 554 | 394 | if ( is_wp_error( $table ) ) { |
| 555 | - // Add an error code to the existing WP_Error. | |
| 556 | - $table->add( 'table_copy_table_load', '', $table_id ); | |
| 557 | - return $table; | |
| 395 | + $error = new WP_Error( 'table_copy_table_load', '', $table_id ); | |
| 396 | + $error->merge_from( $table ); | |
| 397 | + return $error; | |
| 558 | 398 | } |
| 559 | 399 | |
| 560 | 400 | // Adjust name of copied table. |
| 561 | 401 | if ( '' === trim( $table['name'] ) ) { |
| @@ -565,19 +405,19 @@ | ||
| 565 | 405 | |
| 566 | 406 | // Merge this data into an empty table template. |
| 567 | 407 | $table = $this->prepare_table( $this->get_table_template(), $table, false ); |
| 568 | 408 | if ( is_wp_error( $table ) ) { |
| 569 | - // Add an error code to the existing WP_Error. | |
| 570 | - $table->add( 'table_copy_table_prepare', '', $table_id ); | |
| 571 | - return $table; | |
| 409 | + $error = new WP_Error( 'table_copy_table_prepare', '', $table_id ); | |
| 410 | + $error->merge_from( $table ); | |
| 411 | + return $error; | |
| 572 | 412 | } |
| 573 | 413 | |
| 574 | 414 | // Add the copied table. |
| 575 | 415 | $new_table_id = $this->add( $table, 'copy' ); |
| 576 | 416 | if ( is_wp_error( $new_table_id ) ) { |
| 577 | - // Add an error code to the existing WP_Error. | |
| 578 | - $new_table_id->add( 'table_copy_table_add', '', $table_id ); | |
| 579 | - return $new_table_id; | |
| 417 | + $error = new WP_Error( 'table_copy_table_add', '', $table_id ); | |
| 418 | + $error->merge_from( $new_table_id ); | |
| 419 | + return $error; | |
| 580 | 420 | } |
| 581 | 421 | |
| 582 | 422 | /** |
| 583 | 423 | * Fires after an existing table has been copied. |
| @@ -599,14 +439,16 @@ | ||
| 599 | 439 | * |
| 600 | 440 | * @param string $table_id ID of the table to be deleted. |
| 601 | 441 | * @return bool|WP_Error WP_Error on error, true on success. |
| 602 | 442 | */ |
| 603 | - public function delete( $table_id ) { | |
| 443 | + public function delete( string $table_id ) /* : true|WP_Error */ { | |
| 604 | 444 | if ( ! $this->table_exists( $table_id ) ) { |
| 605 | 445 | return new WP_Error( 'table_delete_table_does_not_exist', '', $table_id ); |
| 606 | 446 | } |
| 607 | 447 | |
| 608 | 448 | $post_id = $this->_get_post_id( $table_id ); // No ! false check necessary, as this is covered by table_exists() check above. |
| 449 | + | |
| 450 | + // @phpstan-ignore argument.type | |
| 609 | 451 | $deleted = $this->model_post->delete( $post_id ); // Post Meta fields will be deleted automatically by that function. |
| 610 | 452 | if ( false === $deleted ) { |
| 611 | 453 | return new WP_Error( 'table_delete_post_could_not_be_deleted', '', $post_id ); |
| 612 | 454 | } |
| @@ -635,9 +477,9 @@ | ||
| 635 | 477 | * Delete all tables. |
| 636 | 478 | * |
| 637 | 479 | * @since 1.0.0 |
| 638 | 480 | */ |
| 639 | - public function delete_all() { | |
| 481 | + public function delete_all(): void { | |
| 640 | 482 | $tables = $this->tables->get(); |
| 641 | 483 | if ( empty( $tables['table_post'] ) ) { |
| 642 | 484 | return; |
| 643 | 485 | } |
| @@ -642,11 +484,13 @@ | ||
| 642 | 484 | return; |
| 643 | 485 | } |
| 644 | 486 | |
| 645 | 487 | foreach ( $tables['table_post'] as $table_id => $post_id ) { |
| 646 | - $table_id = (string) $table_id; | |
| 488 | + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers. | |
| 489 | + | |
| 647 | 490 | $this->model_post->delete( $post_id ); // Post Meta fields will be deleted automatically by that function. |
| 648 | 491 | unset( $tables['table_post'][ $table_id ] ); |
| 492 | + | |
| 649 | 493 | // Invalidate table output caches that belong to this table. |
| 650 | 494 | $this->invalidate_table_output_cache( $table_id ); |
| 651 | 495 | } |
| 652 | 496 | |
| @@ -669,9 +513,9 @@ | ||
| 669 | 513 | * |
| 670 | 514 | * @param string $table_id Table ID. |
| 671 | 515 | * @return bool Whether the table ID exists. |
| 672 | 516 | */ |
| 673 | - public function table_exists( $table_id ) { | |
| 517 | + public function table_exists( string $table_id ): bool { | |
| 674 | 518 | $table_post = $this->tables->get( 'table_post' ); |
| 675 | 519 | return isset( $table_post[ $table_id ] ); |
| 676 | 520 | } |
| 677 | 521 | |
| @@ -680,11 +524,11 @@ | ||
| 680 | 524 | * |
| 681 | 525 | * @since 1.0.0 |
| 682 | 526 | * |
| 683 | 527 | * @param bool $single_value Optional. Whether to return just the number of tables from the list, or also count in the database. |
| 684 | - * @return bool int|array Number of Tables (if $single_value), or array of Numbers from list/DB (if ! $single_value). | |
| 528 | + * @return int|array{list: int, db: int} Number of Tables (if $single_value), or array of Numbers from list/DB (if ! $single_value). | |
| 685 | 529 | */ |
| 686 | - public function count_tables( $single_value = true ) { | |
| 530 | + public function count_tables( bool $single_value = true ) /* : int|array */ { | |
| 687 | 531 | $count_list = count( $this->tables->get( 'table_post' ) ); |
| 688 | 532 | if ( $single_value ) { |
| 689 | 533 | return $count_list; |
| 690 | 534 | } |
| @@ -703,9 +547,9 @@ | ||
| 703 | 547 | * @since 1.8.0 Renamed from _invalidate_table_output_cache to invalidate_table_output_cache and made public. |
| 704 | 548 | * |
| 705 | 549 | * @param string $table_id Table ID. |
| 706 | 550 | */ |
| 707 | - public function invalidate_table_output_cache( $table_id ) { | |
| 551 | + public function invalidate_table_output_cache( string $table_id ): void { | |
| 708 | 552 | $caches_list_transient_name = 'tablepress_c_' . md5( $table_id ); |
| 709 | 553 | $caches_list = get_transient( $caches_list_transient_name ); |
| 710 | 554 | if ( false !== $caches_list ) { |
| 711 | 555 | $caches_list = (array) json_decode( $caches_list, true ); |
| @@ -716,15 +560,15 @@ | ||
| 716 | 560 | delete_transient( $caches_list_transient_name ); |
| 717 | 561 | } |
| 718 | 562 | |
| 719 | 563 | /** |
| 720 | - * Flush the caches of the plugins W3 Total Cache, WP Super Cache, Cachify, and Quick Cache. | |
| 564 | + * Flush the caches of common caching plugins. | |
| 721 | 565 | * |
| 722 | 566 | * @since 1.0.0 |
| 723 | 567 | */ |
| 724 | - public function _flush_caching_plugins_caches() { | |
| 568 | + public function _flush_caching_plugins_caches(): void { | |
| 725 | 569 | /** |
| 726 | - * Filter whether the caches of common caching plugins shall be flushed. | |
| 570 | + * Filters whether the caches of common caching plugins shall be flushed. | |
| 727 | 571 | * |
| 728 | 572 | * @since 1.0.0 |
| 729 | 573 | * |
| 730 | 574 | * @param bool $flush Whether caches of caching plugins shall be flushed. Default true. |
| @@ -732,26 +576,77 @@ | ||
| 732 | 576 | if ( ! apply_filters( 'tablepress_flush_caching_plugins_caches', true ) ) { |
| 733 | 577 | return; |
| 734 | 578 | } |
| 735 | 579 | |
| 736 | - // W3 Total Cache | |
| 737 | - if ( function_exists( 'w3tc_pgcache_flush' ) ) { | |
| 738 | - w3tc_pgcache_flush(); | |
| 580 | + // Common cache flush callback. | |
| 581 | + $cache_flush_callbacks = array( | |
| 582 | + array( 'Breeze_PurgeCache', 'breeze_cache_flush' ), // Breeze. | |
| 583 | + array( 'comet_cache', 'clear' ), // Comet Cache. | |
| 584 | + 'pantheon_wp_clear_edge_all', // Pantheon. | |
| 585 | + 'sg_cachepress_purge_cache', // SG Optimizer. | |
| 586 | + array( 'Swift_Performance_Cache', 'clear_all_cache' ), // Swift Performance. | |
| 587 | + 'w3tc_pgcache_flush', // W3 Total Cache. | |
| 588 | + array( 'WpeCommon', 'purge_memcached' ), // WP Engine. | |
| 589 | + array( 'WpeCommon', 'clear_maxcdn_cache' ), // WP Engine. | |
| 590 | + array( 'WpeCommon', 'purge_varnish_cache' ), // WP Engine. | |
| 591 | + 'wpfc_clear_all_cache', // WP Fastest Cache. | |
| 592 | + 'rocket_clean_domain', // WP Rocket. | |
| 593 | + 'wp_cache_clear_cache', // WP Super Cache. | |
| 594 | + array( 'zencache', 'clear' ), // Zen Cache. | |
| 595 | + ); | |
| 596 | + foreach ( $cache_flush_callbacks as $cache_flush_callback ) { | |
| 597 | + if ( is_callable( $cache_flush_callback ) ) { | |
| 598 | + call_user_func( $cache_flush_callback ); | |
| 599 | + } | |
| 739 | 600 | } |
| 740 | - // WP Super Cache | |
| 741 | - if ( function_exists( 'wp_cache_clear_cache' ) ) { | |
| 742 | - wp_cache_clear_cache(); | |
| 601 | + | |
| 602 | + // Common cache flush hooks. | |
| 603 | + $cache_flush_hooks = array( | |
| 604 | + 'ce_clear_cache', // Cache Enabler. | |
| 605 | + 'cachify_flush_cache', // Cachify. | |
| 606 | + 'autoptimize_action_cachepurged', // Hyper Cache. | |
| 607 | + ); | |
| 608 | + foreach ( $cache_flush_hooks as $cache_flush_hook ) { | |
| 609 | + do_action( $cache_flush_hook ); | |
| 743 | 610 | } |
| 744 | - // Cachify | |
| 745 | - do_action( 'cachify_flush_cache' ); | |
| 746 | - // Quick Cache | |
| 747 | - if ( isset( $GLOBALS['quick_cache'] ) && method_exists( $GLOBALS['quick_cache'], 'clear_cache' ) ) { | |
| 748 | - $GLOBALS['quick_cache']->clear_cache(); | |
| 611 | + | |
| 612 | + // Kinsta. | |
| 613 | + if ( isset( $GLOBALS['kinsta_cache'] ) && ! empty( $GLOBALS['kinsta_cache']->kinsta_cache_purge ) && is_callable( array( $GLOBALS['kinsta_cache']->kinsta_cache_purge, 'purge_complete_caches' ) ) ) { | |
| 614 | + $GLOBALS['kinsta_cache']->kinsta_cache_purge->purge_complete_caches(); // @phpstan-ignore method.nonObject | |
| 749 | 615 | } |
| 750 | - // WP Fastest Cache | |
| 751 | - if ( isset( $GLOBALS['wp_fastest_cache'] ) && method_exists( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) { | |
| 752 | - $GLOBALS['wp_fastest_cache']->deleteCache(); | |
| 616 | + // LiteSpeed Cache. | |
| 617 | + if ( is_callable( array( 'LiteSpeed_Cache_Tags', 'add_purge_tag' ) ) ) { | |
| 618 | + LiteSpeed_Cache_Tags::add_purge_tag( '*' ); // @phpstan-ignore class.notFound | |
| 753 | 619 | } |
| 620 | + // Pagely. | |
| 621 | + if ( class_exists( 'PagelyCachePurge' ) ) { | |
| 622 | + $_pagely = new PagelyCachePurge(); | |
| 623 | + if ( is_callable( array( $_pagely, 'purgeAll' ) ) ) { | |
| 624 | + $_pagely->purgeAll(); | |
| 625 | + } | |
| 626 | + } | |
| 627 | + // Pressidum. | |
| 628 | + if ( is_callable( array( 'Ninukis_Plugin', 'get_instance' ) ) ) { | |
| 629 | + $_pressidum = Ninukis_Plugin::get_instance(); // @phpstan-ignore class.notFound | |
| 630 | + if ( is_callable( array( $_pressidum, 'purgeAllCaches' ) ) ) { | |
| 631 | + $_pressidum->purgeAllCaches(); // @phpstan-ignore method.nonObject | |
| 632 | + } | |
| 633 | + } | |
| 634 | + // Savvii. | |
| 635 | + if ( defined( '\Savvii\CacheFlusherPlugin::NAME_DOMAINFLUSH_NOW' ) ) { | |
| 636 | + $_savvii = new \Savvii\CacheFlusherPlugin(); // @phpstan-ignore class.notFound | |
| 637 | + if ( is_callable( array( $_savvii, 'domainflush' ) ) ) { | |
| 638 | + $_savvii->domainflush(); // @phpstan-ignore class.notFound | |
| 639 | + } | |
| 640 | + } | |
| 641 | + // WP Fastest Cache. | |
| 642 | + if ( isset( $GLOBALS['wp_fastest_cache'] ) && is_callable( array( $GLOBALS['wp_fastest_cache'], 'deleteCache' ) ) ) { | |
| 643 | + $GLOBALS['wp_fastest_cache']->deleteCache( true ); // @phpstan-ignore method.nonObject | |
| 644 | + } | |
| 645 | + // WP-Optimize. | |
| 646 | + if ( function_exists( 'WP_Optimize' ) ) { | |
| 647 | + WP_Optimize()->get_page_cache()->purge(); | |
| 648 | + } | |
| 754 | 649 | } |
| 755 | 650 | |
| 756 | 651 | /** |
| 757 | 652 | * Get the post ID of a given table ID (if the table ID exists). |
| @@ -758,17 +653,16 @@ | ||
| 758 | 653 | * |
| 759 | 654 | * @since 1.0.0 |
| 760 | 655 | * |
| 761 | 656 | * @param string $table_id Table ID. |
| 762 | - * @return int|bool Post ID on success, false on error. | |
| 657 | + * @return int|false Post ID on success, false on error. | |
| 763 | 658 | */ |
| 764 | - protected function _get_post_id( $table_id ) { | |
| 659 | + protected function _get_post_id( string $table_id ) /* : int|false */ { | |
| 765 | 660 | $table_post = $this->tables->get( 'table_post' ); |
| 766 | - if ( isset( $table_post[ $table_id ] ) ) { | |
| 767 | - return $table_post[ $table_id ]; | |
| 768 | - } else { | |
| 661 | + if ( ! isset( $table_post[ $table_id ] ) ) { | |
| 769 | 662 | return false; |
| 770 | 663 | } |
| 664 | + return $table_post[ $table_id ]; | |
| 771 | 665 | } |
| 772 | 666 | |
| 773 | 667 | /** |
| 774 | 668 | * Update/Add a post ID for a given table ID, and sort the list of tables by their key in natural sort order. |
| @@ -775,11 +669,11 @@ | ||
| 775 | 669 | * |
| 776 | 670 | * @since 1.0.0 |
| 777 | 671 | * |
| 778 | 672 | * @param string $table_id Table ID. |
| 779 | - * @param int $post_id Post ID. | |
| 673 | + * @param int $post_id Post ID. | |
| 780 | 674 | */ |
| 781 | - protected function _update_post_id( $table_id, $post_id ) { | |
| 675 | + protected function _update_post_id( string $table_id, int $post_id ): void { | |
| 782 | 676 | $tables = $this->tables->get(); |
| 783 | 677 | $tables['table_post'][ $table_id ] = $post_id; |
| 784 | 678 | uksort( $tables['table_post'], 'strnatcasecmp' ); |
| 785 | 679 | $this->tables->update( $tables ); |
| @@ -791,9 +685,9 @@ | ||
| 791 | 685 | * @since 1.0.0 |
| 792 | 686 | * |
| 793 | 687 | * @param string $table_id Table ID. |
| 794 | 688 | */ |
| 795 | - protected function _remove_post_id( $table_id ) { | |
| 689 | + protected function _remove_post_id( string $table_id ): void { | |
| 796 | 690 | $tables = $this->tables->get(); |
| 797 | 691 | unset( $tables['table_post'][ $table_id ] ); |
| 798 | 692 | $this->tables->update( $tables ); |
| 799 | 693 | } |
| @@ -806,9 +700,9 @@ | ||
| 806 | 700 | * @param string $old_id Old table ID. |
| 807 | 701 | * @param string $new_id New table ID. |
| 808 | 702 | * @return bool|WP_Error True on success, WP_Error on error. |
| 809 | 703 | */ |
| 810 | - public function change_table_id( $old_id, $new_id ) { | |
| 704 | + public function change_table_id( string $old_id, string $new_id ) /* : true|WP_Error */ { | |
| 811 | 705 | $post_id = $this->_get_post_id( $old_id ); |
| 812 | 706 | if ( false === $post_id ) { |
| 813 | 707 | return new WP_Error( 'table_change_id_no_post_id_for_table_id', '', $old_id ); |
| 814 | 708 | } |
| @@ -844,16 +738,17 @@ | ||
| 844 | 738 | * @since 1.0.0 |
| 845 | 739 | * |
| 846 | 740 | * @return string Unused table ID (e.g. for a new table). |
| 847 | 741 | */ |
| 848 | - protected function _get_new_table_id() { | |
| 742 | + protected function _get_new_table_id(): string { | |
| 849 | 743 | $tables = $this->tables->get(); |
| 850 | 744 | // Need to check new ID candidate in a loop, because a higher ID might already be in use, if a table ID was changed manually. |
| 851 | 745 | do { |
| 852 | - $tables['last_id'] ++; | |
| 853 | - } while ( $this->table_exists( $tables['last_id'] ) ); | |
| 746 | + ++$tables['last_id']; | |
| 747 | + $last_id_string = (string) $tables['last_id']; | |
| 748 | + } while ( $this->table_exists( $last_id_string ) ); | |
| 854 | 749 | $this->tables->update( $tables ); |
| 855 | - return (string) $tables['last_id']; | |
| 750 | + return $last_id_string; | |
| 856 | 751 | } |
| 857 | 752 | |
| 858 | 753 | /** |
| 859 | 754 | * Get the template for an empty table. |
| @@ -861,24 +756,23 @@ | ||
| 861 | 756 | * Important: This scheme is versioned via TablePress::table_scheme_version; changes likely need a version update! |
| 862 | 757 | * |
| 863 | 758 | * @since 1.0.0 |
| 864 | 759 | * |
| 865 | - * @return array Empty table. | |
| 760 | + * @return array<string, mixed> Empty table. | |
| 866 | 761 | */ |
| 867 | - public function get_table_template() { | |
| 762 | + public function get_table_template(): array { | |
| 868 | 763 | // Attention: Array keys have to be lowercase, to make it possible to match them with Shortcode attributes! |
| 869 | 764 | $table = array( |
| 870 | 765 | 'id' => false, |
| 871 | 766 | 'name' => '', |
| 872 | 767 | 'description' => '', |
| 873 | - 'data' => array( array( '' ) ), // one empty cell | |
| 874 | - // 'created' => current_time( 'mysql' ), | |
| 875 | - 'last_modified' => current_time( 'mysql' ), | |
| 768 | + 'data' => array( array( '' ) ), // One empty cell. | |
| 769 | + 'last_modified' => wp_date( 'Y-m-d H:i:s' ), | |
| 876 | 770 | 'author' => get_current_user_id(), |
| 877 | 771 | 'options' => array( |
| 878 | 772 | 'last_editor' => get_current_user_id(), |
| 879 | - 'table_head' => true, | |
| 880 | - 'table_foot' => false, | |
| 773 | + 'table_head' => 1, | |
| 774 | + 'table_foot' => 0, | |
| 881 | 775 | 'alternating_row_colors' => true, |
| 882 | 776 | 'row_hover' => true, |
| 883 | 777 | 'print_name' => false, |
| 884 | 778 | 'print_name_position' => 'above', |
| @@ -884,9 +778,9 @@ | ||
| 884 | 778 | 'print_name_position' => 'above', |
| 885 | 779 | 'print_description' => false, |
| 886 | 780 | 'print_description_position' => 'below', |
| 887 | 781 | 'extra_css_classes' => '', |
| 888 | - // DataTables JavaScript library | |
| 782 | + // DataTables JavaScript library. | |
| 889 | 783 | 'use_datatables' => true, |
| 890 | 784 | 'datatables_sort' => true, |
| 891 | 785 | 'datatables_filter' => true, |
| 892 | 786 | 'datatables_paginate' => true, |
| @@ -896,18 +790,18 @@ | ||
| 896 | 790 | 'datatables_scrollx' => false, |
| 897 | 791 | 'datatables_custom_commands' => '', |
| 898 | 792 | ), |
| 899 | 793 | 'visibility' => array( |
| 900 | - 'rows' => array( 1 ), // one visbile row | |
| 901 | - 'columns' => array( 1 ), // one visible column | |
| 794 | + 'rows' => array( 1 ), // One visbile row. | |
| 795 | + 'columns' => array( 1 ), // One visible column. | |
| 902 | 796 | ), |
| 903 | 797 | ); |
| 904 | 798 | /** |
| 905 | - * Filter the default template/structure of an empty table. | |
| 799 | + * Filters the default template/structure of an empty table. | |
| 906 | 800 | * |
| 907 | 801 | * @since 1.0.0 |
| 908 | 802 | * |
| 909 | - * @param array $table Default template/structure of an empty table. | |
| 803 | + * @param array<string, mixed> $table Default template/structure of an empty table. | |
| 910 | 804 | */ |
| 911 | 805 | return apply_filters( 'tablepress_table_template', $table ); |
| 912 | 806 | } |
| 913 | 807 | |
| @@ -917,33 +811,27 @@ | ||
| 917 | 811 | * Performs consistency checks on data and visibility settings. |
| 918 | 812 | * |
| 919 | 813 | * @since 1.0.0 |
| 920 | 814 | * |
| 921 | - * @param array $table Table to merge into. | |
| 922 | - * @param array $new_table Table to merge. | |
| 923 | - * @param bool $table_size_check Optional. Whether to check the number of rows and columns (e.g. not necessary for added or copied tables). | |
| 924 | - * @return array|WP_Error Merged table on success, WP_Error on error. | |
| 815 | + * @param array<string, mixed> $table Table to merge into. | |
| 816 | + * @param array<string, mixed> $new_table Table to merge. | |
| 817 | + * @param bool $table_size_check Optional. Whether to check the number of rows and columns (e.g. not necessary for added or copied tables). | |
| 818 | + * @return array<string, mixed>|WP_Error Merged table on success, WP_Error on error. | |
| 925 | 819 | */ |
| 926 | - public function prepare_table( array $table, array $new_table, $table_size_check = true ) { | |
| 820 | + public function prepare_table( array $table, array $new_table, bool $table_size_check = true ) /* : array|WP_Error */ { | |
| 927 | 821 | // Table ID must be the same (if there was an ID already). |
| 928 | - if ( false !== $table['id'] ) { | |
| 929 | - if ( $table['id'] !== $new_table['id'] ) { | |
| 930 | - return new WP_Error( 'table_prepare_no_id_match', '', $new_table['id'] ); | |
| 931 | - } | |
| 822 | + if ( false !== $table['id'] && $table['id'] !== $new_table['id'] ) { | |
| 823 | + return new WP_Error( 'table_prepare_no_id_match', '', $new_table['id'] ); | |
| 932 | 824 | } |
| 933 | 825 | |
| 934 | 826 | // Name, description, and data array need to exist, data must not be empty, the others could be ''. |
| 935 | - if ( ! isset( $new_table['name'] ) | |
| 936 | - || ! isset( $new_table['description'] ) | |
| 937 | - || empty( $new_table['data'] ) | |
| 938 | - || empty( $new_table['data'][0] ) ) { | |
| 827 | + if ( ! isset( $new_table['name'], $new_table['description'] ) | |
| 828 | + || empty( $new_table['data'] ) || empty( $new_table['data'][0] ) ) { | |
| 939 | 829 | return new WP_Error( 'table_prepare_name_description_or_data_not_set' ); |
| 940 | 830 | } |
| 941 | 831 | |
| 942 | 832 | // Visibility needs to exist. |
| 943 | - if ( ! isset( $new_table['visibility'] ) | |
| 944 | - || ! isset( $new_table['visibility']['rows'] ) | |
| 945 | - || ! isset( $new_table['visibility']['columns'] ) ) { | |
| 833 | + if ( ! isset( $new_table['visibility']['rows'], $new_table['visibility']['columns'] ) ) { | |
| 946 | 834 | return new WP_Error( 'table_prepare_visibility_not_set' ); |
| 947 | 835 | } |
| 948 | 836 | $new_table['visibility']['rows'] = array_map( 'intval', $new_table['visibility']['rows'] ); |
| 949 | 837 | $new_table['visibility']['columns'] = array_map( 'intval', $new_table['visibility']['columns'] ); |
| @@ -949,16 +837,14 @@ | ||
| 949 | 837 | $new_table['visibility']['columns'] = array_map( 'intval', $new_table['visibility']['columns'] ); |
| 950 | 838 | |
| 951 | 839 | // Check dimensions of table data array (not done for newly added, copied, or imported tables). |
| 952 | 840 | if ( $table_size_check ) { |
| 953 | - if ( empty( $new_table['number'] ) | |
| 954 | - || ! isset( $new_table['number']['rows'] ) | |
| 955 | - || ! isset( $new_table['number']['columns'] ) ) { | |
| 841 | + if ( ! isset( $new_table['number']['rows'], $new_table['number']['columns'] ) ) { | |
| 956 | 842 | return new WP_Error( 'table_prepare_size_check_numbers_not_set' ); |
| 957 | 843 | } |
| 958 | 844 | // Table data needs to be ok, and have the correct number of rows and columns. |
| 959 | - $new_table['number']['rows'] = intval( $new_table['number']['rows'] ); | |
| 960 | - $new_table['number']['columns'] = intval( $new_table['number']['columns'] ); | |
| 845 | + $new_table['number']['rows'] = (int) $new_table['number']['rows']; | |
| 846 | + $new_table['number']['columns'] = (int) $new_table['number']['columns']; | |
| 961 | 847 | if ( 0 === $new_table['number']['rows'] |
| 962 | 848 | || 0 === $new_table['number']['columns'] |
| 963 | 849 | || count( $new_table['data'] ) !== $new_table['number']['rows'] |
| 964 | 850 | || count( $new_table['data'][0] ) !== $new_table['number']['columns'] ) { |
| @@ -973,18 +859,21 @@ | ||
| 973 | 859 | |
| 974 | 860 | // All checks were successful, replace original values with new ones. |
| 975 | 861 | |
| 976 | 862 | // $table['id'] is either false (and remains false) or already equal to $new_table['id']. |
| 977 | - $table['new_id'] = isset( $new_table['new_id'] ) ? $new_table['new_id'] : $table['id']; | |
| 863 | + $table['new_id'] = $new_table['new_id'] ?? $table['id']; | |
| 978 | 864 | $table['name'] = $new_table['name']; |
| 979 | 865 | $table['description'] = $new_table['description']; |
| 980 | 866 | $table['data'] = $new_table['data']; |
| 981 | - // $table['author'] = get_current_user_id(); // We don't want this, as it would override the original author. | |
| 982 | - // $table['created'] = current_time( 'mysql' ); // We don't want this, as it would override the original datetime. | |
| 983 | - $table['last_modified'] = current_time( 'mysql' ); | |
| 984 | - $table['options']['last_editor'] = get_current_user_id(); | |
| 867 | + // Make sure that cells are stored as strings. | |
| 868 | + array_walk_recursive( | |
| 869 | + $table['data'], | |
| 870 | + static function ( /* string|int|float|bool|null */ &$cell_content, int $col_idx ): void { | |
| 871 | + $cell_content = (string) $cell_content; | |
| 872 | + }, | |
| 873 | + ); | |
| 985 | 874 | // Table Options. |
| 986 | - if ( isset( $new_table['options'] ) ) { // is for example not set for newly added tables | |
| 875 | + if ( isset( $new_table['options'] ) ) { // Options are for example not set for newly added tables. | |
| 987 | 876 | // Specials check for certain options. |
| 988 | 877 | if ( isset( $new_table['options']['extra_css_classes'] ) ) { |
| 989 | 878 | $new_table['options']['extra_css_classes'] = explode( ' ', $new_table['options']['extra_css_classes'] ); |
| 990 | 879 | $new_table['options']['extra_css_classes'] = array_map( array( 'TablePress', 'sanitize_css_class' ), $new_table['options']['extra_css_classes'] ); |
| @@ -991,13 +880,22 @@ | ||
| 991 | 880 | $new_table['options']['extra_css_classes'] = array_unique( $new_table['options']['extra_css_classes'] ); |
| 992 | 881 | $new_table['options']['extra_css_classes'] = trim( implode( ' ', $new_table['options']['extra_css_classes'] ) ); |
| 993 | 882 | } |
| 994 | 883 | if ( isset( $new_table['options']['datatables_paginate_entries'] ) ) { |
| 995 | - $new_table['options']['datatables_paginate_entries'] = intval( $new_table['options']['datatables_paginate_entries'] ); | |
| 884 | + $new_table['options']['datatables_paginate_entries'] = (int) $new_table['options']['datatables_paginate_entries']; | |
| 996 | 885 | if ( $new_table['options']['datatables_paginate_entries'] < 1 ) { |
| 997 | - $new_table['options']['datatables_paginate_entries'] = 10; // default value | |
| 886 | + $new_table['options']['datatables_paginate_entries'] = 10; // Default value. | |
| 998 | 887 | } |
| 999 | 888 | } |
| 889 | + | |
| 890 | + // Backward compatibility: Convert boolean or numeric string "table_head" and "table_foot" options to integer. | |
| 891 | + if ( isset( $new_table['options']['table_head'] ) ) { | |
| 892 | + $new_table['options']['table_head'] = absint( $new_table['options']['table_head'] ); | |
| 893 | + } | |
| 894 | + if ( isset( $new_table['options']['table_foot'] ) ) { | |
| 895 | + $new_table['options']['table_foot'] = absint( $new_table['options']['table_foot'] ); | |
| 896 | + } | |
| 897 | + | |
| 1000 | 898 | // Merge new options. |
| 1001 | 899 | $default_table = $this->get_table_template(); |
| 1002 | 900 | $table['options'] = array_intersect_key( $table['options'], $default_table['options'] ); |
| 1003 | 901 | $new_table['options'] = array_intersect_key( $new_table['options'], $default_table['options'] ); |
| @@ -1005,11 +903,22 @@ | ||
| 1005 | 903 | } |
| 1006 | 904 | // Table Visibility. |
| 1007 | 905 | $table['visibility']['rows'] = $new_table['visibility']['rows']; |
| 1008 | 906 | $table['visibility']['columns'] = $new_table['visibility']['columns']; |
| 1009 | - // Convert DataTables 1.9 parameters (Hungarian notation) to DataTables 1.10 parameters (camelCase notation). | |
| 907 | + | |
| 908 | + // $table['author'] = get_current_user_id(); // We don't want this, as it would override the original author. | |
| 909 | + // $table['created'] = wp_date( 'Y-m-d H:i:s' ); // We don't want this, as it would override the original datetime. | |
| 910 | + $table['last_modified'] = wp_date( 'Y-m-d H:i:s' ); | |
| 911 | + $table['options']['last_editor'] = get_current_user_id(); | |
| 912 | + | |
| 913 | + // Prevent issues if the "Custom Commands" field is not set, e.g. when non-admins have previously edited the table. | |
| 914 | + if ( ! isset( $table['options']['datatables_custom_commands'] ) ) { | |
| 915 | + $table['options']['datatables_custom_commands'] = ''; | |
| 916 | + } | |
| 917 | + | |
| 918 | + // Convert CSS classes and some DataTables 1.x parameters to the DataTables 2 variants. | |
| 1010 | 919 | if ( '' !== $table['options']['datatables_custom_commands'] ) { |
| 1011 | - $table['options']['datatables_custom_commands'] = strtr( $table['options']['datatables_custom_commands'], $this->datatables_parameter_mappings ); | |
| 920 | + $table['options']['datatables_custom_commands'] = TablePress::convert_datatables_api_data( $table['options']['datatables_custom_commands'] ); | |
| 1012 | 921 | } |
| 1013 | 922 | |
| 1014 | 923 | return $table; |
| 1015 | 924 | } |
| @@ -1018,15 +927,15 @@ | ||
| 1018 | 927 | * Save the table options of a table (in a post meta field of the table's post). |
| 1019 | 928 | * |
| 1020 | 929 | * @since 1.0.0 |
| 1021 | 930 | * |
| 1022 | - * @param int $post_id Post ID. | |
| 1023 | - * @param array $options Table options. | |
| 931 | + * @param int $post_id Post ID. | |
| 932 | + * @param array<string, mixed> $options Table options. | |
| 1024 | 933 | * @return bool True on success, false on error. |
| 1025 | 934 | */ |
| 1026 | - protected function _add_table_options( $post_id, array $options ) { | |
| 935 | + protected function _add_table_options( int $post_id, array $options ): bool { | |
| 1027 | 936 | $options = wp_json_encode( $options, TABLEPRESS_JSON_OPTIONS ); |
| 1028 | - return $this->model_post->add_meta_field( $post_id, $this->table_options_field_name, $options ); | |
| 937 | + return $this->model_post->add_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore argument.type | |
| 1029 | 938 | } |
| 1030 | 939 | |
| 1031 | 940 | /** |
| 1032 | 941 | * Update the table options of a table (in a post meta field in the table's post). |
| @@ -1032,15 +941,15 @@ | ||
| 1032 | 941 | * Update the table options of a table (in a post meta field in the table's post). |
| 1033 | 942 | * |
| 1034 | 943 | * @since 1.0.0 |
| 1035 | 944 | * |
| 1036 | - * @param int $post_id Post ID. | |
| 1037 | - * @param array $options Table options. | |
| 945 | + * @param int $post_id Post ID. | |
| 946 | + * @param array<string, mixed> $options Table options. | |
| 1038 | 947 | * @return bool True on success, false on error. |
| 1039 | 948 | */ |
| 1040 | - protected function _update_table_options( $post_id, array $options ) { | |
| 949 | + protected function _update_table_options( int $post_id, array $options ): bool { | |
| 1041 | 950 | $options = wp_json_encode( $options, TABLEPRESS_JSON_OPTIONS ); |
| 1042 | - return $this->model_post->update_meta_field( $post_id, $this->table_options_field_name, $options ); | |
| 951 | + return $this->model_post->update_meta_field( $post_id, $this->table_options_field_name, $options ); // @phpstan-ignore argument.type | |
| 1043 | 952 | } |
| 1044 | 953 | |
| 1045 | 954 | /** |
| 1046 | 955 | * Get the table options of a table (from a post meta field of the table's post). |
| @@ -1047,16 +956,22 @@ | ||
| 1047 | 956 | * |
| 1048 | 957 | * @since 1.0.0 |
| 1049 | 958 | * |
| 1050 | 959 | * @param int $post_id Post ID. |
| 1051 | - * @return array Table options on success, empty array on error. | |
| 960 | + * @return array<string, mixed> Table options on success, empty array on error. | |
| 1052 | 961 | */ |
| 1053 | - protected function _get_table_options( $post_id ) { | |
| 962 | + protected function _get_table_options( int $post_id ): array { | |
| 1054 | 963 | $options = $this->model_post->get_meta_field( $post_id, $this->table_options_field_name ); |
| 1055 | 964 | if ( empty( $options ) ) { |
| 1056 | 965 | return array(); |
| 1057 | 966 | } |
| 1058 | - return (array) json_decode( $options, true ); | |
| 967 | + $options = (array) json_decode( $options, true ); | |
| 968 | + | |
| 969 | + // Backward compatibility: Convert boolean "table_head" and "table_foot" options to integer. | |
| 970 | + $options['table_head'] = absint( $options['table_head'] ); | |
| 971 | + $options['table_foot'] = absint( $options['table_foot'] ); | |
| 972 | + | |
| 973 | + return $options; | |
| 1059 | 974 | } |
| 1060 | 975 | |
| 1061 | 976 | /** |
| 1062 | 977 | * Save the table visibility of a table (in a post meta field of the table's post). |
| @@ -1062,15 +977,15 @@ | ||
| 1062 | 977 | * Save the table visibility of a table (in a post meta field of the table's post). |
| 1063 | 978 | * |
| 1064 | 979 | * @since 1.0.0 |
| 1065 | 980 | * |
| 1066 | - * @param int $post_id Post ID. | |
| 1067 | - * @param array $visibility Table visibility. | |
| 981 | + * @param int $post_id Post ID. | |
| 982 | + * @param array{rows: int[], columns: int[]} $visibility Table visibility. | |
| 1068 | 983 | * @return bool True on success, false on error. |
| 1069 | 984 | */ |
| 1070 | - protected function _add_table_visibility( $post_id, array $visibility ) { | |
| 985 | + protected function _add_table_visibility( int $post_id, array $visibility ): bool { | |
| 1071 | 986 | $visibility = wp_json_encode( $visibility, TABLEPRESS_JSON_OPTIONS ); |
| 1072 | - return $this->model_post->add_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); | |
| 987 | + return $this->model_post->add_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore argument.type | |
| 1073 | 988 | } |
| 1074 | 989 | |
| 1075 | 990 | /** |
| 1076 | 991 | * Update the table visibility of a table (in a post meta field in the table's post). |
| @@ -1076,15 +991,15 @@ | ||
| 1076 | 991 | * Update the table visibility of a table (in a post meta field in the table's post). |
| 1077 | 992 | * |
| 1078 | 993 | * @since 1.0.0 |
| 1079 | 994 | * |
| 1080 | - * @param int $post_id Post ID. | |
| 1081 | - * @param array $visibility Table visibility. | |
| 995 | + * @param int $post_id Post ID. | |
| 996 | + * @param array{rows: int[], columns: int[]} $visibility Table visibility. | |
| 1082 | 997 | * @return bool True on success, false on error. |
| 1083 | 998 | */ |
| 1084 | - protected function _update_table_visibility( $post_id, array $visibility ) { | |
| 999 | + protected function _update_table_visibility( int $post_id, array $visibility ): bool { | |
| 1085 | 1000 | $visibility = wp_json_encode( $visibility, TABLEPRESS_JSON_OPTIONS ); |
| 1086 | - return $this->model_post->update_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); | |
| 1001 | + return $this->model_post->update_meta_field( $post_id, $this->table_visibility_field_name, $visibility ); // @phpstan-ignore argument.type | |
| 1087 | 1002 | } |
| 1088 | 1003 | |
| 1089 | 1004 | /** |
| 1090 | 1005 | * Get the table visibility of a table (from a post meta field of the table's post). |
| @@ -1091,14 +1006,17 @@ | ||
| 1091 | 1006 | * |
| 1092 | 1007 | * @since 1.0.0 |
| 1093 | 1008 | * |
| 1094 | 1009 | * @param int $post_id Post ID. |
| 1095 | - * @return array Table visibility on success, empty array on error. | |
| 1010 | + * @return array{rows: int[], columns: int[]} Table visibility on success, empty array on error. | |
| 1096 | 1011 | */ |
| 1097 | - protected function _get_table_visibility( $post_id ) { | |
| 1012 | + protected function _get_table_visibility( int $post_id ): array { | |
| 1098 | 1013 | $visibility = $this->model_post->get_meta_field( $post_id, $this->table_visibility_field_name ); |
| 1099 | 1014 | if ( empty( $visibility ) ) { |
| 1100 | - return array(); | |
| 1015 | + return array( | |
| 1016 | + 'rows' => array(), | |
| 1017 | + 'columns' => array(), | |
| 1018 | + ); | |
| 1101 | 1019 | } |
| 1102 | 1020 | return json_decode( $visibility, true ); |
| 1103 | 1021 | } |
| 1104 | 1022 | |
| @@ -1107,10 +1025,13 @@ | ||
| 1107 | 1025 | * remove (no longer) existing options, after a table scheme change, |
| 1108 | 1026 | * for all tables. |
| 1109 | 1027 | * |
| 1110 | 1028 | * @since 1.0.0 |
| 1029 | + * @since 2.0.0 Add optional $remove_old_options parameter. | |
| 1030 | + * | |
| 1031 | + * @param bool $remove_old_options Optional. Whether old table options should be removed from the database. Default true. | |
| 1111 | 1032 | */ |
| 1112 | - public function merge_table_options_defaults() { | |
| 1033 | + public function merge_table_options_defaults( bool $remove_old_options = true ): void { | |
| 1113 | 1034 | $table_post = $this->tables->get( 'table_post' ); |
| 1114 | 1035 | if ( empty( $table_post ) ) { |
| 1115 | 1036 | return; |
| 1116 | 1037 | } |
| @@ -1121,12 +1042,27 @@ | ||
| 1121 | 1042 | // Get default Table with default Table Options. |
| 1122 | 1043 | $default_table = $this->get_table_template(); |
| 1123 | 1044 | |
| 1124 | 1045 | // Go through all tables (this loop now uses the WP cache). |
| 1125 | - foreach ( $table_post as $table_id => $post_id ) { | |
| 1046 | + foreach ( $table_post as $post_id ) { | |
| 1126 | 1047 | $table_options = $this->_get_table_options( $post_id ); |
| 1127 | - // Remove old (i.e. no longer existing) Table Options. | |
| 1128 | - $table_options = array_intersect_key( $table_options, $default_table['options'] ); | |
| 1048 | + | |
| 1049 | + /** | |
| 1050 | + * Filters the Table Options before they are merged with the default Table Options. | |
| 1051 | + * | |
| 1052 | + * @since 3.0.0 | |
| 1053 | + * | |
| 1054 | + * @param array<string, mixed> $table_options Table Options. | |
| 1055 | + * @param array<string, mixed> $default_table_options Default Table Options. | |
| 1056 | + * @param bool $remove_old_options Whether old table options should be removed from the database. | |
| 1057 | + * @param int $post_id Post ID of the table. | |
| 1058 | + */ | |
| 1059 | + $table_options = apply_filters( 'tablepress_table_options_before_merge', $table_options, $default_table['options'], $remove_old_options, $post_id ); | |
| 1060 | + | |
| 1061 | + if ( $remove_old_options ) { | |
| 1062 | + // Remove old (i.e. no longer existing) Table Options. | |
| 1063 | + $table_options = array_intersect_key( $table_options, $default_table['options'] ); | |
| 1064 | + } | |
| 1129 | 1065 | // Merge current into new Table Options. |
| 1130 | 1066 | $table_options = array_merge( $default_table['options'], $table_options ); |
| 1131 | 1067 | $this->_update_table_options( $post_id, $table_options ); |
| 1132 | 1068 | } |
| @@ -1132,14 +1068,13 @@ | ||
| 1132 | 1068 | } |
| 1133 | 1069 | } |
| 1134 | 1070 | |
| 1135 | 1071 | /** |
| 1136 | - * Convert old parameter names to new ones in DataTables "Custom Commands". | |
| 1137 | - * DataTables 1.9 used Hungarian notation, while DataTables 1.10+ (used since TablePress 1.5) uses camelCase notation. | |
| 1072 | + * Updates all tables' "Custom Commands" to use DataTables 2 variants instead of old DataTables 1.x CSS classes and parameters | |
| 1138 | 1073 | * |
| 1139 | - * @since 1.5.0 | |
| 1074 | + * @since 3.0.0 | |
| 1140 | 1075 | */ |
| 1141 | - public function convert_datatables_parameter_names_tp15() { | |
| 1076 | + public function update_custom_commands_datatables_tp30(): void { | |
| 1142 | 1077 | $table_post = $this->tables->get( 'table_post' ); |
| 1143 | 1078 | if ( empty( $table_post ) ) { |
| 1144 | 1079 | return; |
| 1145 | 1080 | } |
| @@ -1149,15 +1084,22 @@ | ||
| 1149 | 1084 | |
| 1150 | 1085 | foreach ( $table_post as $table_id => $post_id ) { |
| 1151 | 1086 | $table_options = $this->_get_table_options( $post_id ); |
| 1152 | 1087 | |
| 1088 | + // Fix tables where the "Custom Commands" entry is missing entirely. | |
| 1089 | + if ( ! isset( $table_options['datatables_custom_commands'] ) ) { | |
| 1090 | + $table_options['datatables_custom_commands'] = ''; | |
| 1091 | + $this->_update_table_options( $post_id, $table_options ); | |
| 1092 | + continue; | |
| 1093 | + } | |
| 1094 | + | |
| 1153 | 1095 | // Nothing to do if there are no "Custom Commands". |
| 1154 | - if ( empty( $table_options['datatables_custom_commands'] ) ) { | |
| 1096 | + if ( '' === $table_options['datatables_custom_commands'] ) { | |
| 1155 | 1097 | continue; |
| 1156 | 1098 | } |
| 1157 | 1099 | // Run search/replace. |
| 1158 | 1100 | $old_custom_commands = $table_options['datatables_custom_commands']; |
| 1159 | - $table_options['datatables_custom_commands'] = strtr( $table_options['datatables_custom_commands'], $this->datatables_parameter_mappings ); | |
| 1101 | + $table_options['datatables_custom_commands'] = TablePress::convert_datatables_api_data( $table_options['datatables_custom_commands'] ); | |
| 1160 | 1102 | // No need to save (which runs a DB query) if nothing was replaced in the "Custom Commands". |
| 1161 | 1103 | if ( $old_custom_commands === $table_options['datatables_custom_commands'] ) { |
| 1162 | 1104 | continue; |
| 1163 | 1105 | } |
| @@ -1170,9 +1112,9 @@ | ||
| 1170 | 1112 | * Invalidate all table output caches, e.g. after a plugin update. |
| 1171 | 1113 | * |
| 1172 | 1114 | * @since 1.0.0 |
| 1173 | 1115 | */ |
| 1174 | - public function invalidate_table_output_caches() { | |
| 1116 | + public function invalidate_table_output_caches(): void { | |
| 1175 | 1117 | $table_post = $this->tables->get( 'table_post' ); |
| 1176 | 1118 | if ( empty( $table_post ) ) { |
| 1177 | 1119 | return; |
| 1178 | 1120 | } |
| @@ -1177,8 +1119,9 @@ | ||
| 1177 | 1119 | return; |
| 1178 | 1120 | } |
| 1179 | 1121 | |
| 1180 | 1122 | foreach ( $table_post as $table_id => $post_id ) { |
| 1123 | + $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers. | |
| 1181 | 1124 | $this->invalidate_table_output_cache( $table_id ); |
| 1182 | 1125 | } |
| 1183 | 1126 | } |
| 1184 | 1127 | |
| @@ -1189,11 +1132,11 @@ | ||
| 1189 | 1132 | * @since 1.5.0 |
| 1190 | 1133 | * |
| 1191 | 1134 | * @global wpdb $wpdb WordPress database abstraction object. |
| 1192 | 1135 | */ |
| 1193 | - public function add_mime_type_to_posts() { | |
| 1136 | + public function add_mime_type_to_posts(): void { | |
| 1194 | 1137 | global $wpdb; |
| 1195 | - $wpdb->update( $wpdb->posts, array( 'post_mime_type' => 'application/json' ), array( 'post_type' => $this->model_post->get_post_type() ) ); | |
| 1138 | + $wpdb->update( $wpdb->posts, array( 'post_mime_type' => 'application/json' ), array( 'post_type' => $this->model_post->get_post_type() ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching | |
| 1196 | 1139 | } |
| 1197 | 1140 | |
| 1198 | 1141 | /** |
| 1199 | 1142 | * Add a table ID for a post (table) that was imported through the WP WXR importer to the table ID to post ID map. |
| @@ -1199,14 +1142,14 @@ | ||
| 1199 | 1142 | * Add a table ID for a post (table) that was imported through the WP WXR importer to the table ID to post ID map. |
| 1200 | 1143 | * |
| 1201 | 1144 | * @since 1.5.0 |
| 1202 | 1145 | * |
| 1203 | - * @param int $post_id Post ID of the imported post. | |
| 1204 | - * @param int $original_post_ID Original post ID that the post had on the site where it was exported from. | |
| 1205 | - * @param array $postdata Post data that was imported into the database. | |
| 1206 | - * @param array $post Original post data as it was exported. | |
| 1146 | + * @param int|WP_Error $post_id Post ID of the imported post on success. 0 or WP_Error on failure. | |
| 1147 | + * @param int $original_post_id Original post ID that the post had on the site where it was exported from. | |
| 1148 | + * @param array<string, mixed> $postdata Post data that was imported into the database. | |
| 1149 | + * @param array<string, mixed> $post Original post data as it was exported. | |
| 1207 | 1150 | */ |
| 1208 | - public function add_table_id_on_wp_import( $post_id, $original_post_ID, array $postdata, array $post ) { | |
| 1151 | + public function add_table_id_on_wp_import( /* int|WP_Error */ $post_id, int $original_post_id, array $postdata, array $post ): void { | |
| 1209 | 1152 | // Bail if the post could not be imported or if the post is not a TablePress table. |
| 1210 | 1153 | if ( is_wp_error( $post_id ) || $this->model_post->get_post_type() !== $postdata['post_type'] ) { |
| 1211 | 1154 | return; |
| 1212 | 1155 | } |
| @@ -1225,9 +1168,9 @@ | ||
| 1225 | 1168 | |
| 1226 | 1169 | // Save the post ID for each of the table IDs. |
| 1227 | 1170 | $post_id_saved = false; |
| 1228 | 1171 | foreach ( $table_ids as $table_id ) { |
| 1229 | - $table_id = preg_replace( '/[^a-zA-Z0-9_-]/', '', $table_id ); | |
| 1172 | + $table_id = (string) preg_replace( '/[^a-zA-Z0-9_-]/', '', $table_id ); | |
| 1230 | 1173 | if ( '' === $table_id || $this->table_exists( $table_id ) ) { |
| 1231 | 1174 | continue; |
| 1232 | 1175 | } |
| 1233 | 1176 | $this->_update_post_id( $table_id, $post_id ); |
| @@ -1245,14 +1188,14 @@ | ||
| 1245 | 1188 | * Remove the `_tablepress_export_table_id` post meta field from the fields that are imported during a WP WXR import. |
| 1246 | 1189 | * |
| 1247 | 1190 | * @since 1.5.0 |
| 1248 | 1191 | * |
| 1249 | - * @param array $postmeta Post meta fields for the post. | |
| 1250 | - * @param int $post_id Post ID. | |
| 1251 | - * @param array $post Post. | |
| 1252 | - * @return array Modified post meta fields. | |
| 1192 | + * @param array<string, mixed> $postmeta Post meta fields for the post. | |
| 1193 | + * @param int $post_id Post ID. | |
| 1194 | + * @param array<string, mixed> $post Post. | |
| 1195 | + * @return array<string, mixed> Modified post meta fields. | |
| 1253 | 1196 | */ |
| 1254 | - public function prevent_table_id_post_meta_import_on_wp_import( array $postmeta, $post_id, array $post ) { | |
| 1197 | + public function prevent_table_id_post_meta_import_on_wp_import( array $postmeta, int $post_id, array $post ): array { | |
| 1255 | 1198 | // Bail if the post is not a TablePress table. |
| 1256 | 1199 | if ( $this->model_post->get_post_type() !== $post['post_type'] ) { |
| 1257 | 1200 | return $postmeta; |
| 1258 | 1201 | } |
| @@ -1277,10 +1220,11 @@ | ||
| 1277 | 1220 | * |
| 1278 | 1221 | * @param bool $skip Whether to skip the current post meta. Default false. |
| 1279 | 1222 | * @param string $meta_key Current meta key. |
| 1280 | 1223 | * @param stdClass $meta Current meta object. |
| 1224 | + * @return bool Whether to skip the current post meta (unchanged $skip parameter). | |
| 1281 | 1225 | */ |
| 1282 | - public function add_table_id_to_wp_export( $skip, $meta_key, $meta ) { | |
| 1226 | + public function add_table_id_to_wp_export( bool $skip, string $meta_key, stdClass $meta ): bool { | |
| 1283 | 1227 | // Bail if the exporter doesn't process a TablePress table right now. |
| 1284 | 1228 | if ( $this->table_options_field_name !== $meta_key ) { |
| 1285 | 1229 | return $skip; |
| 1286 | 1230 | } |
| @@ -1295,17 +1239,24 @@ | ||
| 1295 | 1239 | } |
| 1296 | 1240 | |
| 1297 | 1241 | // Pretend that there is a `_tablepress_export_table_id` post meta field with the list of table IDs. |
| 1298 | 1242 | $key = '_tablepress_export_table_id'; |
| 1243 | + | |
| 1244 | + /** | |
| 1245 | + * Load WP export functions. | |
| 1246 | + */ | |
| 1247 | + require_once ABSPATH . 'wp-admin/includes/export.php'; // @phpstan-ignore requireOnce.fileNotFound (This is a WordPress core file that always exists.) | |
| 1299 | 1248 | $value = wxr_cdata( implode( ',', $table_ids ) ); |
| 1300 | 1249 | |
| 1301 | 1250 | // Hijack the filter and print extra XML code for our faked post meta field. |
| 1251 | + // phpcs:disable WordPress.Security.EscapeOutput.HeredocOutputNotEscaped | |
| 1302 | 1252 | echo <<<WXR |
| 1303 | - <wp:postmeta> | |
| 1304 | - <wp:meta_key>{$key}</wp:meta_key> | |
| 1305 | - <wp:meta_value>{$value}</wp:meta_value> | |
| 1306 | - </wp:postmeta>\n | |
| 1307 | -WXR; | |
| 1253 | + <wp:postmeta> | |
| 1254 | + <wp:meta_key>{$key}</wp:meta_key> | |
| 1255 | + <wp:meta_value>{$value}</wp:meta_value> | |
| 1256 | + </wp:postmeta>\n | |
| 1257 | + WXR; | |
| 1258 | + // phpcs:enable | |
| 1308 | 1259 | |
| 1309 | 1260 | return $skip; |
| 1310 | 1261 | } |
| 1311 | 1262 | |
| @@ -1313,9 +1264,9 @@ | ||
| 1313 | 1264 | * Delete the WP_Option of the model. |
| 1314 | 1265 | * |
| 1315 | 1266 | * @since 1.0.0 |
| 1316 | 1267 | */ |
| 1317 | - public function destroy() { | |
| 1268 | + public function destroy(): void { | |
| 1318 | 1269 | $this->tables->delete(); |
| 1319 | 1270 | } |
| 1320 | 1271 | |
| 1321 | 1272 | } // class TablePress_Table_Model |