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
wp-data-access / WPDataAccess / Data_Tables / WPDA_Data_Tables.php

WPDA_Data_Tables.php in WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards 5.5.84, at WPDataAccess/Data_Tables/WPDA_Data_Tables.php

1,326 lines 63.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Suppress "error - 0 - No summary was found for this file" on phpdoc generation
5 *
6 * @package WPDataAccess\Data_Tables
7 */
8 // phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- verified on page
9 namespace WPDataAccess\Data_Tables;
10
11 use stdClass;
12 use WPDataAccess\API\WPDA_Apps;
13 use WPDataAccess\Connection\WPDADB;
14 use WPDataAccess\Data_Dictionary\WPDA_Dictionary_Exist;
15 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
16 use WPDataAccess\Macro\WPDA_Macro;
17 use WPDataAccess\Plugin_Table_Models\WPDA_Publisher_Model;
18 use WPDataAccess\Plugin_Table_Models\WPDA_Media_Model;
19 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
20 use WPDataAccess\List_Table\WPDA_List_Table;
21 use WPDataAccess\Premium\WPDAPRO_Data_Publisher\WPDAPRO_Data_Publisher_Manage_Styles;
22 use WPDataAccess\Premium\WPDAPRO_Geo_Location\WPDAPRO_Geo_Location_WS;
23 use WPDataAccess\Settings\WPDA_Settings_Legacy_DataTables;
24 use WPDataAccess\WPDA;
25 /**
26 * Class WPDA_Data_Tables
27 *
28 * @author Peter Schulz
29 * @since 1.0.0
30 */
31 class WPDA_Data_Tables {
32 protected static $pub_ids = array();
33
34 protected $pub_id_seq = '';
35
36 protected $wpda_list_columns = null;
37
38 protected $wpda_dictionary_checks = null;
39
40 protected $json = null;
41
42 protected $table_settings = null;
43
44 protected $hyperlink_positions = array();
45
46 protected $columns = array();
47
48 protected $column_labels = null;
49
50 protected $primary_index_sorted = array();
51
52 protected $buttons = '[]';
53
54 //CWG This is correct
55 protected $geomap = '';
56
57 protected $geo_search = '';
58
59 protected $geo_search_type = null;
60
61 protected $read_more_html = '';
62
63 protected $serverSide = false;
64
65 public static function enqueue_styles_and_script( $styling = 'default' ) {
66 wp_enqueue_script( 'jquery-ui-draggable' );
67 wp_enqueue_script( 'jquery-ui-resizable' );
68 // Plugin css
69 wp_enqueue_style( 'wpda_datatables_default' );
70 wp_enqueue_style( 'dashicons' );
71 // Needed to display icons for media attachments
72 // Plugin js
73 wp_enqueue_script( 'wpda_datatables' );
74 // Add jQuery DataTables library scripts
75 if ( is_admin() && WPDA::get_option( WPDA::OPTION_BE_LOAD_DATATABLES ) === 'on' || !is_admin() && WPDA::get_option( WPDA::OPTION_FE_LOAD_DATATABLES ) === 'on' ) {
76 wp_enqueue_script( 'jquery_datatables' );
77 }
78 if ( is_admin() && WPDA::get_option( WPDA::OPTION_BE_LOAD_DATATABLES_RESPONSE ) === 'on' || !is_admin() && WPDA::get_option( WPDA::OPTION_FE_LOAD_DATATABLES_RESPONSE ) === 'on' ) {
79 wp_enqueue_script( 'jquery_datatables_responsive' );
80 }
81 $style_added = false;
82 if ( !$style_added || 'default' === $styling ) {
83 // Add jQuery DataTables library styles
84 if ( is_admin() && WPDA::get_option( WPDA::OPTION_BE_LOAD_DATATABLES ) === 'on' || !is_admin() && WPDA::get_option( WPDA::OPTION_FE_LOAD_DATATABLES ) === 'on' ) {
85 wp_enqueue_style( 'jquery_datatables' );
86 }
87 if ( is_admin() && WPDA::get_option( WPDA::OPTION_BE_LOAD_DATATABLES_RESPONSE ) === 'on' || !is_admin() && WPDA::get_option( WPDA::OPTION_FE_LOAD_DATATABLES_RESPONSE ) === 'on' ) {
88 wp_enqueue_style( 'jquery_datatables_responsive' );
89 }
90 }
91 }
92
93 /**
94 * Generate jQuery DataTable code
95 *
96 * Table and column names provided are checked for existency and access to prevent hacking the DataTable code
97 * and SQL injection.
98 *
99 * @param int $pub_id Table ID.
100 * @param string $pub_name Table name.
101 * @param string $database Database name.
102 * @param string $table_name Database table name.
103 * @param string $column_names Comma separated list of column names.
104 * @param string $responsive Yes = responsive mode, No = No responsive mode.
105 * @param int $responsive_cols Number of columns to be displayed in responsive mode.
106 * @param string $responsive_type Modal, Collapsed or Expanded (only if $responsive = Yes).
107 * @param string $responsive_icon Yes = show icon, No = do not show icon (only if $responsive = Yes).
108 * @param string $sql_orderby SQL default order by
109 * @param string $filter_field_name Filter field name (CSV)
110 * @param string $filter_field_value Filter field value (CSV)
111 * @param string $nl2br Convert New Line characters to BR tags
112 *
113 * @return string response wpda_datatables_ajax_call
114 *
115 * @since 1.0.0
116 */
117 public function show(
118 $pub_id,
119 $pub_name,
120 $database,
121 $table_name,
122 $column_names,
123 $responsive,
124 $responsive_cols,
125 $responsive_type,
126 $responsive_icon,
127 $sql_orderby,
128 $filter_field_name = '',
129 $filter_field_value = '',
130 $nl2br = '',
131 $dashboard_styling = false,
132 $is_embedded = false
133 ) {
134 if ( '' === $pub_id && '' === $pub_name && '' === $table_name ) {
135 return '<p>' . __( 'ERROR: Missing argument [need at least pub_id, pub_name or table argument]', 'wp-data-access' ) . '</p>';
136 }
137 if ( '' !== $pub_id || '' !== $pub_name ) {
138 // Get data table information
139 if ( '' !== $pub_id ) {
140 $publication = WPDA_Publisher_Model::get_publication( $pub_id );
141 } else {
142 $publication = WPDA_Publisher_Model::get_publication_by_name( $pub_name );
143 }
144 if ( false === $publication ) {
145 // Querying tables in other schema's is not allowed!
146 return '<p>' . __( 'ERROR: Data table not found', 'wp-data-access' ) . '</p>';
147 }
148 $pub_id = $publication[0]['pub_id'];
149 $database = $publication[0]['pub_schema_name'];
150 $data_source = $publication[0]['pub_data_source'];
151 $table_name = $publication[0]['pub_table_name'];
152 $column_names = $publication[0]['pub_column_names'];
153 if ( null === $column_names || '' === trim( $column_names ) ) {
154 $column_names = '*';
155 }
156 $pub_query = $publication[0]['pub_query'];
157 $pub_cpt_query = $publication[0]['pub_cpt_query'];
158 $pub_cpt_format = $publication[0]['pub_cpt_format'];
159 $responsive = strtolower( (string) $publication[0]['pub_responsive'] );
160 $responsive_popup_title = $publication[0]['pub_responsive_popup_title'];
161 $responsive_cols = $publication[0]['pub_responsive_cols'];
162 $responsive_type = strtolower( (string) $publication[0]['pub_responsive_type'] );
163 $responsive_icon = strtolower( (string) $publication[0]['pub_responsive_icon'] );
164 $pub_flat_scrollx = strtolower( (string) $publication[0]['pub_flat_scrollx'] );
165 $pub_format = $publication[0]['pub_format'];
166 $sql_orderby = $publication[0]['pub_default_orderby'];
167 if ( null === $sql_orderby || 'null' === $sql_orderby ) {
168 $sql_orderby = '';
169 }
170 $pub_table_options_searching = $publication[0]['pub_table_options_searching'];
171 $pub_table_options_ordering = $publication[0]['pub_table_options_ordering'];
172 $pub_table_options_paging = $publication[0]['pub_table_options_paging'];
173 $pub_table_options_serverside = $publication[0]['pub_table_options_serverside'];
174 $pub_table_options_advanced = $publication[0]['pub_table_options_advanced'];
175 $pub_table_options_advanced = str_replace( array("\r", "\n", "\t"), '', (string) $pub_table_options_advanced );
176 $pub_responsive_modal_hyperlinks = $publication[0]['pub_responsive_modal_hyperlinks'];
177 $pub_sort_icons = $publication[0]['pub_sort_icons'];
178 $pub_styles = $publication[0]['pub_styles'];
179 $pub_extentions = $publication[0]['pub_extentions'];
180 if ( !isset( self::$pub_ids[$pub_id] ) ) {
181 self::$pub_ids[$pub_id] = 1;
182 $this->pub_id_seq = '';
183 } else {
184 self::$pub_ids[$pub_id]++;
185 $this->pub_id_seq = '_' . self::$pub_ids[$pub_id];
186 }
187 } else {
188 $pub_id = '0';
189 $data_source = 'Table';
190 $pub_query = null;
191 $pub_cpt_query = null;
192 $pub_cpt_format = '';
193 $responsive_popup_title = '';
194 $pub_format = '';
195 $pub_table_options_searching = 'on';
196 $pub_table_options_ordering = 'on';
197 $pub_table_options_paging = 'on';
198 $pub_table_options_serverside = 'on';
199 $pub_table_options_advanced = '';
200 $pub_responsive_modal_hyperlinks = '';
201 $pub_sort_icons = 'default';
202 $pub_styles = 'default';
203 $pub_extentions = '';
204 $pub_flat_scrollx = 'no';
205 $this->pub_id_seq = '';
206 }
207 // Activate scripts and styles
208 $styling = $this->set_style( $dashboard_styling, ( isset( $publication ) ? $publication : null ) );
209 self::enqueue_styles_and_script( $styling );
210 // Create JSON object from advanced settings
211 try {
212 $this->json = json_decode( (string) $pub_table_options_advanced );
213 if ( null === $this->json || is_array( $this->json ) ) {
214 $this->json = new stdClass();
215 }
216 } catch ( \Exception $e ) {
217 $this->json = new stdClass();
218 }
219 // Add extension support
220 $this->extension_wizard( $pub_extentions );
221 // Check for extra header column
222 $header2 = $this->add_extra_header();
223 // Check button usage
224 $use_buttons_extension = $this->use_buttons_extension();
225 switch ( $pub_sort_icons ) {
226 case 'none':
227 // Hide sort icons
228 wp_enqueue_style( 'wpda_datatables_hide_sort_icons' );
229 break;
230 default:
231 }
232 if ( 'on' !== $pub_table_options_searching || null === $pub_table_options_searching ) {
233 $pub_table_options_searching = 'false';
234 } else {
235 $pub_table_options_searching = 'true';
236 }
237 if ( 'on' !== $pub_table_options_ordering || null === $pub_table_options_ordering ) {
238 $pub_table_options_ordering = 'false';
239 } else {
240 $pub_table_options_ordering = 'true';
241 }
242 if ( 'on' !== $pub_table_options_paging || null === $pub_table_options_paging ) {
243 $pub_table_options_paging = 'false';
244 } else {
245 $pub_table_options_paging = 'true';
246 }
247 if ( !isset( $this->json->serverSide ) ) {
248 if ( 'on' !== $pub_table_options_serverside || null === $pub_table_options_serverside ) {
249 $this->json->serverSide = false;
250 }
251 }
252 if ( '' === $responsive_popup_title || null === $responsive_popup_title || 'Row details' === $responsive_popup_title ) {
253 $responsive_popup_title = __( 'Row details', 'wp-data-access' );
254 // Set title of modal window here to support i18n.
255 }
256 // WordPress database is default
257 if ( '' === $database ) {
258 global $wpdb;
259 $database = $wpdb->dbname;
260 }
261 if ( 'Query' === $data_source || 'CPT' === $data_source ) {
262 } else {
263 // Check if table exists to prevent SQL injection
264 $this->wpda_dictionary_checks = new WPDA_Dictionary_Exist($database, $table_name);
265 if ( !$this->wpda_dictionary_checks->table_exists( '0' === $pub_id, false ) ) {
266 // Table not found.
267 return '<p>' . __( 'ERROR: Invalid table name or not authorized', 'wp-data-access' ) . '</p>';
268 }
269 // Load table settings
270 $table_settings_db = WPDA_Table_Settings_Model::query( $table_name, $database );
271 if ( isset( $table_settings_db[0]['wpda_table_settings'] ) ) {
272 $this->table_settings = json_decode( (string) $table_settings_db[0]['wpda_table_settings'] );
273 }
274 // Get table settings > hyperlinks
275 $hyperlinks = array();
276 if ( isset( $this->table_settings->hyperlinks ) ) {
277 foreach ( $this->table_settings->hyperlinks as $hyperlink ) {
278 $hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' );
279 $hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' );
280 if ( $hyperlink_label !== '' && $hyperlink_html !== '' ) {
281 array_push( $hyperlinks, $hyperlink_label );
282 }
283 }
284 }
285 // Check for geolocation support
286 $geolocation = $this->get_geolocation_settings();
287 $row_count_estimate = WPDA::get_row_count_estimate( $database, $table_name, $this->table_settings );
288 $calc_estimate = $row_count_estimate['is_estimate'];
289 // Get table columns
290 $this->wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $database, $table_name );
291 // Set columns to be queried
292 $this->columns = $this->get_columns( $column_names );
293 // Get column labels
294 $this->column_labels = $this->get_labels( $pub_format );
295 // Define dat table columns
296 $wpda_database_columns = $this->define_columns( $use_buttons_extension, $hyperlinks, $geolocation );
297 }
298 // Run filters to allow plugin users to add custom features
299 if ( has_filter( 'wpda_wpdataaccess_prepare' ) ) {
300 $wpda_wpdataaccess_prepare_filter = apply_filters(
301 'wpda_wpdataaccess_prepare',
302 '',
303 $database,
304 $table_name,
305 $pub_id,
306 $this->columns,
307 $this->table_settings
308 );
309 } else {
310 $wpda_wpdataaccess_prepare_filter = '';
311 }
312 // Get jQuery DataTables language
313 $language = $this->get_language();
314 // Create dynamic columns variable name (must be unique per data table to support multiple data tables on one page)
315 $columnsvar = 'wpdaDbColumns' . preg_replace( '/[^a-zA-Z0-9]/', '', $table_name ) . $pub_id;
316 // Add button extension
317 $this->add_buttons( $use_buttons_extension, $pub_id, $table_name );
318 // Add geolocation support
319 $this->add_geolocation(
320 $geolocation,
321 $pub_id,
322 $table_name,
323 $database
324 );
325 // Add read more button
326 $read_more = $this->add_read_more( $pub_id, $table_name, $pub_table_options_paging );
327 // Update extra header of necessary
328 $header2 = $this->update_extra_header( $header2, $pub_table_options_searching );
329 // Apply global styling
330 $dataTablesClass = $this->add_global_style( $styling, $pub_styles );
331 // Themes like DIVI use IDs to overwrite all defaults of others. This style reassures correct positioning
332 // of the responsive icon. This cannot be added to the plugin CSS files. It needs an ID to overwrite other
333 // ID styling.
334 $styling_default = "\n\t\t\t\t<style>\n\t\t\t\t\t#" . esc_attr( $table_name ) . "{$pub_id}.dataTable.wpda-datatable.dtr-inline.collapsed>tbody>tr>td.dtr-control,\n\t\t\t\t\t#" . esc_attr( $table_name ) . "{$pub_id}.dataTable.wpda-datatable.dtr-inline.collapsed>tbody>tr>th.dtr-control {\n \t\t\t\t\tpadding-left: 2.2em;\n\t\t\t\t\t}\n\t\t\t\t</style>";
335 // Add premium styling
336 $styling_template = $this->add_styling_template(
337 $pub_id,
338 $table_name,
339 $dashboard_styling,
340 ( isset( $publication ) ? $publication : null )
341 );
342 // Prepare values needed for ajax request
343 $database_value = $database;
344 $column_names_value = $column_names;
345 if ( '0' != $pub_id ) {
346 $database_value = '';
347 $column_names_value = '';
348 }
349 // Convert JSON to string
350 $json_value = $this->prepare_json( $responsive, $pub_flat_scrollx );
351 // Generate nonce
352 $wpnonce = $this->generate_nonce( $table_name, $column_names_value, $is_embedded );
353 $wpda_post_vars = [];
354 $http_get_args = [];
355 $http_post_args = [];
356 return $wpda_wpdataaccess_prepare_filter . $styling_default . $styling_template . "<div class='wpda_publication_container'><table id=\"" . esc_attr( $table_name ) . "{$pub_id}{$this->pub_id_seq}\" class=\"{$dataTablesClass}\" cellspacing=\"0\">" . '<thead>' . $this->show_header(
357 $responsive,
358 $responsive_cols,
359 $hyperlinks,
360 $header2,
361 $geolocation
362 ) . '</thead>' . '<tfoot>' . $this->show_header(
363 $responsive,
364 $responsive_cols,
365 $hyperlinks,
366 '',
367 $geolocation
368 ) . '</tfoot>' . '</table></div>' . $this->read_more_html . "<script type='text/javascript'>" . "var {$columnsvar}_advanced_options = " . $json_value . '; ' . "var {$columnsvar} = [" . $wpda_database_columns . '];' . "var {$columnsvar}_geosearch_options = " . json_encode( $this->geo_search_type ) . '; ' . "var {$table_name}_{$pub_id}_args = [" . json_encode( $wpda_post_vars, true ) . ']; ' . "var {$table_name}_{$pub_id}_gets = [" . json_encode( $http_get_args, true ) . ']; ' . "var {$table_name}_{$pub_id}_posts = [" . json_encode( $http_post_args, true ) . ']; ' . 'jQuery(function () {' . ' wpda_datatables_ajax_call(' . "\t\t{$columnsvar}," . ' "' . esc_attr( $database_value ) . '",' . ' "' . esc_attr( $table_name ) . '",' . ' "' . esc_attr( $column_names_value ) . '",' . ' "' . esc_attr( $responsive ) . '",' . ' "' . esc_attr( $responsive_popup_title ) . '",' . ' "' . esc_attr( $responsive_type ) . '",' . ' "' . esc_attr( $responsive_icon ) . '",' . ' "' . esc_attr( $language ) . '",' . ' "' . htmlentities( $sql_orderby ) . '",' . "\t\t{$pub_table_options_searching}," . "\t {$pub_table_options_ordering}," . "\t\t{$pub_table_options_paging}," . "\t\t{$columnsvar}_advanced_options," . "\t\t{$pub_id}," . ' "' . esc_attr( $pub_responsive_modal_hyperlinks ) . '",' . ' [' . implode( ',', $this->hyperlink_positions ) . '],' . ' "' . esc_attr( $filter_field_name ) . '",' . ' "' . esc_attr( $filter_field_value ) . '",' . ' "' . esc_attr( $nl2br ) . '",' . "\t\t{$this->buttons}," . "\t\t\"{$read_more}\"," . ' "' . (( $calc_estimate ? 'true' : 'false' )) . '",' . ' "' . trim( preg_replace( '/\\s+/', ' ', $this->geo_search ) ) . '",' . "\t\t{$columnsvar}_geosearch_options," . ' "' . $wpnonce . '",' . ' "' . $this->pub_id_seq . '"' . ' );' . '});' . '</script>' . $this->geomap;
369 }
370
371 protected function set_style( $dashboard_styling, $publication ) {
372 $styling = 'default';
373 return $styling;
374 }
375
376 protected function extension_wizard( $pub_extentions ) {
377 }
378
379 protected function add_extra_header() {
380 $header2 = '';
381 return $header2;
382 }
383
384 protected function use_buttons_extension() {
385 $use_buttons_extension = false;
386 return $use_buttons_extension;
387 }
388
389 protected function get_geolocation_settings() {
390 return null;
391 }
392
393 protected function get_columns( $column_names ) {
394 if ( '*' === $column_names ) {
395 // Get all column names from table.
396 $columns = array();
397 foreach ( $this->wpda_list_columns->get_table_columns() as $column ) {
398 $columns[] = $column['column_name'];
399 }
400 return $columns;
401 } else {
402 $columns = explode( ',', (string) $column_names );
403 // Create column ARRAY
404 // Check if columns exist to prevent sql injection
405 $i = 0;
406 foreach ( $columns as $column ) {
407 if ( 'wpda_hyperlink_' !== substr( $column, 0, 15 ) ) {
408 if ( !$this->wpda_dictionary_checks->column_exists( $column ) ) {
409 // Column not found
410 return __( 'ERROR: Column', 'wp-data-access' ) . ' ' . esc_attr( $column ) . ' ' . __( 'not found', 'wp-data-access' );
411 }
412 } else {
413 $this->hyperlink_positions[] = $i;
414 }
415 $i++;
416 }
417 return $columns;
418 }
419 }
420
421 protected function get_labels( $pub_format ) {
422 try {
423 $pub_format_json = json_decode( (string) $pub_format, true );
424 if ( isset( $pub_format_json['pub_format']['column_labels'] ) && is_array( $pub_format_json['pub_format']['column_labels'] ) ) {
425 return array_merge( $this->wpda_list_columns->get_table_column_headers(), $pub_format_json['pub_format']['column_labels'] );
426 } else {
427 return $this->wpda_list_columns->get_table_column_headers();
428 }
429 } catch ( \Exception $e ) {
430 return $this->wpda_list_columns->get_table_column_headers();
431 }
432 }
433
434 protected function define_columns( $use_buttons_extension, $hyperlinks, $geolocation ) {
435 $wpda_database_columns = '';
436 for ($i = 0; $i < count( $this->columns ); $i++) {
437 if ( 'wpda_hyperlink_' !== substr( $this->columns[$i], 0, 15 ) ) {
438 $column_label = ( isset( $this->column_labels[$this->columns[$i]] ) ? $this->column_labels[$this->columns[$i]] : $this->columns[$i] );
439 } else {
440 $column_label = $hyperlinks[substr( $this->columns[$i], strrpos( $this->columns[$i], '_' ) + 1 )];
441 }
442 $data_type = WPDA::get_type( $this->wpda_list_columns->get_column_data_type( $this->columns[$i] ) );
443 $data_type_class = "wpda_format_{$data_type}";
444 $wpda_database_columns_obj = (object) null;
445 $wpda_database_columns_obj->className = "{$this->columns[$i]} {$data_type_class}";
446 $wpda_database_columns_obj->name = $this->columns[$i];
447 $wpda_database_columns_obj->targets = $i;
448 $wpda_database_columns_obj->label = $column_label;
449 $wpda_database_columns_obj->searchBuilderType = WPDA::get_sb_type( $this->wpda_list_columns->get_column_data_type( $this->columns[$i] ) );
450 $wpda_database_columns .= json_encode( $wpda_database_columns_obj );
451 if ( $i < count( $this->columns ) - 1 ) {
452 $wpda_database_columns .= ',';
453 }
454 }
455 return $wpda_database_columns;
456 }
457
458 protected function get_language() {
459 // Check data table specific language
460 if ( isset( $this->json->wpda_language, WPDA_Settings_Legacy_DataTables::FRONTEND_LANG[$this->json->wpda_language] ) ) {
461 return WPDA_Settings_Legacy_DataTables::FRONTEND_LANG[$this->json->wpda_language];
462 }
463 // Get data table global language
464 $language = WPDA::get_option( WPDA::OPTION_DP_LANGUAGE );
465 $language_code = ( isset( WPDA_Settings_Legacy_DataTables::FRONTEND_LANG[$language] ) ? WPDA_Settings_Legacy_DataTables::FRONTEND_LANG[$language] : 'en-GB' );
466 return $language_code;
467 }
468
469 protected function add_buttons( $use_buttons_extension, $pub_id, $table_name ) {
470 }
471
472 private function get_button_caption() {
473 return ( isset( $this->json->wpda_button_caption ) && null !== $this->json->wpda_button_caption ? $this->json->wpda_button_caption : 'label' );
474 }
475
476 protected function add_export_button( $button_type, $icon, $hint ) {
477 return null;
478 }
479
480 protected function add_geolocation(
481 $geolocation,
482 $pub_id,
483 $table_name,
484 $database
485 ) {
486 $this->geo_search_type = (object) null;
487 }
488
489 protected function add_read_more( $pub_id, $table_name, $pub_table_options_paging ) {
490 if ( 'false' === $pub_table_options_paging && isset( $this->json->serverSide ) && ('true' === $this->json->serverSide || true === $this->json->serverSide) ) {
491 $this->read_more_html = '<div id="' . esc_attr( $table_name ) . "{$pub_id}_more_container\" class='wpda_more_container' >" . '<button id="' . esc_attr( $table_name ) . "{$pub_id}_more_button\" type='button' class='wpda_more_button dt-button'>SHOW MORE</button>" . '</div>';
492 }
493 return ( '' === $this->read_more_html ? 'false' : 'true' );
494 }
495
496 protected function update_extra_header( $header2, $pub_table_options_searching ) {
497 return $header2;
498 }
499
500 protected function add_global_style( $styling, $pub_styles ) {
501 $dataTablesClass = str_replace( array(',', 'default'), array(' ', 'display'), $pub_styles );
502 return $dataTablesClass;
503 }
504
505 protected function add_styling_template(
506 $pub_id,
507 $table_name,
508 $dashboard_styling,
509 $publication
510 ) {
511 $styling_template = '';
512 // Needed for jdt
513 $this->json->wpda_styling = $styling_template;
514 return $styling_template;
515 }
516
517 protected function prepare_json( $responsive, $pub_flat_scrollx ) {
518 if ( !isset( $this->json->dom ) ) {
519 $this->json->dom = 'lfrtip';
520 }
521 if ( 'no' === strtolower( $responsive ) && 'yes' === strtolower( $pub_flat_scrollx ) && !isset( $this->json->scrollX ) ) {
522 $this->json->scrollX = true;
523 }
524 // Convert JSON to string
525 return json_encode( $this->json );
526 }
527
528 protected function generate_nonce( $table_name, $column_names_value, $is_embedded ) {
529 // Generate nonce
530 $nonce_seed = 'wpda-publication-' . $table_name . '-' . $column_names_value;
531 if ( !$is_embedded ) {
532 // Normal WordPress nonce
533 return wp_create_nonce( $nonce_seed );
534 } else {
535 // Plugin string based nonce to secure embedding
536 return WPDA::wpda_create_sonce( $nonce_seed );
537 }
538 }
539
540 /**
541 * Show table header (footer as well)
542 *
543 * @param string $responsive Yes = responsive mode, No = Flat mode.
544 * @param int $responsive_cols Number of columns to be displayed in responsive mode.
545 * @param array $hyperlinks Hyperlinks defined in column settings.
546 * @param string $header2 Adds an extra header row if TRUE.
547 * @param mixed $geolocation
548 *
549 * @return string output
550 */
551 protected function show_header(
552 $responsive,
553 $responsive_cols,
554 $hyperlinks,
555 $header2,
556 $geolocation
557 ) {
558 $count = 0;
559 $html_output = '';
560 $html_search = '';
561 foreach ( $this->columns as $column ) {
562 $class = '';
563 if ( 'yes' === $responsive ) {
564 if ( is_numeric( $responsive_cols ) ) {
565 if ( (int) $responsive_cols > 0 ) {
566 if ( $count >= 0 && $count < $responsive_cols ) {
567 $class = 'all';
568 } else {
569 $class = 'none';
570 }
571 }
572 }
573 }
574 if ( 'wpda_hyperlink_' !== substr( $column, 0, 15 ) ) {
575 $column_label = ( isset( $this->column_labels[$column] ) ? $this->column_labels[$column] : $column );
576 } else {
577 $column_label = $hyperlinks[substr( $column, strrpos( $column, '_' ) + 1 )];
578 }
579 if ( 'header' === $header2 || 'both' === $header2 ) {
580 $html_search .= "<td class=\"{$class}\" data-column_name_search=\"{$column}\" data-column_name_label=\"{$column_label}\"></td>";
581 $html_output .= "<th class=\"{$class}\" data-column_name=\"{$column}\">{$column_label}</th>";
582 } else {
583 $html_output .= "<th class=\"{$class}\" data-column_name_search=\"{$column}\">{$column_label}</th>";
584 }
585 $count++;
586 }
587 if ( '' !== $html_search ) {
588 $html_search = "<tr>{$html_search}</tr>";
589 }
590 return "{$html_search}<tr>{$html_output}</tr>";
591 }
592
593 private function url_params( $where ) {
594 return $where;
595 }
596
597 /**
598 * Performs jQuery DataTable query
599 *
600 * Once a jQuery DataTable is build using {@see WPDA_Data_Tables::show()}, the DataTable is filled according
601 * to the search criteria and pagination settings on the Datable. The query is performed through this function.
602 * The query result is returned (echo) in JSON format. Table and column names are checked for existence and
603 * access to prevent hacking the DataTable code and SQL injection.
604 *
605 * @since 1.0.0
606 *
607 * @see WPDA_Data_Tables::show()
608 */
609 public function get_data() {
610 $where = '';
611 $_filter = array();
612 $has_sp = false;
613 $sp_columns = array();
614 $pub_id = ( isset( $_REQUEST['pubid'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['pubid'] ) ) : '' );
615 // input var okay.
616 $database = ( isset( $_REQUEST['wpdasrc'] ) ? str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['wpdasrc'] ) ) ) : '' );
617 // input var okay.
618 $table_name = ( isset( $_REQUEST['wpdatabs'] ) ? str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['wpdatabs'] ) ) ) : '' );
619 // input var okay.
620 $columns = ( isset( $_REQUEST['wpdacols'] ) ? str_replace( '`', '', sanitize_text_field( wp_unslash( $_REQUEST['wpdacols'] ) ) ) : '*' );
621 // input var okay.
622 $wpnonce = ( isset( $_REQUEST['wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['wpnonce'] ) ) : '' );
623 // input var okay.
624 if ( '' === $pub_id && '' === $table_name ) {
625 // input var okay.
626 // Database and table name must be set!
627 $this->create_empty_response( 'Missing arguments' );
628 wp_die();
629 }
630 $this->serverSide = true;
631 // Set pagination values.
632 $offset = 0;
633 // phpcs:disable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
634 if ( isset( $_REQUEST['start'] ) && ctype_digit( $_REQUEST['start'] ) ) {
635 $offset = (int) $_REQUEST['start'];
636 // input var okay.
637 }
638 $limit = -1;
639 // jQuery DataTables default.
640 if ( isset( $_REQUEST['length'] ) && ctype_digit( $_REQUEST['length'] ) ) {
641 $limit = (int) $_REQUEST['length'];
642 // input var okay.
643 }
644 $publication_mode = 'normal';
645 if ( -1 == $limit && isset( $_REQUEST['more_start'] ) && ctype_digit( $_REQUEST['more_start'] ) && isset( $_REQUEST['more_limit'] ) && ctype_digit( $_REQUEST['more_limit'] ) ) {
646 $publication_mode = 'more';
647 $offset = (int) $_REQUEST['more_start'];
648 // input var okay.
649 $limit = (int) $_REQUEST['more_limit'];
650 // input var okay.
651 }
652 // phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
653 if ( '' !== $pub_id && '0' != $pub_id ) {
654 // Get data
655 $publication = WPDA_Publisher_Model::get_publication( $pub_id );
656 if ( false === $publication ) {
657 // Data table not found
658 $this->create_empty_response( 'Invalid arguments' );
659 wp_die();
660 }
661 $kill_token = false;
662 $pub_table_options_advanced = $publication[0]['pub_table_options_advanced'];
663 $pub_table_options_advanced = str_replace( array("\r", "\n", "\t"), '', (string) $pub_table_options_advanced );
664 try {
665 $json = json_decode( (string) $pub_table_options_advanced );
666 $kill_token = isset( $json->killToken ) && (true === $json->killToken || 'true' === $json->killToken);
667 } catch ( \Exception $e ) {
668 $json = null;
669 }
670 $database = $publication[0]['pub_schema_name'];
671 $table_name = $publication[0]['pub_table_name'];
672 $columns = $publication[0]['pub_column_names'];
673 if ( null === $columns || '' === trim( $columns ) ) {
674 $columns = '*';
675 }
676 // Check token
677 $table_name_verify = ( 'Query' === $publication[0]['pub_data_source'] || 'CPT' === $publication[0]['pub_data_source'] ? "custom{$pub_id}" : $table_name );
678 if ( !$kill_token && !wp_verify_nonce( $wpnonce, 'wpda-publication-' . $table_name_verify . '-' ) && !WPDA::wpda_verify_sonce( $wpnonce, 'wpda-publication-' . $table_name_verify . '-' ) ) {
679 $this->create_empty_response( 'Token expired, please refresh page' );
680 wp_die();
681 }
682 // Get default where
683 if ( isset( $publication[0]['pub_default_where'] ) ) {
684 if ( null !== $publication[0]['pub_default_where'] && '' !== trim( $publication[0]['pub_default_where'] ) ) {
685 $where = $publication[0]['pub_default_where'];
686 }
687 }
688 // Get server side options.
689 if ( isset( $json->serverSide ) ) {
690 $this->serverSide = true === $json->serverSide || 'true' === $json->serverSide;
691 } else {
692 if ( 'on' !== $publication[0]['pub_table_options_serverside'] || null === $publication[0]['pub_table_options_serverside'] ) {
693 $this->serverSide = false;
694 }
695 }
696 } else {
697 // Check token = old shortcode usage
698 if ( !wp_verify_nonce( $wpnonce, 'wpda-publication-' . $table_name . '-' . $columns ) && !WPDA::wpda_verify_sonce( $wpnonce, 'wpda-publication-' . $table_name . '-' . $columns ) ) {
699 $this->create_empty_response( 'Token expired, please refresh page' );
700 wp_die();
701 }
702 // Do not allow to access other schemas
703 if ( strpos( $table_name, '.' ) ) {
704 $this->create_empty_response( 'Wrong argument' );
705 wp_die();
706 }
707 // Check access
708 $wpda_dictionary_checks = new WPDA_Dictionary_Exist($database, $table_name);
709 if ( !$wpda_dictionary_checks->table_exists( true, false ) ) {
710 $this->create_empty_response( 'Not authorized' );
711 wp_die();
712 }
713 // Init var to prevent undefined var messages.
714 $json = null;
715 }
716 if ( '' !== $where && 'where' !== strtolower( substr( trim( $where ), 0, 5 ) ) ) {
717 $where = "where {$where}";
718 }
719 if ( '' !== $where ) {
720 $_filter = array(
721 'filter_default' => $where,
722 );
723 }
724 $wpdadb = WPDADB::get_db_connection( $database );
725 if ( null === $wpdadb ) {
726 $this->create_empty_response( 'Invalid connection' );
727 wp_die();
728 // Remote database not available
729 }
730 // Add field filters from shortcode
731 $filter_field_name = '';
732 $filter_field_value = '';
733 if ( isset( $_REQUEST['filter_field_name'], $_REQUEST['filter_field_value'] ) ) {
734 // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
735 $filter_field_name_raw = wp_unslash( $_REQUEST['filter_field_name'] );
736 $filter_field_value_raw = wp_unslash( $_REQUEST['filter_field_value'] );
737 // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
738 if ( is_string( $filter_field_name_raw ) && is_string( $filter_field_value_raw ) ) {
739 $filter_field_name = sanitize_text_field( $filter_field_name_raw );
740 $filter_field_value = sanitize_text_field( $filter_field_value_raw );
741 }
742 }
743 if ( '' !== $filter_field_name && '' !== $filter_field_value ) {
744 if ( '*' === $columns ) {
745 $allowed_columns = array();
746 $tbl = WPDA_List_Columns_Cache::get_list_columns( $database, $table_name );
747 $cols = $tbl->get_table_columns();
748 foreach ( $cols as $col ) {
749 if ( isset( $col['column_name'] ) ) {
750 $allowed_columns[] = $col['column_name'];
751 }
752 }
753 } else {
754 $allowed_columns = explode( ',', $columns );
755 }
756 $filter_field_name_array = array_map( 'trim', explode( ',', $filter_field_name ) );
757 $filter_field_value_array = array_map( 'trim', explode( ',', $filter_field_value ) );
758 if ( count( $filter_field_name_array ) === count( $filter_field_value_array ) ) {
759 $prepare_fields = array();
760 $prepare_values = array();
761 for ($i = 0; $i < count( $filter_field_name_array ); $i++) {
762 $field_name = $filter_field_name_array[$i];
763 $field_value = $filter_field_value_array[$i];
764 if ( !in_array( $field_name, $allowed_columns, true ) ) {
765 continue;
766 }
767 $prepare_fields[] = $field_name;
768 $prepare_values[] = $field_value;
769 }
770 for ($i = 0; $i < count( $prepare_fields ); $i++) {
771 if ( '' === $where ) {
772 $where = $wpdadb->prepare( ' WHERE %i LIKE %s ', array($prepare_fields[$i], $prepare_values[$i]) );
773 } else {
774 $where .= $wpdadb->prepare( ' AND %i LIKE %s ', array($prepare_fields[$i], $prepare_values[$i]) );
775 }
776 }
777 $_filter['filter_field_name'] = $filter_field_name;
778 $_filter['filter_field_value'] = $filter_field_value;
779 }
780 }
781 // Get all column names from table (must be comma separated string)
782 $this->wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $database, $table_name );
783 $table_columns = $this->wpda_list_columns->get_table_columns();
784 // Save column:data_type pairs for fast access
785 $column_array_ordered = array();
786 foreach ( $table_columns as $column ) {
787 $column_array_ordered[$column['column_name']] = $column['data_type'];
788 }
789 // Load table settings
790 $table_settings_db = WPDA_Table_Settings_Model::query( $table_name, $database );
791 if ( isset( $table_settings_db[0]['wpda_table_settings'] ) ) {
792 $table_settings = json_decode( (string) $table_settings_db[0]['wpda_table_settings'] );
793 } else {
794 $table_settings = array();
795 }
796 if ( '*' === $columns ) {
797 // Get all column names from table (must be comma separated string).
798 $column_array = array();
799 foreach ( $table_columns as $column ) {
800 $column_array[] = $column['column_name'];
801 }
802 $columns = implode( ',', $column_array );
803 } else {
804 // Check if columns exist (prevent sql injection).
805 $wpda_dictionary_checks = new WPDA_Dictionary_Exist($database, $table_name);
806 $column_array = explode( ',', (string) $columns );
807 $has_dynamic_hyperlinks = false;
808 foreach ( $column_array as $column ) {
809 if ( 'wpda_hyperlink_' !== substr( $column, 0, 15 ) ) {
810 if ( !$wpda_dictionary_checks->column_exists( $column ) ) {
811 // Column not found.
812 $this->create_empty_response( 'Invalid column name' );
813 wp_die();
814 }
815 } else {
816 $has_dynamic_hyperlinks = true;
817 }
818 }
819 if ( $has_dynamic_hyperlinks ) {
820 // Check for columns needed for substitution and missing in the query
821 $hyperlink_substitution_columns = array();
822 if ( isset( $table_settings->hyperlinks ) ) {
823 foreach ( $table_settings->hyperlinks as $hyperlink ) {
824 if ( isset( $hyperlink->hyperlink_html ) ) {
825 foreach ( $table_columns as $column ) {
826 if ( stripos( $hyperlink->hyperlink_html, "\$\${$column['column_name']}\$\$" ) !== false ) {
827 $hyperlink_substitution_columns[$column['column_name']] = true;
828 }
829 }
830 }
831 }
832 }
833 foreach ( $hyperlink_substitution_columns as $hyperlink_substitution_column => $val ) {
834 if ( !in_array( $hyperlink_substitution_column, $column_array ) ) {
835 $columns .= ",{$hyperlink_substitution_column}";
836 }
837 }
838 }
839 }
840 // Save column name without backticks for later use
841 $column_array_clean = $column_array;
842 // Set order by.
843 $orderby = '';
844 if ( isset( $_REQUEST['order'] ) && is_array( $_REQUEST['order'] ) ) {
845 // input var okay.
846 $orderby_columns = array();
847 $orderby_args = array();
848 // Sanitize argument array and write result to temporary sanitizes array for processing:
849 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
850 foreach ( $_REQUEST['order'] as $order_column ) {
851 if ( isset( $order_column['column'] ) ) {
852 $orderby_args[] = array(
853 'column' => sanitize_sql_orderby( wp_unslash( $order_column['column'] ) ),
854 'dir' => ( isset( $order_column['dir'] ) && 'desc' === $order_column['dir'] ? 'desc' : 'asc' ),
855 );
856 }
857 }
858 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
859 foreach ( $orderby_args as $order_column ) {
860 // input var okay.
861 $column_index = $order_column['column'];
862 $column_name = str_replace( '`', '', $column_array[$column_index] );
863 $column_dir = $order_column['dir'];
864 $orderby_columns[] = "`{$column_name}` {$column_dir}";
865 }
866 $orderby = implode( ',', $orderby_columns );
867 }
868 // Add search criteria.
869 if ( isset( $_REQUEST['search']['value'] ) ) {
870 $search_value = sanitize_text_field( wp_unslash( $_REQUEST['search']['value'] ) );
871 // input var okay.
872 } else {
873 $search_value = '';
874 }
875 $where_columns = WPDA::construct_where_clause(
876 $database,
877 $table_name,
878 $this->wpda_list_columns->get_table_columns(),
879 $search_value
880 );
881 if ( '' !== $where_columns ) {
882 if ( '' === $where ) {
883 $where = " where {$where_columns} ";
884 } else {
885 $where .= " and {$where_columns} ";
886 }
887 }
888 if ( '' !== $where ) {
889 $where = WPDA::substitute_environment_vars( $where );
890 }
891 if ( '' !== $search_value ) {
892 $_filter['filter_dyn'] = $search_value;
893 }
894 foreach ( $_REQUEST as $key => $value ) {
895 if ( 'wpda_search_' === substr( $key, 0, 12 ) ) {
896 $_filter['filter_args'][$key] = $value;
897 }
898 }
899 $geo_radius_col = '';
900 // Execute query.
901 $column_array = explode( ',', (string) $columns );
902 $column_array_orig = $column_array;
903 $images_array = array();
904 $imagesurl_array = array();
905 $attachments_array = array();
906 $hyperlinks_array = array();
907 $hyperlinks_array_col = array();
908 $audio_array = array();
909 $video_array = array();
910 if ( isset( $publication[0]['pub_format'] ) && '' !== $publication[0]['pub_format'] && null !== $publication[0]['pub_format'] ) {
911 try {
912 $pub_format = json_decode( (string) $publication[0]['pub_format'], true );
913 } catch ( \Exception $e ) {
914 $pub_format = null;
915 }
916 $column_images = array();
917 $column_attachments = array();
918 if ( isset( $pub_format['pub_format']['column_images'] ) ) {
919 $column_images = $pub_format['pub_format']['column_images'];
920 }
921 if ( isset( $pub_format['pub_format']['column_attachments'] ) ) {
922 $column_attachments = $pub_format['pub_format']['column_attachments'];
923 }
924 $i = 0;
925 foreach ( $column_array as $col ) {
926 if ( isset( $column_images[$col] ) ) {
927 array_push( $images_array, $i );
928 }
929 $i++;
930 }
931 $i = 0;
932 foreach ( $column_array as $col ) {
933 if ( isset( $column_attachments[$col] ) ) {
934 array_push( $attachments_array, $i );
935 }
936 $i++;
937 }
938 } else {
939 $pub_format = null;
940 }
941 // Check media columns defined on plugin level and add to arrays
942 $i = 0;
943 foreach ( $column_array as $col ) {
944 if ( 'Image' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
945 if ( !isset( $images_array[$i] ) ) {
946 array_push( $images_array, $i );
947 }
948 } elseif ( 'ImageURL' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
949 array_push( $imagesurl_array, $i );
950 } elseif ( 'Attachment' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
951 if ( !isset( $attachments_array[$i] ) ) {
952 array_push( $attachments_array, $i );
953 }
954 } elseif ( 'Hyperlink' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
955 if ( !isset( $hyperlinks_array[$i] ) ) {
956 array_push( $hyperlinks_array, $i );
957 array_push( $hyperlinks_array_col, $col );
958 }
959 } elseif ( 'Audio' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
960 array_push( $audio_array, $i );
961 } elseif ( 'Video' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
962 array_push( $video_array, $i );
963 }
964 $i++;
965 }
966 // Change dynamic hyperlinks
967 $update = array();
968 $i = 0;
969 $hyperlinks_column_index = array();
970 foreach ( $column_array as $col ) {
971 if ( 'wpda_hyperlink_' === substr( $col, 0, 15 ) ) {
972 $update[$col] = "'x' as {$col}";
973 $hyperlinks_column_index[$i] = substr( $col, 15 );
974 } else {
975 $update[$col] = '`' . str_replace( '`', '', $col ) . '`';
976 }
977 $i++;
978 }
979 $column_array = $update;
980 $columns_backticks = implode( ',', $column_array ) . $geo_radius_col;
981 $query = "select {$columns_backticks} from `{$wpdadb->dbname}`.`{$table_name}` {$where}";
982 if ( '' !== $orderby ) {
983 $query .= " order by {$orderby} ";
984 }
985 if ( -1 != $limit ) {
986 $query .= $wpdadb->prepare( " limit %d offset %d", [$limit, $offset] );
987 }
988 $hyperlinks = array();
989 if ( count( $hyperlinks_column_index ) ) {
990 if ( isset( $table_settings->hyperlinks ) ) {
991 foreach ( $table_settings->hyperlinks as $hyperlink ) {
992 $hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' );
993 $hyperlink_target = ( isset( $hyperlink->hyperlink_target ) ? $hyperlink->hyperlink_target : false );
994 $hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' );
995 if ( $hyperlink_label !== '' && $hyperlink_html !== '' ) {
996 array_push( $hyperlinks, array(
997 'hyperlink_label' => $hyperlink_label,
998 'hyperlink_target' => $hyperlink_target,
999 'hyperlink_html' => $hyperlink_html,
1000 ) );
1001 }
1002 }
1003 }
1004 }
1005 $nl2br = ( isset( $_REQUEST['nl2br'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nl2br'] ) ) : '' );
1006 // input var okay.
1007 if ( 'on' === $nl2br || 'yes' === $nl2br || 'true' === $nl2br ) {
1008 $nl2br = 'on';
1009 } else {
1010 if ( '' !== $pub_id ) {
1011 if ( isset( $publication[0]['pub_table_options_nl2br'] ) ) {
1012 $nl2br = $publication[0]['pub_table_options_nl2br'];
1013 }
1014 }
1015 }
1016 $wpdadb->suppress_errors( true );
1017 $rows = $wpdadb->get_results( $query, 'ARRAY_N' );
1018 if ( '' !== $wpdadb->last_error ) {
1019 $this->create_empty_response( __( 'ERROR: Invalid query', 'wp-data-access' ) );
1020 WPDA::wpda_log_wp_error( $wpdadb->last_error );
1021 wp_die();
1022 }
1023 $rows_final = array();
1024 foreach ( $rows as $row ) {
1025 $row_orig = $row;
1026 if ( 'on' === $nl2br && null !== $nl2br ) {
1027 // Replace NL with BR tags
1028 for ($nl = 0; $nl < count( $row ); $nl++) {
1029 $row[$nl] = nl2br( (string) $row[$nl] );
1030 }
1031 }
1032 foreach ( $hyperlinks_column_index as $key => $value ) {
1033 if ( isset( $hyperlinks[$value] ) ) {
1034 $hyperlink_html = ( isset( $hyperlinks[$value]['hyperlink_html'] ) ? $hyperlinks[$value]['hyperlink_html'] : '' );
1035 if ( '' !== $hyperlink_html ) {
1036 $i = 0;
1037 foreach ( $column_array as $column ) {
1038 $column_name = str_replace( '`', '', $column );
1039 $hyperlink_html = str_replace( "\$\${$column_name}\$\$", $row[$i], $hyperlink_html );
1040 $i++;
1041 }
1042 }
1043 $macro = new WPDA_Macro($hyperlink_html);
1044 $hyperlink_html = $macro->exe_macro();
1045 if ( '' !== $hyperlink_html ) {
1046 if ( false !== strpos( ltrim( $hyperlink_html ), '&lt;' ) ) {
1047 $row[$key] = html_entity_decode( $hyperlink_html );
1048 } else {
1049 $hyperlink_label = ( isset( $hyperlinks[$value]['hyperlink_label'] ) ? $hyperlinks[$value]['hyperlink_label'] : '' );
1050 $hyperlink_target = ( isset( $hyperlinks[$value]['hyperlink_target'] ) ? $hyperlinks[$value]['hyperlink_target'] : false );
1051 $target = ( true === $hyperlink_target ? "target='_blank'" : '' );
1052 $row[$key] = "<a href='" . str_replace( ' ', '+', $hyperlink_html ) . "' {$target}>{$hyperlink_label}</a>";
1053 }
1054 } else {
1055 $row[$key] = '';
1056 }
1057 } else {
1058 $row[$key] = 'ERROR';
1059 }
1060 }
1061 for ($i = 0; $i < count( $imagesurl_array ); $i++) {
1062 $row[$imagesurl_array[$i]] = '<img src="' . $row[$imagesurl_array[$i]] . '" width="100%">';
1063 }
1064 for ($i = 0; $i < count( $images_array ); $i++) {
1065 $image_ids = explode( ',', (string) $row[$images_array[$i]] );
1066 $image_src = '';
1067 foreach ( $image_ids as $image_id ) {
1068 $url = wp_get_attachment_url( esc_attr( $image_id ) );
1069 if ( false !== $url ) {
1070 $image_src .= ( '' !== $image_src ? '<br/>' : '' );
1071 $image_src .= '<img src="' . $url . '" width="100%">';
1072 }
1073 }
1074 $row[$images_array[$i]] = $image_src;
1075 }
1076 for ($i = 0; $i < count( $attachments_array ); $i++) {
1077 $media_ids = explode( ',', (string) $row[$attachments_array[$i]] );
1078 $media_links = '';
1079 foreach ( $media_ids as $media_id ) {
1080 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1081 if ( false !== $url ) {
1082 $mime_type = get_post_mime_type( $media_id );
1083 if ( false !== $mime_type ) {
1084 $title = get_the_title( esc_attr( $media_id ) );
1085 $media_links .= WPDA_List_Table::column_media_attachment( $url, $title, $mime_type );
1086 }
1087 }
1088 }
1089 $row[$attachments_array[$i]] = $media_links;
1090 }
1091 if ( isset( $hyperlinks_array ) ) {
1092 $hyperlink_definition = ( isset( $table_settings->table_settings->hyperlink_definition ) && 'text' === $table_settings->table_settings->hyperlink_definition ? 'text' : 'json' );
1093 for ($i = 0; $i < count( $hyperlinks_array ); $i++) {
1094 if ( 'json' === $hyperlink_definition ) {
1095 $hyperlink = json_decode( (string) $row[$hyperlinks_array[$i]], true );
1096 if ( is_array( $hyperlink ) && isset( $hyperlink['label'] ) && isset( $hyperlink['url'] ) && isset( $hyperlink['target'] ) ) {
1097 if ( '' === $hyperlink['url'] ) {
1098 $row[$hyperlinks_array[$i]] = esc_attr( $hyperlink['label'] );
1099 } else {
1100 $row[$hyperlinks_array[$i]] = "<a href='" . esc_url_raw( $hyperlink['url'] ) . "' target='" . esc_attr( $hyperlink['target'] ) . "'>" . esc_attr( $hyperlink['label'] ) . "</a>";
1101 }
1102 } else {
1103 $row[$hyperlinks_array[$i]] = '';
1104 }
1105 } else {
1106 if ( null !== $row[$hyperlinks_array[$i]] && '' !== $row[$hyperlinks_array[$i]] ) {
1107 $hyperlink_label = esc_attr( $this->wpda_list_columns->get_column_label( $hyperlinks_array_col[$i] ) );
1108 $row[$hyperlinks_array[$i]] = "<a href='" . esc_url_raw( $row[$hyperlinks_array[$i]] ) . "' target='_blank'>" . esc_attr( $hyperlink_label ) . "</a>";
1109 } else {
1110 $row[$hyperlinks_array[$i]] = '';
1111 }
1112 }
1113 }
1114 }
1115 for ($i = 0; $i < count( $audio_array ); $i++) {
1116 $media_ids = explode( ',', (string) $row[$audio_array[$i]] );
1117 $media_links = '';
1118 foreach ( $media_ids as $media_id ) {
1119 if ( 'audio' === substr( get_post_mime_type( $media_id ), 0, 5 ) ) {
1120 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1121 if ( false !== $url ) {
1122 $title = get_the_title( esc_attr( $media_id ) );
1123 if ( false !== $url ) {
1124 $media_links .= '<div class="wpda_tooltip" title="' . esc_attr( $title ) . '">' . do_shortcode( '[audio src="' . esc_url_raw( $url ) . '"]' ) . '</div>';
1125 }
1126 }
1127 }
1128 }
1129 $row[$audio_array[$i]] = $media_links;
1130 }
1131 for ($i = 0; $i < count( $video_array ); $i++) {
1132 $media_ids = explode( ',', (string) $row[$video_array[$i]] );
1133 $media_links = '';
1134 foreach ( $media_ids as $media_id ) {
1135 if ( 'video' === substr( get_post_mime_type( $media_id ), 0, 5 ) ) {
1136 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1137 if ( false !== $url ) {
1138 if ( false !== $url ) {
1139 $media_links .= do_shortcode( '[video src="' . esc_url_raw( $url ) . '"]' );
1140 }
1141 }
1142 }
1143 }
1144 $row[$video_array[$i]] = $media_links;
1145 }
1146 // Format date and time columns
1147 for ($i = 0; $i < count( $row ); $i++) {
1148 if ( '' !== $row[$i] && null !== $row[$i] ) {
1149 if ( isset( $column_array_clean[$i] ) ) {
1150 if ( isset( $column_array_ordered[$column_array_clean[$i]] ) ) {
1151 switch ( $column_array_ordered[$column_array_clean[$i]] ) {
1152 case 'date':
1153 $row[$i] = date_i18n( get_option( 'date_format' ), strtotime( $row[$i] ) );
1154 break;
1155 case 'time':
1156 $row[$i] = date_i18n( get_option( 'time_format' ), strtotime( $row[$i] ) );
1157 break;
1158 case 'datetime':
1159 case 'timestamp':
1160 $row[$i] = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $row[$i] ) );
1161 }
1162 }
1163 }
1164 }
1165 }
1166 // Remove script tags if available
1167 for ($i = 0; $i < count( $row ); $i++) {
1168 $row[$i] = str_replace( array('<script>', '</script>'), array('&lt;script&gt;', '&lt;/script&gt;'), (string) $row[$i] );
1169 }
1170 array_push( $rows_final, $row );
1171 }
1172 if ( $this->serverSide ) {
1173 if ( isset( $_REQUEST['records_total'] ) && is_numeric( $_REQUEST['records_total'] ) && (!isset( $json->wpda_count_on_each_request ) || false === $json->wpda_count_on_each_request) ) {
1174 // Prevent row count on each request
1175 $rows_estimate = sanitize_text_field( wp_unslash( $_REQUEST['records_total'] ) );
1176 // input var okay.
1177 $do_real_count = false;
1178 } else {
1179 $row_count_estimate = WPDA::get_row_count_estimate( $database, $table_name, $table_settings );
1180 $rows_estimate = $row_count_estimate['row_count'];
1181 $do_real_count = $row_count_estimate['do_real_count'];
1182 }
1183 } else {
1184 $rows_estimate = count( $rows_final );
1185 $do_real_count = false;
1186 }
1187 if ( 'more' === $publication_mode ) {
1188 // Use estimate row count
1189 $count_table = $rows_estimate;
1190 $count_table_filtered = $rows_estimate;
1191 } else {
1192 if ( !$do_real_count ) {
1193 // Use estimate row count
1194 $count_table = $rows_estimate;
1195 } else {
1196 // Count rows in table = real row count
1197 $query2 = "select count(*) from `{$wpdadb->dbname}`.`{$table_name}`";
1198 $count_rows = $wpdadb->get_results( $query2, 'ARRAY_N' );
1199 $count_table = $count_rows[0][0];
1200 // Number of rows in table.
1201 }
1202 if ( isset( $_REQUEST['wpda_use_estimates_only'] ) && 'true' === $_REQUEST['wpda_use_estimates_only'] ) {
1203 // Prevent row count, only estimates required
1204 $count_table_filtered = $count_table;
1205 } else {
1206 if ( '' !== $where ) {
1207 if ( isset( $_REQUEST['records_filtered'] ) && is_numeric( $_REQUEST['records_filtered'] ) && (!isset( $json->wpda_count_on_each_request ) || false === $json->wpda_count_on_each_request) ) {
1208 $count_table_filtered = sanitize_text_field( wp_unslash( $_REQUEST['records_filtered'] ) );
1209 // input var okay.
1210 } else {
1211 // Count rows in selection (only necessary if a search criteria was entered).
1212 $query3 = "select count(*) from `{$wpdadb->dbname}`.`{$table_name}` {$where}";
1213 $count_rows_filtered = $wpdadb->get_results( $query3, 'ARRAY_N' );
1214 $count_table_filtered = $count_rows_filtered[0][0];
1215 // Number of rows in table.
1216 }
1217 } else {
1218 // No search criteria entered: # filtered rows = # table rows.
1219 $count_table_filtered = $count_table;
1220 }
1221 }
1222 }
1223 // Convert query result to jQuery DataTables object.
1224 $obj = (object) null;
1225 $obj->draw = ( isset( $_REQUEST['draw'] ) ? intval( $_REQUEST['draw'] ) : 0 );
1226 $obj->recordsTotal = intval( $count_table );
1227 $obj->recordsFiltered = intval( $count_table_filtered );
1228 $obj->data = $rows_final;
1229 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1230 $obj->error = $wpdadb->last_error;
1231 }
1232 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1233 $obj->debug = array(
1234 'columns' => $columns,
1235 'columns_backticks' => $columns_backticks,
1236 'query' => $query,
1237 'where' => $where,
1238 'orderby' => $orderby,
1239 'filter' => $_filter,
1240 'advanced_settings' => $json,
1241 'column_labels' => $this->wpda_list_columns->get_table_column_headers(),
1242 'labels' => array_flip( $this->get_labels( json_encode( $pub_format ) ) ),
1243 'serverSide' => $this->serverSide,
1244 );
1245 }
1246 // Send header
1247 if ( !WPDA::wpda_verify_sonce( $wpnonce, 'wpda-publication-' . $table_name . '-' ) ) {
1248 WPDA::sent_header( 'application/json' );
1249 } else {
1250 // Enable CORS for embedded publications
1251 WPDA::sent_header( 'application/json', '*' );
1252 }
1253 // Convert object to json. jQuery DataTables needs json format.
1254 echo json_encode( $obj );
1255 wp_die();
1256 }
1257
1258 private function get_data_custom_query(
1259 $publication,
1260 $json,
1261 $has_sp,
1262 $sp_columns,
1263 $sql_query,
1264 $is_cpt,
1265 $offset,
1266 $limit
1267 ) {
1268 return null;
1269 }
1270
1271 private function get_orderby_from_request() {
1272 $orderby = '';
1273 // Init order by.
1274 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
1275 if ( isset( $_REQUEST['order'] ) && is_array( $_REQUEST['order'] ) ) {
1276 foreach ( $_REQUEST['order'] as $order_column ) {
1277 if ( isset( $order_column['column'], $order_column['dir'] ) && is_numeric( $order_column['column'] ) && ('asc' === $order_column['dir'] || 'desc' === $order_column['dir']) ) {
1278 $preprend = ( '' === $orderby ? ' order by ' : ',' );
1279 $orderby .= $preprend . (intval( $order_column['column'] ) + 1) . ' ' . $order_column['dir'];
1280 }
1281 }
1282 }
1283 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
1284 return $orderby;
1285 }
1286
1287 private function sp(
1288 $wpdadb,
1289 $table_name,
1290 $columns,
1291 $panes,
1292 $where,
1293 $bt = '`'
1294 ) {
1295 $sp = array();
1296 return $sp;
1297 }
1298
1299 public function qb_group( $data ) {
1300 return null;
1301 }
1302
1303 public function qb_criteria( $crit ) {
1304 return null;
1305 }
1306
1307 private function qb( $labels ) {
1308 return null;
1309 }
1310
1311 private function create_empty_response( $error = '', $debug = '' ) {
1312 $obj = (object) null;
1313 $obj->draw = 0;
1314 $obj->recordsTotal = 0;
1315 $obj->recordsFiltered = 0;
1316 $obj->data = array();
1317 $obj->error = $error;
1318 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1319 $obj->debug = $debug;
1320 }
1321 echo json_encode( $obj );
1322 }
1323
1324 }
1325
1326 // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing