PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.84
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.84
5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 5.5.41 5.5.42 All 160 releases
← All changes | WPDataAccess/API/WPDA_API_Core.php +240 -26 5.5.35.5.84 View file →
@@ -38,8 +38,15 @@
38 38 'validate_callback' => function ( $param ) {
39 39 return $this->validate_db_identifier( $param );
40 40 },
41 41 ),
42 + 'client_side' => array(
43 + 'required' => false,
44 + 'type' => 'boolean',
45 + 'description' => __( 'Server side processing', 'wp-data-access' ),
46 + 'sanitize_callback' => 'sanitize_text_field',
47 + 'validate_callback' => 'rest_validate_request_arg',
48 + ),
42 49 'app_id' => array(
43 50 'required' => true,
44 51 'type' => 'integer',
45 52 'description' => __( 'App ID', 'wp-data-access' ),
@@ -80,8 +87,15 @@
80 87 'description' => __( 'App settings', 'wp-data-access' ),
81 88 'sanitize_callback' => 'sanitize_text_field',
82 89 'validate_callback' => 'rest_validate_request_arg',
83 90 ),
91 + 'app_add_to_menu' => array(
92 + 'required' => true,
93 + 'type' => 'integer',
94 + 'description' => __( 'Add app to dashboard menu', 'wp-data-access' ),
95 + 'sanitize_callback' => 'absint',
96 + 'validate_callback' => 'rest_validate_request_arg',
97 + ),
84 98 'app_cls' => array(
85 99 'required' => true,
86 100 'type' => 'array',
87 101 'description' => __( 'App columns', 'wp-data-access' ),
@@ -91,8 +105,70 @@
91 105 'validate_callback' => function ( $param ) {
92 106 return $this->validate_columns( $param );
93 107 },
94 108 ),
109 + 'join_tab' => array(
110 + 'required' => false,
111 + 'type' => 'boolean',
112 + 'description' => __( 'Use join table', 'wp-data-access' ),
113 + 'sanitize_callback' => 'sanitize_text_field',
114 + 'validate_callback' => 'rest_validate_request_arg',
115 + ),
116 + 'rel_tab' => array(
117 + 'required' => false,
118 + 'type' => 'boolean',
119 + 'description' => __( 'Use relation table', 'wp-data-access' ),
120 + 'sanitize_callback' => 'sanitize_text_field',
121 + 'validate_callback' => 'rest_validate_request_arg',
122 + ),
123 + 'md' => array(
124 + 'required' => false,
125 + 'type' => 'mixed',
126 + 'description' => __( 'Master detail join conditions', 'wp-data-access' ),
127 + 'sanitize_callback' => function ( $param ) {
128 + $columns = array();
129 + foreach ( rest_sanitize_object( $param ) as $column_name => $value ) {
130 + $columns[$this->sanitize_db_identifier( $column_name )] = sanitize_text_field( wp_unslash( $value ) );
131 + }
132 + return $columns;
133 + },
134 + 'validate_callback' => function ( $param ) {
135 + return is_array( $param );
136 + },
137 + ),
138 + 'cascade' => array(
139 + 'required' => false,
140 + 'type' => 'boolean',
141 + 'description' => __( 'Use search arguments if true', 'wp-data-access' ),
142 + 'sanitize_callback' => 'sanitize_text_field',
143 + 'validate_callback' => 'rest_validate_request_arg',
144 + ),
145 + 'app_apps' => array(
146 + 'required' => false,
147 + 'type' => 'array',
148 + 'description' => __( 'Array of app IDs', 'wp-data-access' ),
149 + 'sanitize_callback' => function ( $param ) {
150 + $apps = array();
151 + foreach ( $param as $value ) {
152 + if ( is_numeric( $value ) ) {
153 + $apps[] = $value;
154 + }
155 + }
156 + return $apps;
157 + },
158 + 'validate_callback' => function ( $param ) {
159 + return is_array( $param );
160 + },
161 + ),
162 + 'app_query' => array(
163 + 'required' => false,
164 + 'type' => 'string',
165 + 'description' => __( 'Custom query', 'wp-data-access' ),
166 + 'sanitize_callback' => function ( $param ) {
167 + return html_entity_decode( wp_unslash( $param ), ENT_QUOTES );
168 + // Preserve SQL operators
169 + },
170 + ),
95 171 'col' => array(
96 172 'required' => true,
97 173 'type' => 'string',
98 174 'description' => __( 'Column name', 'wp-data-access' ),
@@ -103,9 +179,9 @@
103 179 return $this->validate_db_identifier( $param );
104 180 },
105 181 ),
106 182 'cols' => array(
107 - 'required' => true,
183 + 'required' => false,
108 184 'type' => 'mixed',
109 185 'description' => __( 'Table or view columns', 'wp-data-access' ),
110 186 'sanitize_callback' => function ( $param ) {
111 187 $columns = array();
@@ -121,9 +197,9 @@
121 197 'page_index' => array(
122 198 'required' => false,
123 199 'type' => 'integer',
124 200 'description' => __( 'Page number', 'wp-data-access' ),
125 - 'default' => 1,
201 + 'default' => 0,
126 202 'minimum' => 0,
127 203 'sanitize_callback' => 'absint',
128 204 'validate_callback' => 'rest_validate_request_arg',
129 205 ),
@@ -184,18 +260,65 @@
184 260 'required' => false,
185 261 'type' => 'mixed',
186 262 'description' => __( 'Search columns for lov support', 'wp-data-access' ),
187 263 'sanitize_callback' => function ( $param ) {
188 - $columns = array();
189 - foreach ( rest_sanitize_object( $param ) as $column_name => $value ) {
190 - $columns[$this->sanitize_db_identifier( $column_name )] = sanitize_text_field( wp_unslash( $value ) );
264 + $lovs = array();
265 + foreach ( $param as $value ) {
266 + $lovs[] = $this->sanitize_db_identifier( $value );
191 267 }
192 - return $columns;
268 + return $lovs;
193 269 },
194 270 'validate_callback' => function ( $param ) {
195 271 return is_array( $param );
196 272 },
197 273 ),
274 + 'search_data_types' => array(
275 + 'required' => false,
276 + 'type' => 'mixed',
277 + 'description' => __( 'Search columns for lov support', 'wp-data-access' ),
278 + 'sanitize_callback' => function ( $param ) {
279 + $date_types = array();
280 + foreach ( $param as $key => $value ) {
281 + $date_types[$this->sanitize_db_identifier( $key )] = sanitize_text_field( $value );
282 + }
283 + return $date_types;
284 + },
285 + 'validate_callback' => function ( $param ) {
286 + return is_array( $param );
287 + },
288 + ),
289 + 'search_custom' => array(
290 + 'required' => false,
291 + 'description' => __( 'Custom search filters auto generated from http parameter requirements in default where', 'wp-data-access' ),
292 + 'sanitize_callback' => function ( $param ) {
293 + $search_custom = array();
294 + foreach ( $param as $key => $value ) {
295 + if ( is_array( $value ) ) {
296 + foreach ( $value as $column_name => $column_value ) {
297 + $search_custom[$key][$this->sanitize_db_identifier( $column_name )] = sanitize_text_field( $column_value );
298 + }
299 + }
300 + }
301 + return $search_custom;
302 + },
303 + 'validate_callback' => function ( $param ) {
304 + return is_array( $param );
305 + },
306 + ),
307 + 'search_params' => array(
308 + 'required' => false,
309 + 'description' => __( 'Shortcode parameters', 'wp-data-access' ),
310 + 'sanitize_callback' => function ( $param ) {
311 + $search_custom = array();
312 + foreach ( $param as $key => $value ) {
313 + $search_custom[$this->sanitize_db_identifier( $key )] = sanitize_text_field( $value );
314 + }
315 + return $search_custom;
316 + },
317 + 'validate_callback' => function ( $param ) {
318 + return is_array( $param );
319 + },
320 + ),
198 321 'sorting' => array(
199 322 'required' => false,
200 323 'description' => __( 'Order by (array of { id and desc })', 'wp-data-access' ),
201 324 'sanitize_callback' => function ( $param ) {
@@ -259,10 +382,19 @@
259 382 'validate_callback' => function ( $param ) {
260 383 return is_array( $param );
261 384 },
262 385 ),
386 + 'typ' => array(
387 + 'required' => true,
388 + 'type' => 'integer',
389 + 'description' => __( 'Type = 0, view = 1', 'wp-data-access' ),
390 + 'minimum' => 0,
391 + 'maximum' => 1,
392 + 'sanitize_callback' => 'absint',
393 + 'validate_callback' => 'rest_validate_request_arg',
394 + ),
263 395 'media' => array(
264 - 'required' => true,
396 + 'required' => false,
265 397 'type' => 'mixed',
266 398 'description' => __( 'Media columns', 'wp-data-access' ),
267 399 'sanitize_callback' => function ( $param ) {
268 400 $media = array();
@@ -274,14 +406,87 @@
274 406 'validate_callback' => function ( $param ) {
275 407 return is_array( $param );
276 408 },
277 409 ),
410 + 'copy_key' => array(
411 + 'required' => true,
412 + 'type' => 'string',
413 + 'description' => __( 'Internal copy action identifier', 'wp-data-access' ),
414 + 'sanitize_callback' => 'sanitize_text_field',
415 + 'validate_callback' => 'rest_validate_request_arg',
416 + ),
417 + 'access' => array(
418 + 'required' => true,
419 + 'type' => 'string',
420 + 'description' => __( 'Access (user | global) ', 'wp-data-access' ),
421 + 'sanitize_callback' => function ( $param ) {
422 + return ( 'global' === strtolower( $param ) ? 'global' : 'user' );
423 + },
424 + 'validate_callback' => function ( $param ) {
425 + return 'global' === strtolower( $param ) || 'user' === strtolower( $param );
426 + },
427 + ),
428 + 'query' => array(
429 + 'required' => true,
430 + 'type' => 'string',
431 + 'description' => __( 'SQL query', 'wp-data-access' ),
432 + 'sanitize_callback' => function ( $param ) {
433 + return html_entity_decode( wp_unslash( $param ), ENT_QUOTES );
434 + // Preserve SQL operators
435 + },
436 + ),
437 + 'name' => array(
438 + 'required' => true,
439 + 'type' => 'string',
440 + 'description' => __( 'Query name', 'wp-data-access' ),
441 + 'sanitize_callback' => 'sanitize_text_field',
442 + 'validate_callback' => 'rest_validate_request_arg',
443 + ),
444 + 'vqb' => array(
445 + 'required' => false,
446 + 'type' => 'mixed',
447 + 'description' => __( 'Visual Query Builder', 'wp-data-access' ),
448 + 'sanitize_callback' => function ( $param ) {
449 + return rest_sanitize_object( $param );
450 + },
451 + 'validate_callback' => 'rest_validate_request_arg',
452 + ),
453 + 'params' => array(
454 + 'required' => false,
455 + 'type' => 'array',
456 + 'description' => __( 'Cron job parameters', 'wp-data-access' ),
457 + 'sanitize_callback' => function ( $param ) {
458 + $params = array();
459 + if ( is_array( $param ) ) {
460 + foreach ( $param as $key => $value ) {
461 + if ( 'params' === $key || 'notify' === $key ) {
462 + // Sanitize custom parameters
463 + $custom_params = array();
464 + foreach ( $value as $param_key => $param_value ) {
465 + $custom_params[sanitize_text_field( $param_key )] = sanitize_text_field( $param_value );
466 + }
467 + $params[sanitize_text_field( $key )] = $custom_params;
468 + } else {
469 + $params[sanitize_text_field( $key )] = sanitize_text_field( $value );
470 + }
471 + }
472 + }
473 + return $params;
474 + },
475 + 'validate_callback' => function ( $param ) {
476 + return is_array( $param );
477 + },
478 + ),
278 479 );
279 480 }
280 481
281 - protected function get_param( $key ) {
482 + protected function get_param( $key, $description = null ) {
282 483 if ( isset( $this->params[$key] ) ) {
283 - return $this->params[$key];
484 + $param = $this->params[$key];
485 + if ( null !== $description ) {
486 + $param['description'] = $description;
487 + }
488 + return $param;
284 489 } else {
285 490 // Force REST API error
286 491 return false;
287 492 }
@@ -303,10 +508,10 @@
303 508 }
304 509 return WPDA_API_Core::$user_login;
305 510 }
306 511
307 - protected function current_user_can_access( $admins_only = false ) {
308 - return in_array( 'administrator', $this->get_user_roles() );
512 + protected function current_user_can_access() {
513 + return WPDA::current_user_is_admin();
309 514 }
310 515
311 516 protected function unauthorized() {
312 517 return new \WP_Error('error', __( 'Unauthorized', 'wp-data-access' ), array(
@@ -313,9 +518,9 @@
313 518 'status' => 401,
314 519 ));
315 520 }
316 521
317 - protected function current_user_token_valid( $request, $token_required = false ) {
522 + protected function current_user_token_valid( $request ) {
318 523 return wp_verify_nonce( $request->get_header( 'X-WP-Nonce' ), 'wp_rest' );
319 524 }
320 525
321 526 protected function invalid_nonce() {
@@ -339,9 +544,12 @@
339 544 protected function current_user_can_remote() {
340 545 return false;
341 546 }
342 547
343 - protected function sanitize_db_identifier( $param ) {
548 + public static function sanitize_db_identifier( $param ) {
549 + if ( !is_string( $param ) ) {
550 + return null;
551 + }
344 552 // Preserve starting and trailing spaces
345 553 $spaces_before = strlen( $param ) - strlen( ltrim( $param ) );
346 554 $spaces_after = strlen( $param ) - strlen( rtrim( $param ) );
347 555 return str_repeat( ' ', $spaces_before ) . WPDA::remove_backticks( sanitize_text_field( $param ) ) . str_repeat( ' ', $spaces_after );
@@ -346,9 +554,9 @@
346 554 $spaces_after = strlen( $param ) - strlen( rtrim( $param ) );
347 555 return str_repeat( ' ', $spaces_before ) . WPDA::remove_backticks( sanitize_text_field( $param ) ) . str_repeat( ' ', $spaces_after );
348 556 }
349 557
350 - protected function validate_db_identifier( $param ) {
558 + public static function validate_db_identifier( $param ) {
351 559 return !empty( WPDA::remove_backticks( $param ) );
352 560 }
353 561
354 562 protected function sanitize_columns( $param ) {
@@ -395,15 +603,16 @@
395 603 return $users;
396 604 }
397 605
398 606 protected function get_env() {
399 - return array(
400 - 'ip' => $_SERVER['REMOTE_ADDR'],
607 + $env = array(
608 + 'ip' => ( isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '' ),
401 609 'id' => WPDA::get_current_user_id(),
402 610 'user' => WPDA::get_current_user_login(),
403 611 'roles' => WPDA::get_current_user_roles(),
404 612 'login' => 'anonymous' !== WPDA::get_current_user_login(),
405 613 );
614 + return $env;
406 615 }
407 616
408 617 protected function get_table_info( $dbs, $tbl, $default_where = '' ) {
409 618 $wpdadb = WPDADB::get_db_connection( $dbs );
@@ -413,17 +622,16 @@
413 622 'engine' => null,
414 623 'count' => null,
415 624 );
416 625 }
417 - $query = $wpdadb->prepare( "\n\t\t\t\t\tselect table_type,\n\t\t\t\t\t engine,\n\t\t\t\t\t table_rows\n\t\t\t\t\t from information_schema.tables\n\t\t\t\t\t where table_schema = %s\n\t\t\t\t\t and table_name = %s\n\t\t\t\t\t order by table_name\n\t\t\t\t", array($wpdadb->dbname, $tbl) );
626 + $query = $wpdadb->prepare( "\n\t\t\t\t\tselect table_type,\n\t\t\t\t\t engine,\n\t\t\t\t\t table_rows\n\t\t\t\t\t from information_schema.tables\n\t\t\t\t\t where table_schema = %s\n\t\t\t\t\t and table_name = %s\n\t\t\t\t", array($wpdadb->dbname, $tbl) );
418 627 $resultset = $wpdadb->get_results( $query, 'ARRAY_N' );
419 - // phpcs:ignore Standard.Category.SniffName.ErrorCode
420 628 if ( count( $resultset ) === 1 ) {
421 629 if ( null !== $resultset[0][2] ) {
422 630 return array(
423 631 'type' => $resultset[0][0],
424 632 'engine' => $resultset[0][1],
425 - 'count' => ( '' === $default_where ? ( $resultset[0][2] === 0 ? null : $resultset[0][2] ) : null ),
633 + 'count' => ( '' === $default_where ? ( $resultset[0][2] == 0 ? null : $resultset[0][2] ) : null ),
426 634 );
427 635 } else {
428 636 $count = $this->get_row_count_estimate( $dbs, $tbl );
429 637 return array(
@@ -454,20 +662,26 @@
454 662 return -1;
455 663 }
456 664 }
457 665
458 - protected function get_media( $dbs, $tbl, $columns ) {
666 + protected function get_media(
667 + $dbs,
668 + $tbl,
669 + $columns,
670 + $prefix = ''
671 + ) {
459 672 $media = array();
460 673 $wp_media = array();
461 674 foreach ( $columns as $column ) {
462 675 $media_type = WPDA_Media_Model::get_column_media( $tbl, $column['column_name'], $dbs );
676 + $column_name = $prefix . $column['column_name'];
463 677 switch ( $media_type ) {
464 678 case 'ImageURL':
465 - $media[$column['column_name']] = $media_type;
679 + $media[$column_name] = $media_type;
466 680 break;
467 681 case 'Hyperlink':
468 682 // Get table settings.
469 - $table_settings_db = WPDA_Table_Settings_Model::query( $dbs, $tbl );
683 + $table_settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
470 684 if ( isset( $table_settings_db[0]['wpda_table_settings'] ) ) {
471 685 $table_settings = json_decode( $table_settings_db[0]['wpda_table_settings'], true );
472 686 } else {
473 687 $table_settings = null;
@@ -473,20 +687,20 @@
473 687 $table_settings = null;
474 688 }
475 689 // Check hyperlink format.
476 690 if ( isset( $table_settings['table_settings']['hyperlink_definition'] ) && 'text' === $table_settings['table_settings']['hyperlink_definition'] ) {
477 - $media[$column['column_name']] = 'HyperlinkURL';
691 + $media[$column_name] = 'HyperlinkURL';
478 692 } else {
479 - $media[$column['column_name']] = 'HyperlinkObject';
693 + $media[$column_name] = 'HyperlinkObject';
480 694 }
481 695 break;
482 696 default:
483 697 if ( false !== $media_type ) {
484 698 // Handle WordPress Media Library integration
485 - $media[$column['column_name']] = "WP-{$media_type}";
699 + $media[$column_name] = "WP-{$media_type}";
486 700 }
487 701 }
488 - $wp_media[$column['column_name']] = $media_type;
702 + $wp_media[$column_name] = $media_type;
489 703 }
490 704 return [
491 705 'media' => $media,
492 706 'wp_media' => $wp_media,