PluginProbe
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards / 5.5.83
WP Data Access – App Builder for Tables, Forms, Charts, Maps & Dashboards v5.5.83
5.5.85 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 All 161 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.83, at WPDataAccess/Data_Tables/WPDA_Data_Tables.php

1,324 lines 63.1 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 $filter_field_name_raw = wp_unslash( $_REQUEST['filter_field_name'] );
735 $filter_field_value_raw = wp_unslash( $_REQUEST['filter_field_value'] );
736 if ( is_string( $filter_field_name_raw ) && is_string( $filter_field_value_raw ) ) {
737 $filter_field_name = sanitize_text_field( $filter_field_name_raw );
738 $filter_field_value = sanitize_text_field( $filter_field_value_raw );
739 }
740 }
741 if ( '' !== $filter_field_name && '' !== $filter_field_value ) {
742 if ( '*' === $columns ) {
743 $allowed_columns = array();
744 $tbl = WPDA_List_Columns_Cache::get_list_columns( $database, $table_name );
745 $cols = $tbl->get_table_columns();
746 foreach ( $cols as $col ) {
747 if ( isset( $col['column_name'] ) ) {
748 $allowed_columns[] = $col['column_name'];
749 }
750 }
751 } else {
752 $allowed_columns = explode( ',', $columns );
753 }
754 $filter_field_name_array = array_map( 'trim', explode( ',', $filter_field_name ) );
755 $filter_field_value_array = array_map( 'trim', explode( ',', $filter_field_value ) );
756 if ( count( $filter_field_name_array ) === count( $filter_field_value_array ) ) {
757 $prepare_fields = array();
758 $prepare_values = array();
759 for ($i = 0; $i < count( $filter_field_name_array ); $i++) {
760 $field_name = $filter_field_name_array[$i];
761 $field_value = $filter_field_value_array[$i];
762 if ( !in_array( $field_name, $allowed_columns, true ) ) {
763 continue;
764 }
765 $prepare_fields[] = $field_name;
766 $prepare_values[] = $field_value;
767 }
768 for ($i = 0; $i < count( $prepare_fields ); $i++) {
769 if ( '' === $where ) {
770 $where = $wpdadb->prepare( ' WHERE %i LIKE %s ', array($prepare_fields[$i], $prepare_values[$i]) );
771 } else {
772 $where .= $wpdadb->prepare( ' AND %i LIKE %s ', array($prepare_fields[$i], $prepare_values[$i]) );
773 }
774 }
775 $_filter['filter_field_name'] = $filter_field_name;
776 $_filter['filter_field_value'] = $filter_field_value;
777 }
778 }
779 // Get all column names from table (must be comma separated string)
780 $this->wpda_list_columns = WPDA_List_Columns_Cache::get_list_columns( $database, $table_name );
781 $table_columns = $this->wpda_list_columns->get_table_columns();
782 // Save column:data_type pairs for fast access
783 $column_array_ordered = array();
784 foreach ( $table_columns as $column ) {
785 $column_array_ordered[$column['column_name']] = $column['data_type'];
786 }
787 // Load table settings
788 $table_settings_db = WPDA_Table_Settings_Model::query( $table_name, $database );
789 if ( isset( $table_settings_db[0]['wpda_table_settings'] ) ) {
790 $table_settings = json_decode( (string) $table_settings_db[0]['wpda_table_settings'] );
791 } else {
792 $table_settings = array();
793 }
794 if ( '*' === $columns ) {
795 // Get all column names from table (must be comma separated string).
796 $column_array = array();
797 foreach ( $table_columns as $column ) {
798 $column_array[] = $column['column_name'];
799 }
800 $columns = implode( ',', $column_array );
801 } else {
802 // Check if columns exist (prevent sql injection).
803 $wpda_dictionary_checks = new WPDA_Dictionary_Exist($database, $table_name);
804 $column_array = explode( ',', (string) $columns );
805 $has_dynamic_hyperlinks = false;
806 foreach ( $column_array as $column ) {
807 if ( 'wpda_hyperlink_' !== substr( $column, 0, 15 ) ) {
808 if ( !$wpda_dictionary_checks->column_exists( $column ) ) {
809 // Column not found.
810 $this->create_empty_response( 'Invalid column name' );
811 wp_die();
812 }
813 } else {
814 $has_dynamic_hyperlinks = true;
815 }
816 }
817 if ( $has_dynamic_hyperlinks ) {
818 // Check for columns needed for substitution and missing in the query
819 $hyperlink_substitution_columns = array();
820 if ( isset( $table_settings->hyperlinks ) ) {
821 foreach ( $table_settings->hyperlinks as $hyperlink ) {
822 if ( isset( $hyperlink->hyperlink_html ) ) {
823 foreach ( $table_columns as $column ) {
824 if ( stripos( $hyperlink->hyperlink_html, "\$\${$column['column_name']}\$\$" ) !== false ) {
825 $hyperlink_substitution_columns[$column['column_name']] = true;
826 }
827 }
828 }
829 }
830 }
831 foreach ( $hyperlink_substitution_columns as $hyperlink_substitution_column => $val ) {
832 if ( !in_array( $hyperlink_substitution_column, $column_array ) ) {
833 $columns .= ",{$hyperlink_substitution_column}";
834 }
835 }
836 }
837 }
838 // Save column name without backticks for later use
839 $column_array_clean = $column_array;
840 // Set order by.
841 $orderby = '';
842 if ( isset( $_REQUEST['order'] ) && is_array( $_REQUEST['order'] ) ) {
843 // input var okay.
844 $orderby_columns = array();
845 $orderby_args = array();
846 // Sanitize argument array and write result to temporary sanitizes array for processing:
847 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
848 foreach ( $_REQUEST['order'] as $order_column ) {
849 if ( isset( $order_column['column'] ) ) {
850 $orderby_args[] = array(
851 'column' => sanitize_sql_orderby( wp_unslash( $order_column['column'] ) ),
852 'dir' => ( isset( $order_column['dir'] ) && 'desc' === $order_column['dir'] ? 'desc' : 'asc' ),
853 );
854 }
855 }
856 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
857 foreach ( $orderby_args as $order_column ) {
858 // input var okay.
859 $column_index = $order_column['column'];
860 $column_name = str_replace( '`', '', $column_array[$column_index] );
861 $column_dir = $order_column['dir'];
862 $orderby_columns[] = "`{$column_name}` {$column_dir}";
863 }
864 $orderby = implode( ',', $orderby_columns );
865 }
866 // Add search criteria.
867 if ( isset( $_REQUEST['search']['value'] ) ) {
868 $search_value = sanitize_text_field( wp_unslash( $_REQUEST['search']['value'] ) );
869 // input var okay.
870 } else {
871 $search_value = '';
872 }
873 $where_columns = WPDA::construct_where_clause(
874 $database,
875 $table_name,
876 $this->wpda_list_columns->get_table_columns(),
877 $search_value
878 );
879 if ( '' !== $where_columns ) {
880 if ( '' === $where ) {
881 $where = " where {$where_columns} ";
882 } else {
883 $where .= " and {$where_columns} ";
884 }
885 }
886 if ( '' !== $where ) {
887 $where = WPDA::substitute_environment_vars( $where );
888 }
889 if ( '' !== $search_value ) {
890 $_filter['filter_dyn'] = $search_value;
891 }
892 foreach ( $_REQUEST as $key => $value ) {
893 if ( 'wpda_search_' === substr( $key, 0, 12 ) ) {
894 $_filter['filter_args'][$key] = $value;
895 }
896 }
897 $geo_radius_col = '';
898 // Execute query.
899 $column_array = explode( ',', (string) $columns );
900 $column_array_orig = $column_array;
901 $images_array = array();
902 $imagesurl_array = array();
903 $attachments_array = array();
904 $hyperlinks_array = array();
905 $hyperlinks_array_col = array();
906 $audio_array = array();
907 $video_array = array();
908 if ( isset( $publication[0]['pub_format'] ) && '' !== $publication[0]['pub_format'] && null !== $publication[0]['pub_format'] ) {
909 try {
910 $pub_format = json_decode( (string) $publication[0]['pub_format'], true );
911 } catch ( \Exception $e ) {
912 $pub_format = null;
913 }
914 $column_images = array();
915 $column_attachments = array();
916 if ( isset( $pub_format['pub_format']['column_images'] ) ) {
917 $column_images = $pub_format['pub_format']['column_images'];
918 }
919 if ( isset( $pub_format['pub_format']['column_attachments'] ) ) {
920 $column_attachments = $pub_format['pub_format']['column_attachments'];
921 }
922 $i = 0;
923 foreach ( $column_array as $col ) {
924 if ( isset( $column_images[$col] ) ) {
925 array_push( $images_array, $i );
926 }
927 $i++;
928 }
929 $i = 0;
930 foreach ( $column_array as $col ) {
931 if ( isset( $column_attachments[$col] ) ) {
932 array_push( $attachments_array, $i );
933 }
934 $i++;
935 }
936 } else {
937 $pub_format = null;
938 }
939 // Check media columns defined on plugin level and add to arrays
940 $i = 0;
941 foreach ( $column_array as $col ) {
942 if ( 'Image' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
943 if ( !isset( $images_array[$i] ) ) {
944 array_push( $images_array, $i );
945 }
946 } elseif ( 'ImageURL' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
947 array_push( $imagesurl_array, $i );
948 } elseif ( 'Attachment' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
949 if ( !isset( $attachments_array[$i] ) ) {
950 array_push( $attachments_array, $i );
951 }
952 } elseif ( 'Hyperlink' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
953 if ( !isset( $hyperlinks_array[$i] ) ) {
954 array_push( $hyperlinks_array, $i );
955 array_push( $hyperlinks_array_col, $col );
956 }
957 } elseif ( 'Audio' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
958 array_push( $audio_array, $i );
959 } elseif ( 'Video' === WPDA_Media_Model::get_column_media( $table_name, $col, $database ) ) {
960 array_push( $video_array, $i );
961 }
962 $i++;
963 }
964 // Change dynamic hyperlinks
965 $update = array();
966 $i = 0;
967 $hyperlinks_column_index = array();
968 foreach ( $column_array as $col ) {
969 if ( 'wpda_hyperlink_' === substr( $col, 0, 15 ) ) {
970 $update[$col] = "'x' as {$col}";
971 $hyperlinks_column_index[$i] = substr( $col, 15 );
972 } else {
973 $update[$col] = '`' . str_replace( '`', '', $col ) . '`';
974 }
975 $i++;
976 }
977 $column_array = $update;
978 $columns_backticks = implode( ',', $column_array ) . $geo_radius_col;
979 $query = "select {$columns_backticks} from `{$wpdadb->dbname}`.`{$table_name}` {$where}";
980 if ( '' !== $orderby ) {
981 $query .= " order by {$orderby} ";
982 }
983 if ( -1 != $limit ) {
984 $query .= $wpdadb->prepare( " limit %d offset %d", [$limit, $offset] );
985 }
986 $hyperlinks = array();
987 if ( count( $hyperlinks_column_index ) ) {
988 if ( isset( $table_settings->hyperlinks ) ) {
989 foreach ( $table_settings->hyperlinks as $hyperlink ) {
990 $hyperlink_label = ( isset( $hyperlink->hyperlink_label ) ? $hyperlink->hyperlink_label : '' );
991 $hyperlink_target = ( isset( $hyperlink->hyperlink_target ) ? $hyperlink->hyperlink_target : false );
992 $hyperlink_html = ( isset( $hyperlink->hyperlink_html ) ? $hyperlink->hyperlink_html : '' );
993 if ( $hyperlink_label !== '' && $hyperlink_html !== '' ) {
994 array_push( $hyperlinks, array(
995 'hyperlink_label' => $hyperlink_label,
996 'hyperlink_target' => $hyperlink_target,
997 'hyperlink_html' => $hyperlink_html,
998 ) );
999 }
1000 }
1001 }
1002 }
1003 $nl2br = ( isset( $_REQUEST['nl2br'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['nl2br'] ) ) : '' );
1004 // input var okay.
1005 if ( 'on' === $nl2br || 'yes' === $nl2br || 'true' === $nl2br ) {
1006 $nl2br = 'on';
1007 } else {
1008 if ( '' !== $pub_id ) {
1009 if ( isset( $publication[0]['pub_table_options_nl2br'] ) ) {
1010 $nl2br = $publication[0]['pub_table_options_nl2br'];
1011 }
1012 }
1013 }
1014 $wpdadb->suppress_errors( true );
1015 $rows = $wpdadb->get_results( $query, 'ARRAY_N' );
1016 if ( '' !== $wpdadb->last_error ) {
1017 $this->create_empty_response( __( 'ERROR: Invalid query', 'wp-data-access' ) );
1018 WPDA::wpda_log_wp_error( $wpdadb->last_error );
1019 wp_die();
1020 }
1021 $rows_final = array();
1022 foreach ( $rows as $row ) {
1023 $row_orig = $row;
1024 if ( 'on' === $nl2br && null !== $nl2br ) {
1025 // Replace NL with BR tags
1026 for ($nl = 0; $nl < count( $row ); $nl++) {
1027 $row[$nl] = nl2br( (string) $row[$nl] );
1028 }
1029 }
1030 foreach ( $hyperlinks_column_index as $key => $value ) {
1031 if ( isset( $hyperlinks[$value] ) ) {
1032 $hyperlink_html = ( isset( $hyperlinks[$value]['hyperlink_html'] ) ? $hyperlinks[$value]['hyperlink_html'] : '' );
1033 if ( '' !== $hyperlink_html ) {
1034 $i = 0;
1035 foreach ( $column_array as $column ) {
1036 $column_name = str_replace( '`', '', $column );
1037 $hyperlink_html = str_replace( "\$\${$column_name}\$\$", $row[$i], $hyperlink_html );
1038 $i++;
1039 }
1040 }
1041 $macro = new WPDA_Macro($hyperlink_html);
1042 $hyperlink_html = $macro->exe_macro();
1043 if ( '' !== $hyperlink_html ) {
1044 if ( false !== strpos( ltrim( $hyperlink_html ), '&lt;' ) ) {
1045 $row[$key] = html_entity_decode( $hyperlink_html );
1046 } else {
1047 $hyperlink_label = ( isset( $hyperlinks[$value]['hyperlink_label'] ) ? $hyperlinks[$value]['hyperlink_label'] : '' );
1048 $hyperlink_target = ( isset( $hyperlinks[$value]['hyperlink_target'] ) ? $hyperlinks[$value]['hyperlink_target'] : false );
1049 $target = ( true === $hyperlink_target ? "target='_blank'" : '' );
1050 $row[$key] = "<a href='" . str_replace( ' ', '+', $hyperlink_html ) . "' {$target}>{$hyperlink_label}</a>";
1051 }
1052 } else {
1053 $row[$key] = '';
1054 }
1055 } else {
1056 $row[$key] = 'ERROR';
1057 }
1058 }
1059 for ($i = 0; $i < count( $imagesurl_array ); $i++) {
1060 $row[$imagesurl_array[$i]] = '<img src="' . $row[$imagesurl_array[$i]] . '" width="100%">';
1061 }
1062 for ($i = 0; $i < count( $images_array ); $i++) {
1063 $image_ids = explode( ',', (string) $row[$images_array[$i]] );
1064 $image_src = '';
1065 foreach ( $image_ids as $image_id ) {
1066 $url = wp_get_attachment_url( esc_attr( $image_id ) );
1067 if ( false !== $url ) {
1068 $image_src .= ( '' !== $image_src ? '<br/>' : '' );
1069 $image_src .= '<img src="' . $url . '" width="100%">';
1070 }
1071 }
1072 $row[$images_array[$i]] = $image_src;
1073 }
1074 for ($i = 0; $i < count( $attachments_array ); $i++) {
1075 $media_ids = explode( ',', (string) $row[$attachments_array[$i]] );
1076 $media_links = '';
1077 foreach ( $media_ids as $media_id ) {
1078 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1079 if ( false !== $url ) {
1080 $mime_type = get_post_mime_type( $media_id );
1081 if ( false !== $mime_type ) {
1082 $title = get_the_title( esc_attr( $media_id ) );
1083 $media_links .= WPDA_List_Table::column_media_attachment( $url, $title, $mime_type );
1084 }
1085 }
1086 }
1087 $row[$attachments_array[$i]] = $media_links;
1088 }
1089 if ( isset( $hyperlinks_array ) ) {
1090 $hyperlink_definition = ( isset( $table_settings->table_settings->hyperlink_definition ) && 'text' === $table_settings->table_settings->hyperlink_definition ? 'text' : 'json' );
1091 for ($i = 0; $i < count( $hyperlinks_array ); $i++) {
1092 if ( 'json' === $hyperlink_definition ) {
1093 $hyperlink = json_decode( (string) $row[$hyperlinks_array[$i]], true );
1094 if ( is_array( $hyperlink ) && isset( $hyperlink['label'] ) && isset( $hyperlink['url'] ) && isset( $hyperlink['target'] ) ) {
1095 if ( '' === $hyperlink['url'] ) {
1096 $row[$hyperlinks_array[$i]] = esc_attr( $hyperlink['label'] );
1097 } else {
1098 $row[$hyperlinks_array[$i]] = "<a href='" . esc_url_raw( $hyperlink['url'] ) . "' target='" . esc_attr( $hyperlink['target'] ) . "'>" . esc_attr( $hyperlink['label'] ) . "</a>";
1099 }
1100 } else {
1101 $row[$hyperlinks_array[$i]] = '';
1102 }
1103 } else {
1104 if ( null !== $row[$hyperlinks_array[$i]] && '' !== $row[$hyperlinks_array[$i]] ) {
1105 $hyperlink_label = esc_attr( $this->wpda_list_columns->get_column_label( $hyperlinks_array_col[$i] ) );
1106 $row[$hyperlinks_array[$i]] = "<a href='" . esc_url_raw( $row[$hyperlinks_array[$i]] ) . "' target='_blank'>" . esc_attr( $hyperlink_label ) . "</a>";
1107 } else {
1108 $row[$hyperlinks_array[$i]] = '';
1109 }
1110 }
1111 }
1112 }
1113 for ($i = 0; $i < count( $audio_array ); $i++) {
1114 $media_ids = explode( ',', (string) $row[$audio_array[$i]] );
1115 $media_links = '';
1116 foreach ( $media_ids as $media_id ) {
1117 if ( 'audio' === substr( get_post_mime_type( $media_id ), 0, 5 ) ) {
1118 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1119 if ( false !== $url ) {
1120 $title = get_the_title( esc_attr( $media_id ) );
1121 if ( false !== $url ) {
1122 $media_links .= '<div class="wpda_tooltip" title="' . esc_attr( $title ) . '">' . do_shortcode( '[audio src="' . esc_url_raw( $url ) . '"]' ) . '</div>';
1123 }
1124 }
1125 }
1126 }
1127 $row[$audio_array[$i]] = $media_links;
1128 }
1129 for ($i = 0; $i < count( $video_array ); $i++) {
1130 $media_ids = explode( ',', (string) $row[$video_array[$i]] );
1131 $media_links = '';
1132 foreach ( $media_ids as $media_id ) {
1133 if ( 'video' === substr( get_post_mime_type( $media_id ), 0, 5 ) ) {
1134 $url = wp_get_attachment_url( esc_attr( $media_id ) );
1135 if ( false !== $url ) {
1136 if ( false !== $url ) {
1137 $media_links .= do_shortcode( '[video src="' . esc_url_raw( $url ) . '"]' );
1138 }
1139 }
1140 }
1141 }
1142 $row[$video_array[$i]] = $media_links;
1143 }
1144 // Format date and time columns
1145 for ($i = 0; $i < count( $row ); $i++) {
1146 if ( '' !== $row[$i] && null !== $row[$i] ) {
1147 if ( isset( $column_array_clean[$i] ) ) {
1148 if ( isset( $column_array_ordered[$column_array_clean[$i]] ) ) {
1149 switch ( $column_array_ordered[$column_array_clean[$i]] ) {
1150 case 'date':
1151 $row[$i] = date_i18n( get_option( 'date_format' ), strtotime( $row[$i] ) );
1152 break;
1153 case 'time':
1154 $row[$i] = date_i18n( get_option( 'time_format' ), strtotime( $row[$i] ) );
1155 break;
1156 case 'datetime':
1157 case 'timestamp':
1158 $row[$i] = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $row[$i] ) );
1159 }
1160 }
1161 }
1162 }
1163 }
1164 // Remove script tags if available
1165 for ($i = 0; $i < count( $row ); $i++) {
1166 $row[$i] = str_replace( array('<script>', '</script>'), array('&lt;script&gt;', '&lt;/script&gt;'), (string) $row[$i] );
1167 }
1168 array_push( $rows_final, $row );
1169 }
1170 if ( $this->serverSide ) {
1171 if ( isset( $_REQUEST['records_total'] ) && is_numeric( $_REQUEST['records_total'] ) && (!isset( $json->wpda_count_on_each_request ) || false === $json->wpda_count_on_each_request) ) {
1172 // Prevent row count on each request
1173 $rows_estimate = sanitize_text_field( wp_unslash( $_REQUEST['records_total'] ) );
1174 // input var okay.
1175 $do_real_count = false;
1176 } else {
1177 $row_count_estimate = WPDA::get_row_count_estimate( $database, $table_name, $table_settings );
1178 $rows_estimate = $row_count_estimate['row_count'];
1179 $do_real_count = $row_count_estimate['do_real_count'];
1180 }
1181 } else {
1182 $rows_estimate = count( $rows_final );
1183 $do_real_count = false;
1184 }
1185 if ( 'more' === $publication_mode ) {
1186 // Use estimate row count
1187 $count_table = $rows_estimate;
1188 $count_table_filtered = $rows_estimate;
1189 } else {
1190 if ( !$do_real_count ) {
1191 // Use estimate row count
1192 $count_table = $rows_estimate;
1193 } else {
1194 // Count rows in table = real row count
1195 $query2 = "select count(*) from `{$wpdadb->dbname}`.`{$table_name}`";
1196 $count_rows = $wpdadb->get_results( $query2, 'ARRAY_N' );
1197 $count_table = $count_rows[0][0];
1198 // Number of rows in table.
1199 }
1200 if ( isset( $_REQUEST['wpda_use_estimates_only'] ) && 'true' === $_REQUEST['wpda_use_estimates_only'] ) {
1201 // Prevent row count, only estimates required
1202 $count_table_filtered = $count_table;
1203 } else {
1204 if ( '' !== $where ) {
1205 if ( isset( $_REQUEST['records_filtered'] ) && is_numeric( $_REQUEST['records_filtered'] ) && (!isset( $json->wpda_count_on_each_request ) || false === $json->wpda_count_on_each_request) ) {
1206 $count_table_filtered = sanitize_text_field( wp_unslash( $_REQUEST['records_filtered'] ) );
1207 // input var okay.
1208 } else {
1209 // Count rows in selection (only necessary if a search criteria was entered).
1210 $query3 = "select count(*) from `{$wpdadb->dbname}`.`{$table_name}` {$where}";
1211 $count_rows_filtered = $wpdadb->get_results( $query3, 'ARRAY_N' );
1212 $count_table_filtered = $count_rows_filtered[0][0];
1213 // Number of rows in table.
1214 }
1215 } else {
1216 // No search criteria entered: # filtered rows = # table rows.
1217 $count_table_filtered = $count_table;
1218 }
1219 }
1220 }
1221 // Convert query result to jQuery DataTables object.
1222 $obj = (object) null;
1223 $obj->draw = ( isset( $_REQUEST['draw'] ) ? intval( $_REQUEST['draw'] ) : 0 );
1224 $obj->recordsTotal = intval( $count_table );
1225 $obj->recordsFiltered = intval( $count_table_filtered );
1226 $obj->data = $rows_final;
1227 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1228 $obj->error = $wpdadb->last_error;
1229 }
1230 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1231 $obj->debug = array(
1232 'columns' => $columns,
1233 'columns_backticks' => $columns_backticks,
1234 'query' => $query,
1235 'where' => $where,
1236 'orderby' => $orderby,
1237 'filter' => $_filter,
1238 'advanced_settings' => $json,
1239 'column_labels' => $this->wpda_list_columns->get_table_column_headers(),
1240 'labels' => array_flip( $this->get_labels( json_encode( $pub_format ) ) ),
1241 'serverSide' => $this->serverSide,
1242 );
1243 }
1244 // Send header
1245 if ( !WPDA::wpda_verify_sonce( $wpnonce, 'wpda-publication-' . $table_name . '-' ) ) {
1246 WPDA::sent_header( 'application/json' );
1247 } else {
1248 // Enable CORS for embedded publications
1249 WPDA::sent_header( 'application/json', '*' );
1250 }
1251 // Convert object to json. jQuery DataTables needs json format.
1252 echo json_encode( $obj );
1253 wp_die();
1254 }
1255
1256 private function get_data_custom_query(
1257 $publication,
1258 $json,
1259 $has_sp,
1260 $sp_columns,
1261 $sql_query,
1262 $is_cpt,
1263 $offset,
1264 $limit
1265 ) {
1266 return null;
1267 }
1268
1269 private function get_orderby_from_request() {
1270 $orderby = '';
1271 // Init order by.
1272 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
1273 if ( isset( $_REQUEST['order'] ) && is_array( $_REQUEST['order'] ) ) {
1274 foreach ( $_REQUEST['order'] as $order_column ) {
1275 if ( isset( $order_column['column'], $order_column['dir'] ) && is_numeric( $order_column['column'] ) && ('asc' === $order_column['dir'] || 'desc' === $order_column['dir']) ) {
1276 $preprend = ( '' === $orderby ? ' order by ' : ',' );
1277 $orderby .= $preprend . (intval( $order_column['column'] ) + 1) . ' ' . $order_column['dir'];
1278 }
1279 }
1280 }
1281 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
1282 return $orderby;
1283 }
1284
1285 private function sp(
1286 $wpdadb,
1287 $table_name,
1288 $columns,
1289 $panes,
1290 $where,
1291 $bt = '`'
1292 ) {
1293 $sp = array();
1294 return $sp;
1295 }
1296
1297 public function qb_group( $data ) {
1298 return null;
1299 }
1300
1301 public function qb_criteria( $crit ) {
1302 return null;
1303 }
1304
1305 private function qb( $labels ) {
1306 return null;
1307 }
1308
1309 private function create_empty_response( $error = '', $debug = '' ) {
1310 $obj = (object) null;
1311 $obj->draw = 0;
1312 $obj->recordsTotal = 0;
1313 $obj->recordsFiltered = 0;
1314 $obj->data = array();
1315 $obj->error = $error;
1316 if ( 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG ) ) {
1317 $obj->debug = $debug;
1318 }
1319 echo json_encode( $obj );
1320 }
1321
1322 }
1323
1324 // phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing