PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / 6.5.1.7
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin v6.5.1.7
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / source / class.wdttools.php

class.wdttools.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin 6.5.1.7, at source/class.wdttools.php

1,390 lines 59.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined('ABSPATH') or die("Cannot access pages directly.");
4
5 class WDTTools
6 {
7
8 public static $jsVars = array();
9
10 /**
11 * Helper function that returns array of possible column types
12 * @return array
13 */
14 public static function getPossibleColumnTypes()
15 {
16 return array(
17 'input' => __('One line string', 'wpdatatables'),
18 'memo' => __('Multi-line string', 'wpdatatables'),
19 'select' => __('One-line selectbox', 'wpdatatables'),
20 'multiselect' => __('Multi-line selectbox', 'wpdatatables'),
21 'int' => __('Integer', 'wpdatatables'),
22 'float' => __('Float', 'wpdatatables'),
23 'date' => __('Date', 'wpdatatables'),
24 'datetime' => __('Datetime', 'wpdatatables'),
25 'time' => __('Time', 'wpdatatables'),
26 'link' => __('URL Link', 'wpdatatables'),
27 'email' => __('E-mail', 'wpdatatables'),
28 'image' => __('Image', 'wpdatatables'),
29 'file' => __('Attachment', 'wpdatatables')
30 );
31 }
32
33 /**
34 * Helper function that sanitize column header
35 * @param $header
36 * @return mixed
37 */
38 public static function sanitizeHeader($header)
39 {
40 return
41 str_replace(
42 range('0', '9'),
43 range('a', 'j'),
44 str_replace(
45 array('$', '_', '&', ' '),
46 '',
47 $header
48 )
49 );
50 }
51
52
53 /**
54 * Helper function that returns curl data
55 * @param $url
56 * @return mixed|null
57 * @throws Exception
58 */
59 public static function curlGetData($url)
60 {
61 $ch = curl_init();
62 $timeout = 100;
63 $agent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36';
64
65 curl_setopt($ch, CURLOPT_URL, $url);
66 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
67 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
68 curl_setopt($ch, CURLOPT_USERAGENT, $agent);
69 curl_setopt($ch, CURLOPT_REFERER, site_url());
70 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
71
72 $data = apply_filters('wpdatatables_curl_get_data', null, $ch, $url);
73 if( null === $data ) {
74 $data = curl_exec($ch);
75 if (curl_error($ch)) {
76 $error = curl_error($ch);
77 curl_close($ch);
78
79 throw new Exception($error);
80 }
81 if (strpos($data, '<TITLE>Moved Temporarily</TITLE>') ||
82 strpos($data, 'Error 400 (Bad Request)')) {
83 throw new Exception(__('wpDataTables was unable to read your Google Spreadsheet, as it\'s not been published correctly. <br/> You can publish it by going to <b>File ->Share -> Publish to the web</b> ', 'wpdatatables'));
84 }
85 $info = curl_getinfo($ch);
86 curl_close($ch);
87
88 if ($info['http_code'] === 404) {
89 return NULL;
90 }
91 if ($info['http_code'] === 401) {
92 throw new Exception(__('wpDataTables was unable to access data. Unauthorized access. Please make file accessible.', 'wpdatatables'));
93 }
94
95 $data = apply_filters('wpdatatables_curl_get_data_complete', $data, $url);
96 }
97
98 return $data;
99 }
100
101
102 /**
103 * Helper function to find CSV delimiter
104 * @param $csv_url
105 * @return string
106 */
107 public static function detectCSVDelimiter($csv_url)
108 {
109
110 if (!file_exists($csv_url) || !is_readable($csv_url)) {
111 throw new WDTException('Could not open ' . $csv_url . ' for reading! File does not exist.');
112 }
113 $fileResurce = fopen($csv_url, 'r');
114
115 $delimiterList = [',', ':', ';', "\t", '|'];
116 $counts = [];
117 foreach ($delimiterList as $delimiter) {
118 $counts[$delimiter] = [];
119 }
120
121 $lineNumber = 0;
122 while (($line = fgets($fileResurce)) !== false && (++$lineNumber < 1000)) {
123 $lineCount = [];
124 for ($i = strlen($line) - 1; $i >= 0; --$i) {
125 $character = $line[$i];
126 if (isset($counts[$character])) {
127 if (!isset($lineCount[$character])) {
128 $lineCount[$character] = 0;
129 }
130 ++$lineCount[$character];
131 }
132 }
133 foreach ($delimiterList as $delimiter) {
134 $counts[$delimiter][] = isset($lineCount[$delimiter])
135 ? $lineCount[$delimiter]
136 : 0;
137 }
138 }
139
140 $RMSD = [];
141 $middleIdx = floor(($lineNumber - 1) / 2);
142
143 foreach ($delimiterList as $delimiter) {
144 $series = $counts[$delimiter];
145 sort($series);
146
147 $median = ($lineNumber % 2)
148 ? $series[$middleIdx]
149 : ($series[$middleIdx] + $series[$middleIdx + 1]) / 2;
150
151 if ($median === 0) {
152 continue;
153 }
154
155 $RMSD[$delimiter] = array_reduce(
156 $series,
157 function ($sum, $value) use ($median) {
158 return $sum + pow($value - $median, 2);
159 }
160 ) / count($series);
161 }
162
163 $min = INF;
164 foreach ($delimiterList as $delimiter) {
165 if (!isset($RMSD[$delimiter])) {
166 continue;
167 }
168
169 if ($RMSD[$delimiter] < $min) {
170 $min = $RMSD[$delimiter];
171 $finalDelimiter = $delimiter;
172 }
173 }
174
175 if ($delimiter === null) {
176 $finalDelimiter = reset($delimiterList);
177 }
178
179 return $finalDelimiter;
180 }
181
182
183 /**
184 * Helper function that convert CSV file to Array
185 * @param $csv
186 * @return array
187 */
188 public static function csvToArray($csv)
189 {
190 $arr = array();
191 $lines = explode("\n", $csv);
192 foreach ($lines as $row) {
193 $arr[] = str_getcsv($row, ",");
194 }
195 $count = count($arr) - 1;
196 $labels = array_shift($arr);
197 $countLabels = count($labels);
198 $keys = array();
199 foreach ($labels as $label) {
200 $keys[] = trim(preg_replace('/\s\s+/', ' ', str_replace("\n", " ", $label)));
201 }
202 $keys = array_map('trim', $keys);
203 $returnArray = array();
204 for ($j = 0; $j < $count; $j++) {
205 if (count($arr[$j]) < $countLabels){
206 for ($k = 0; $k < $countLabels; $k++){
207 if(!isset($arr[$j][$k])){
208 $arr[$j][$k] = '';
209 }
210 }
211 }
212 if (count($keys) == count($arr[$j])) {
213 $d = array_combine($keys, $arr[$j]);
214 $returnArray[$j] = $d;
215 }
216 }
217 return $returnArray;
218 }
219
220 public static function getTranslationStringsPlugin()
221 {
222 return array(
223 'success' => __('Success!', 'wpdatatables'),
224 'error' => __('Error!', 'wpdatatables'),
225 );
226 }
227 /**
228 * Helper function that returns array of translation strings used for localization of JavaScript files
229 * @return array
230 */
231 public static function getTranslationStrings()
232 {
233 return array(
234 'back_to_date' => __('Back to date', 'wpdatatables'),
235 'browse_file' => __('Browse', 'wpdatatables'),
236 'cancel' => __('Cancel', 'wpdatatables'),
237 'cannot_be_empty' => __(' field cannot be empty!', 'wpdatatables'),
238 'choose_file' => __('Use selected file', 'wpdatatables'),
239 'chooseFile' => __('Choose file', 'wpdatatables'),
240 'close' => __('Close', 'wpdatatables'),
241 'columnAdded' => __('Column has been added!', 'wpdatatables'),
242 'columnHeaderEmpty' => __('Column header cannot be empty!', 'wpdatatables'),
243 'columnRemoveConfirm' => __('Please confirm column deletion!', 'wpdatatables'),
244 'columnRemoved' => __('Column has been removed!', 'wpdatatables'),
245 'columnsEmpty' => __('Please select columns that you want to use in table', 'wpdatatables'),
246 'copy' => __('Copy', 'wpdatatables'),
247 'databaseInsertError' => __('There was an error trying to insert a new row!', 'wpdatatables'),
248 'dataSaved' => __('Data has been saved!', 'wpdatatables'),
249 'detach_file' => __('detach', 'wpdatatables'),
250 'delete' => __('Delete', 'wpdatatables'),
251 'deleteSelected' => __('Delete selected', 'wpdatatables'),
252 'error' => __('Error!', 'wpdatatables'),
253 'fileUploadEmptyFile' => __('Please upload or choose a file from Media Library!', 'wpdatatables'),
254 'from' => __('From', 'wpdatatables'),
255 'invalid_email' => __('Please provide a valid e-mail address for field', 'wpdatatables'),
256 'invalid_link' => __('Please provide a valid URL link for field', 'wpdatatables'),
257 'invalid_value' => __('You have entered invalid value. Press ESC to cancel.', 'wpdatatables'),
258 'lengthMenu' => __('Show _MENU_ entries', 'wpdatatables'),
259 'merge' => __('Merge', 'wpdatatables'),
260 'newColumnName' => __('New column', 'wpdatatables'),
261 'numberOfColumnsError' => __('Number of columns can not be empty or 0', 'wpdatatables'),
262 'numberOfRowsError' => __('Number of rows can not be empty or 0', 'wpdatatables'),
263 'oAria' => array(
264 'sSortAscending' => __(': activate to sort column ascending', 'wpdatatables'),
265 'sSortDescending' => __(': activate to sort column descending', 'wpdatatables')
266 ),
267 'ok' => __('Ok', 'wpdatatables'),
268 'oPaginate' => array(
269 'sFirst' => __('First', 'wpdatatables'),
270 'sLast' => __('Last', 'wpdatatables'),
271 'sNext' => __('Next', 'wpdatatables'),
272 'sPrevious' => __('Previous', 'wpdatatables')
273 ),
274 'replace' => __('Replace', 'wpdatatables'),
275 'rowDeleted' => __('Row has been deleted!', 'wpdatatables'),
276 'saveChart' => __('Save chart', 'wpdatatables'),
277 'select_upload_file' => __('Select a file to use in table', 'wpdatatables'),
278 'selectExcelCsv' => __('Select an Excel or CSV file', 'wpdatatables'),
279 'sEmptyTable' => __('No data available in table', 'wpdatatables'),
280 'settings_saved_successful' => __('Plugin settings saved successfully', 'wpdatatables'),
281 'settings_saved_error' => __('Unable to save settings of plugin. Please try again or contact us over Support page.', 'wpdatatables'),
282 'shortcodeSaved' => __('Shortcode has been copied to the clipboard.', 'wpdatatables'),
283 'sInfo' => __('Showing _START_ to _END_ of _TOTAL_ entries', 'wpdatatables'),
284 'sInfoEmpty' => __('Showing 0 to 0 of 0 entries', 'wpdatatables'),
285 'sInfoFiltered' => __('(filtered from _MAX_ total entries)', 'wpdatatables'),
286 'sInfoPostFix' => '',
287 'sInfoThousands' => __(',', 'wpdatatables'),
288 'sLengthMenu' => __('Show _MENU_ entries', 'wpdatatables'),
289 'sLoadingRecords' => __('Loading...', 'wpdatatables'),
290 'sProcessing' => __('Processing...', 'wpdatatables'),
291 'sqlError' => __('SQL error', 'wpdatatables'),
292 'sSearch' => __('Search: ', 'wpdatatables'),
293 'success' => __('Success!', 'wpdatatables'),
294 'sZeroRecords' => __('No matching records found', 'wpdatatables'),
295 'systemInfoSaved' => __('System info data has been copied to the clipboard. You can now paste it in file or in support topic.', 'wpdatatables'),
296 'tableSaved' => __('Table saved successfully!', 'wpdatatables'),
297 'to' => __('To', 'wpdatatables'),
298 'clear_table_data' => __('Clear table data', 'wpdatatables'),
299 'star_rating' => __('Star rating', 'wpdatatables'),
300 'shortcode' => __('Shortcode', 'wpdatatables'),
301 'html_code' => __('HTML code', 'wpdatatables'),
302 'media' => __('Media', 'wpdatatables'),
303 'link' => __('Link', 'wpdatatables'),
304 'clip' => __('Clip', 'wpdatatables'),
305 'overflow' => __('Overflow', 'wpdatatables'),
306 'wrap' => __('Wrap', 'wpdatatables'),
307 'left' => __('Left', 'wpdatatables'),
308 'center' => __('Center', 'wpdatatables'),
309 'right' => __('Right', 'wpdatatables'),
310 'justify' => __('Justify', 'wpdatatables'),
311 'top' => __('Top', 'wpdatatables'),
312 'middle' => __('Middle', 'wpdatatables'),
313 'bottom' => __('Bottom', 'wpdatatables'),
314 'insert_row_above' => __('Insert row above', 'wpdatatables'),
315 'insert_row_below' => __('Insert row below', 'wpdatatables'),
316 'remove_row' => __('Remove row', 'wpdatatables'),
317 'insert_col_left' => __('Insert column left', 'wpdatatables'),
318 'insert_col_right' => __('Insert column right', 'wpdatatables'),
319 'remove_column' => __('Remove column', 'wpdatatables'),
320 'alignment' => __('Alignment', 'wpdatatables'),
321 'cut' => __('Cut', 'wpdatatables'),
322 'insert_custom' => __('Insert custom', 'wpdatatables'),
323 'undo' => __('Undo', 'wpdatatables'),
324 'redo' => __('Redo', 'wpdatatables'),
325 'text_wrapping' => __('Text wrapping', 'wpdatatables'),
326 'merge_cells' => __('Merge cells', 'wpdatatables'),
327 'firstPageWCAG' => __('First page', 'wpdatatables'),
328 'lastPageWCAG' => __('Last page', 'wpdatatables'),
329 'nextPageWCAG' => __('Next page', 'wpdatatables'),
330 'previousPageWCAG' => __('Previous page', 'wpdatatables'),
331 'pageWCAG' => __('wpDataTable Page ', 'wpdatatables'),
332 'spacerWCAG' => __('Spacer', 'wpdatatables'),
333 'printTableWCAG' => __('Print table', 'wpdatatables'),
334 'exportTableWCAG' => __('Export table', 'wpdatatables'),
335 'clearFiltersWCAG' => __('Clear filters', 'wpdatatables'),
336 'colvisWCAG' => __('Column visibility', 'wpdatatables'),
337 'invalidResponseServer' => __('Invalid response from server', 'wpdatatables'),
338 'failedToLoadFormFields' => __('Failed to load form fields', 'wpdatatables'),
339 );
340 }
341
342 /**
343 * Helper function that returns all update info
344 * @return array
345 */
346 public static function getDeactivationInfo()
347 {
348 return array(
349 'version' => get_option('wdtVersion'),
350 'wdt_nonce' => wp_nonce_field('wdtDeactivationNonce', 'wdtNonce'),
351 'titleDeactivation' => __('QUICK FEEDBACK', 'wpdatatables'),
352 'captionDeactivation' => __('If you have a moment, please let us know why you are deactivating the wpDataTables plugin:', 'wpdatatables'),
353 'captionDeactivationError' => __('Please select one option from the following list: ', 'wpdatatables'),
354 'deactivate_reasons' => [
355 0 => [
356 'id' => 'feature_needed',
357 'title' => esc_html__( 'The plugin doesn’t have a feature that I need' ),
358 'input_placeholder' => esc_html__('Please explain your use case and the feature you need: '),
359 'alert' => '',
360 ],
361 1 => [
362 'id' => 'premium_version',
363 'title' => esc_html__( 'I bought the premium version' ),
364 'input_placeholder' => '',
365 'alert' => '',
366 ],
367 2 => [
368 'id' => 'stopped_working',
369 'title' => esc_html__( 'The plugin suddenly stopped working' ),
370 'input_placeholder' => esc_html__('Tell us more… '),
371 'alert' => esc_html__('Have you reached out to our support team?'),
372 ],
373 3 => [
374 'id' => 'broke_my_site',
375 'title' => esc_html__( 'The plugin broke my site' ),
376 'input_placeholder' => esc_html__('Tell us more… '),
377 'alert' => esc_html__('Have you reached out to our support team?'),
378 ],
379 4 => [
380 'id' => 'better_plugin',
381 'title' => esc_html__( 'I found a better plugin' ),
382 'input_placeholder' => esc_html__('Please share which plugin: '),
383 'alert' => '',
384 ],
385 5 => [
386 'id' => 'temporary_deactivation',
387 'title' => esc_html__( 'It is a temporary deactivation - I’m troubleshooting an issue' ),
388 'input_placeholder' => '',
389 'alert' => '',
390 ],
391 6 => [
392 'id' => 'able_to_work',
393 'title' => esc_html__( 'I haven’t been able to get the plugin to work' ),
394 'input_placeholder' => esc_html__('Tell us more… '),
395 'alert' => esc_html__('Have you reached out to our support team?'),
396 ],
397 7 => [
398 'id' => 'no_longer_needed',
399 'title' => esc_html__( 'I no longer need the plugin' ),
400 'input_placeholder' => esc_html__('Please share more about your use case: '),
401 'alert' => '',
402 ],
403 8 => [
404 'id' => 'conflict',
405 'title' => esc_html__( 'The plugin has a conflict with the theme or other plugin' ),
406 'input_placeholder' => esc_html__('Please share which plugin/theme: '),
407 'alert' => esc_html__('Have you reached out to our support team?'),
408 ],
409 9 => [
410 'id' => 'other',
411 'title' => esc_html__( 'Other' ),
412 'input_placeholder' => esc_html__('How could we improve? '),
413 'alert' => '',
414 ],
415 ]
416 );
417 }
418
419 /**
420 * Helper function that returns an array with date and time settings from wp_options
421 * @return array
422 */
423 public static function getDateTimeSettings()
424 {
425 return array(
426 'wdtDateFormat' => get_option('wdtDateFormat'),
427 'wdtTimeFormat' => get_option('wdtTimeFormat')
428 );
429 }
430
431 /**
432 * Helper function that returns an array with wpDataTables admin pages
433 * @return array
434 */
435 public static function getWpDataTablesAdminPages()
436 {
437 return array(
438 'dashboardUrl' => menu_page_url('wpdatatables-dashboard', false),
439 'browseTablesUrl' => menu_page_url('wpdatatables-administration', false),
440 'browseChartsUrl' => menu_page_url('wpdatatables-charts', false),
441 'liteVSPremiumUrl' => menu_page_url('wpdatatables-lite-vs-premium', false)
442 );
443 }
444 /**
445 * Helper function that returns an array with wpDataTables popover strings
446 * @return array
447 */
448 public static function getWpDataTablesPopoverStrings()
449 {
450 return array(
451 'title' => __('This is a premium feature', 'wpdatatables'),
452 'description' => __('This feature is available only in premium version of wpDataTables', 'wpdatatables'),
453 'compare_link' => __('Compare and View Pricing', 'wpdatatables'),
454 );
455 }
456
457
458 /**
459 * Helper function that returns an array of strings for tutorials
460 * @return array
461 */
462 public static function getTutorialsTranslationStrings()
463 {
464 $guideTeacherIMG = '<img class="wdt-emoji-title" src="'. WDT_ROOT_URL . 'assets/img/male-teacher.png">';
465 $waveIMG = '<img class="wdt-emoji-body" src="'. WDT_ROOT_URL . 'assets/img/wave.png">';
466 $partyTitleIMG = '<img class="wdt-emoji-title" src="'. WDT_ROOT_URL . 'assets/img/party-popper.png">';
467 $hourglassIMG = '<img class="wdt-emoji-title" src="'. WDT_ROOT_URL . 'assets/img/hourglass-not-done.png">';
468 $raisedHandsIMG = '<img class="wdt-emoji-title m-l-5" src="'. WDT_ROOT_URL . 'assets/img/raising-hands.png">';
469 $chartIMG = '<img class="wdt-emoji-title" src="'. WDT_ROOT_URL . 'assets/img/chart-increasing.png">';
470
471 return array(
472 'cannot_be_empty_field' => __('Field cannot be empty!', 'wpdatatables'),
473 'cannot_be_empty_chart_type' => __('Please choose chart type.', 'wpdatatables'),
474 'cannot_be_empty_chart_table' => __('Please select wpDataTable from dropdown.', 'wpdatatables'),
475 'cannot_be_empty_chart_table_columns' => __('Columns field cannot be empty', 'wpdatatables'),
476 'cancel_button' => __('Cancel', 'wpdatatables'),
477 'cancel_tour' => __('Tutorial is not canceled, closed or end properly. Please cancel it by clicking on Cancel button.', 'wpdatatables'),
478 'finish_button' => __('Finish Tutorial', 'wpdatatables'),
479 'next_button' => __('Continue', 'wpdatatables'),
480 'start_button' => __('Start', 'wpdatatables'),
481 'skip_button' => __('Skip Tutorial', 'wpdatatables'),
482 'tour0' => array(
483 'step0' => array(
484 'title' => $guideTeacherIMG . __('Welcome to the tutorial!', 'wpdatatables'),
485 'content' => __('Hello ', 'wpdatatables') . $waveIMG . __(', in this tutorial, we will show you how to create a simple table from scratch by choosing a custom number of columns and rows. How to customize each cell, merge cells and a lot more.', 'wpdatatables'),
486 ),
487 'step1' => array(
488 'title' => __(' Let\'s create a new wpDataTable from scratch!', 'wpdatatables'),
489 'content' => __('Click on \'Create a Table\' to access the wpDataTables Table Wizard.', 'wpdatatables'),
490 ),
491 'step2' => array(
492 'title' => __('Choose this option', 'wpdatatables'),
493 'content' => __('Please select \'Create a simple table from scratch\'.', 'wpdatatables'),
494 ),
495 'step3' => array(
496 'title' => __('Click Next', 'wpdatatables'),
497 'content' => __('Please click the \'Next\' button to continue.', 'wpdatatables'),
498 ),
499 'step4' => array(
500 'title' => __('Welcome to the Simple table wizard!', 'wpdatatables'),
501 'content' => __('Please click \'Continue\' button to move on.', 'wpdatatables'),
502 ),
503 'step5' => array(
504 'title' => __('Choose a name for your table', 'wpdatatables'),
505 'content' => __('After inserting table name, click \'Continue\' to move on.', 'wpdatatables'),
506 ),
507 'step6' => array(
508 'title' => __('Choose the number of columns for your table', 'wpdatatables'),
509 'content' => __('Please choose how many columns it will have. Remember that you can always add or reduce the number of columns later. Click \'Continue\' when you finish.', 'wpdatatables'),
510 ),
511 'step7' => array(
512 'title' => __('Choose the number of rows for your table.', 'wpdatatables'),
513 'content' => __('Please choose how many rows it will have. Remember that you can always add or reduce the number of rows later. Click \'Continue\' when you finish.', 'wpdatatables'),
514 ),
515 'step8' => array(
516 'title' => __('Click on the \'Generate Table\' button', 'wpdatatables'),
517 'content' => __('When you click on the button, the empty table will be ready for you. ', 'wpdatatables'),
518 ),
519 'step9' => array(
520 'title' => $hourglassIMG .__('We are generating the table...', 'wpdatatables'),
521 'content' => __('Please, when you see the table, click \'Continue\' to move on.', 'wpdatatables'),
522 ),
523 'step10' => array(
524 'title' => __('Nice job! You just configured your table and it is ready to fill it with data.', 'wpdatatables') . $raisedHandsIMG,
525 'content' => __('Now we will guide you on how to insert data and check table layout throw Simple table editor, table toolbar and table preview. Please click \'Continue\' to move on.', 'wpdatatables'),
526 ),
527 'step11' => array(
528 'title' => __('This is Simple table editor', 'wpdatatables'),
529 'content' => __('Here you can populate your table with data. <br><br>You can move around the cells using keyboard arrows and the Tab button. <br><br>Rearrange columns or rows by drag and drop column or row headers. Easily resize column width and row height by dragging the right corner of the column header, or the bottom line of the row header. Click \'Continue\' to move on.', 'wpdatatables'),
530 ),
531 'step12' => array(
532 'title' => __('Check out the Simple table toolbar', 'wpdatatables'),
533 'content' => __('Here you can style and insert custom data for each cell or range of cells. You can add or delete columns and rows, merge cells, customize sections by colors, background, alignment, insert custom links, media, shortcodes, star ratings or custom HTML code.', 'wpdatatables'),
534 ),
535 'step13' => array(
536 'title' => __('Responsive table views', 'wpdatatables'),
537 'content' => __('You can switch between Desktop, Tablet or Mobile devices by clicking on the tab that you need, so you can make sure your table looks excellent across all devices. ', 'wpdatatables'),
538 ),
539 'step14' => array(
540 'title' => __('Real-time preview', 'wpdatatables'),
541 'content' => __('Here you will see how your table will look like on the page. Please click \'Continue\' to move on.', 'wpdatatables'),
542 ),
543 'step15' => array(
544 'title' =>$partyTitleIMG . __('Congrats! Your table is ready.', 'wpdatatables'),
545 'content' => __('Now you can copy the shortcode for this table, and check out how it looks on your website when you paste it to a post or page. You can always come back and edit the table as you like.', 'wpdatatables'),
546 )
547 ),
548 'tour1' => array(
549 'step0' => array(
550 'title' => $guideTeacherIMG . __('Welcome to the tutorial!', 'wpdatatables'),
551 'content' => __('Hello ', 'wpdatatables') . $waveIMG . __(', in this tutorial we will show you how to create a wpDataTable linked to an existing data source. "Linked" in this context means that if you create a table, for example, based on an Excel file, it will read the data from this file every time it loads, making sure all table values changes are instantly reflected in the table.', 'wpdatatables'),
552 ),
553 'step1' => array(
554 'title' => __('Let\'s create a new wpDataTable!', 'wpdatatables'),
555 'content' => __('Click on \'Create a Table\' to access the wpDataTables Table Wizard.', 'wpdatatables'),
556 ),
557 'step2' => array(
558 'title' => __('Choose this option.', 'wpdatatables'),
559 'content' => __('Please select \'Create a table linked to an existing data source\'.', 'wpdatatables'),
560 ),
561 'step3' => array(
562 'title' => __('Click Next', 'wpdatatables'),
563 'content' => __('Please click the \'Next\' button to continue.', 'wpdatatables'),
564 ),
565 'step4' => array(
566 'title' => __('Input data source type', 'wpdatatables'),
567 'content' => __('Please select a data source type that you need.', 'wpdatatables'),
568 ),
569 'step5' => array(
570 'title' => __('Select Data source type', 'wpdatatables'),
571 'content' => __('Please choose the data source that you need ( Excel, CSV, JSON, XML or PHP array) and then click \'Continue\' button.<br><br>(SQL and Google Spreadsheet are available in Premium version)', 'wpdatatables'),
572 ),
573 'step6' => array(
574 'title' => __('Input file path or URL', 'wpdatatables'),
575 'content' => __('Upload your file or provide the full URL here. When you finish click \'Continue\' button.', 'wpdatatables'),
576 ),
577 'step7' => array(
578 'title' => __('Click Save Changes', 'wpdatatables'),
579 'content' => __('Please click on the \'Save Changes\' button to create a table.<br><br> If you get an error message after button click and you are not able to solve it, please contact us on our support platform and provide us this data source that you use for creating this table and copy error message as well and click Skip tutorial.', 'wpdatatables'),
580 ),
581 'step8' => array(
582 'title' => $hourglassIMG .__('The table is creating...', 'wpdatatables'),
583 'content' => __('Now the table is creating. Wait until you see it in the background and then click \'Continue\'.', 'wpdatatables'),
584 ),
585 'step9' => array(
586 'title' => $partyTitleIMG . __('Nice job! You just created your first wpDataTable!', 'wpdatatables') . $raisedHandsIMG,
587 'content' => __('Now you can copy the shortcode for this table, and check out how it looks on your website when you paste it to a post or page.', 'wpdatatables'),
588 )
589 ),
590 'tour2' => array(
591 'step0' => array(
592 'title' => $guideTeacherIMG . __('Welcome to the tutorial!', 'wpdatatables'),
593 'content' => __('Hello ', 'wpdatatables') . $waveIMG . __(', in this tutorial we will show you how to create a chart in wpDataTables plugin.', 'wpdatatables'),
594 ),
595 'step1' => array(
596 'title' => __('Let\'s create a new wpDataTables Chart!', 'wpdatatables'),
597 'content' => __('Click on \'Create a Chart\' to access the wpDataTables Chart Wizard.', 'wpdatatables'),
598 ),
599 'step2' => array(
600 'title' => $chartIMG . __('Welcome to the Chart Wizard!', 'wpdatatables'),
601 'content' => __('You are at the first step now; we will introduce you the wpDataTables Chart Wizard section by section.<br><br> Click \'Continue\' button to move forward.', 'wpdatatables'),
602 ),
603 'step3' => array(
604 'title' => __('Follow the steps in the Chart Wizard', 'wpdatatables'),
605 'content' => __('By following these steps, you will finish building your chart in the Chart Wizard. The current step will always be highlighted in blue.<br><br> Click \'Continue\' button to move forward.', 'wpdatatables'),
606 ),
607 'step4' => array(
608 'title' => __('Choose a name for your Chart', 'wpdatatables'),
609 'content' => __('Click \'Continue\' button when you’re ready to move forward.', 'wpdatatables'),
610 ),
611 'step5' => array(
612 'title' => __('In wpDataTables you can find several charts render engines.', 'wpdatatables'),
613 'content' => __('Click on the dropdown, and you will see several options that you can choose from.(Google charts nad Chart.js are only available) <br><br>To continue, click on the dropdown.', 'wpdatatables'),
614 ),
615 'step6' => array(
616 'title' => __('Choose chart engine.', 'wpdatatables'),
617 'content' => __('By clicking on chart engine options, you will choose the engine that will render your chart.<br><br> When you finish, please click \'Continue\' button to move forward.', 'wpdatatables'),
618 ),
619 'step7' => array(
620 'title' => __('Different charts types. ', 'wpdatatables'),
621 'content' => __('Here you can choose a chart type. Please, click on the chart type that you prefer.<br><br> When you finish, please click \'Continue\' button to move forward.', 'wpdatatables'),
622 ),
623 'step10' => array(
624 'title' => __('The first step is finished!', 'wpdatatables'),
625 'content' => __('Let\'s move on. Please, click \'Next\' to continue.', 'wpdatatables'),
626 ),
627 'step11' => array(
628 'title' => __('Now you need to choose a wpDataTable based on which we will build a chart for you', 'wpdatatables'),
629 'content' => __('Click on the dropdown, and all your tables will be listed. The columns of the table that you choose will be used for creating the chart.<br><br>If you didn\'t create a wpDataTable yet, then please click on the \'Skip Tutorial\' button and create wpDataTable that would contain the data to visualize first.', 'wpdatatables'),
630 ),
631 'step12' => array(
632 'title' => __('Pick your wpDataTable', 'wpdatatables'),
633 'content' => __('Pick a wpDataTable from which you want to render a chart and when you finish, please click \'Continue\' to move on.', 'wpdatatables'),
634 ),
635 'step13' => array(
636 'title' => __('The second step is finished!', 'wpdatatables') . $raisedHandsIMG,
637 'content' => __('Let\'s see what is coming up next. <br><br> Please, click \'Next\' to continue.', 'wpdatatables'),
638 ),
639 'step14' => array(
640 'title' => __('Just a heads up!', 'wpdatatables'),
641 'content' => __('Here you will choose from which columns you will create a chart.<br><br> Please click \'Continue\' button to move forward.', 'wpdatatables'),
642 ),
643 'step15' => array(
644 'title' => __('Meet the wpDataTable Column Blocks', 'wpdatatables'),
645 'content' => __('Here you will choose columns you want to use in the chart. Drag and drop it, or click on the arrow to move the desired column to the \'Columns used in the chart\' section.<br><br> When you finish please, click \'Continue.\'', 'wpdatatables'),
646 ),
647 'step16' => array(
648 'title' => __('Well done!', 'wpdatatables') . $raisedHandsIMG,
649 'content' => __('Just two more steps to go. Please click \'Next\' to continue.', 'wpdatatables'),
650 ),
651 'step17' => array(
652 'title' => __('Chart settings and chart preview.', 'wpdatatables'),
653 'content' => __('Here you can adjust chart settings, different parameters are grouped in section; adjusting the parameters will be reflected in the preview of your chart in real-time on the right-hand side.<br><br> Please click \'Continue\' button to move forward.', 'wpdatatables'),
654 ),
655 'step18' => array(
656 'title' => __('In this sidebar, you can find the chart settings section.', 'wpdatatables'),
657 'content' => __('By clicking on each section, you can set your desired parameters per section.<br><br> Please click \'Continue\' button to move on.', 'wpdatatables'),
658 ),
659 'step19' => array(
660 'title' => __('Here are the available chart options', 'wpdatatables'),
661 'content' => __('Set different chart options for the chosen section to get your desired chart look.<br><br> Please click \'Continue\' button to move on.', 'wpdatatables'),
662 ),
663 'step27' => array(
664 'title' => __('How your chart will look like on the page of your website', 'wpdatatables'),
665 'content' => __('Here you can see a preview of your chart based on the settings you have chosen.<br><br> Please click \'Continue\' button to move on.', 'wpdatatables'),
666 ),
667 'step28' => array(
668 'title' => __('You can save your chart now', 'wpdatatables'),
669 'content' => __('If you are satisfied with your chart appearance, click on the \'Save chart\' button and all your settings for this chart will be saved in the database.', 'wpdatatables'),
670 ),
671 'step29' => array(
672 'title' => $partyTitleIMG . __('Congrats! Your first chart is ready!', 'wpdatatables') . $raisedHandsIMG,
673 'content' => __('Now you can copy the shortcode for this chart and paste it in any WP post or page. <br><br>You may now finish this tutorial. ', 'wpdatatables'),
674 )
675 )
676 );
677 }
678
679 /**
680 * Helper function that define default value
681 * @param $possible
682 * @param $index
683 * @param string $default
684 * @return string
685 */
686 public static function defineDefaultValue($possible, $index, $default = '')
687 {
688 return isset($possible[$index]) ? $possible[$index] : $default;
689 }
690
691 /**
692 * Helper function that extract column headers in array
693 * @param $rawDataArr
694 * @return array
695 * @throws WDTException
696 */
697 public static function extractHeaders($rawDataArr)
698 {
699 reset($rawDataArr);
700 if (!is_array($rawDataArr[key($rawDataArr)])) {
701 throw new WDTException('Please provide a valid 2-dimensional array.');
702 }
703 return array_keys($rawDataArr[key($rawDataArr)]);
704 }
705
706 /**
707 * Helper function that detect columns data type
708 * @param $rawDataArr
709 * @param $headerArr
710 * @return array
711 * @throws WDTException
712 */
713 public static function detectColumnDataTypes($rawDataArr, $headerArr)
714 {
715 $autodetectData = array();
716 $autodetectRowsCount = (10 > count($rawDataArr)) ? count($rawDataArr) - 1 : 9;
717 $wdtColumnTypes = array();
718 for ($i = 0; $i <= $autodetectRowsCount; $i++) {
719 foreach ($headerArr as $key) {
720 $cur_val = current($rawDataArr);
721 if (!is_array($cur_val[$key])) {
722 $autodetectData[$key][] = $cur_val[$key];
723 } else {
724 if (array_key_exists('value', $cur_val[$key])) {
725 $autodetectData[$key][] = $cur_val[$key]['value'];
726 } else {
727 throw new WDTException('Please provide a correct format for the cell.');
728 }
729 }
730 }
731 next($rawDataArr);
732 }
733 foreach ($headerArr as $key) {
734 $wdtColumnTypes[$key] = self::wdtDetectColumnType($autodetectData[$key]);
735 }
736 return $wdtColumnTypes;
737 }
738
739 /**
740 * Helper function that convert XML to Array
741 * @param $xml SimpleXMLElement
742 * @param bool $root
743 * @return array|string
744 */
745 public static function convertXMLtoArr($xml, $root = true)
746 {
747 if (!$xml->children()) {
748 return (string)$xml;
749 }
750
751 $array = array();
752 foreach ($xml->children() as $element => $node) {
753 $totalElement = count($xml->{$element});
754
755 // Has attributes
756 if ($attributes = $node->attributes()) {
757 $data = array(
758 'attributes' => array(),
759 'value' => (count($node) > 0) ? self::xmlToArray($node, false) : (string)$node
760 );
761
762 foreach ($attributes as $attr => $value) {
763 $data['attributes'][$attr] = (string)$value;
764 }
765
766 $array[] = $data['attributes'];
767 } else {
768 if ($totalElement > 1) {
769 $array[][] = self::convertXMLtoArr($node, false);
770 } else {
771 $array[$element] = self::convertXMLtoArr($node, false);
772 }
773 }
774 }
775
776 return $array;
777 }
778
779 /**
780 * Helper function that check if the array is associative
781 * @param $arr
782 * @return bool
783 */
784 public static function isArrayAssoc($arr)
785 {
786 return array_keys($arr) !== range(0, count($arr) - 1);
787 }
788
789 /**
790 * Helper function that detect single column type
791 * @param $values
792 * @return string
793 */
794 private static function wdtDetectColumnType($values)
795 {
796 if (self::_detect($values, 'WDTTools::wdtIsIP')) {
797 return 'string';
798 }
799 if (self::_detect($values, 'WDTTools::wdtIsInteger')) {
800 return 'int';
801 }
802 if (self::_detect($values, 'preg_match', WDT_TIME_12H_REGEX) || self::_detect($values, 'preg_match', WDT_TIME_24H_REGEX)) {
803 return 'time';
804 }
805 if (self::_detect($values, 'WDTTools::wdtIsDateTime')) {
806 return 'datetime';
807 }
808 if (self::_detect($values, 'WDTTools::wdtIsDate')) {
809 return 'date';
810 }
811 if (self::_detect($values, 'preg_match', WDT_CURRENCY_REGEX) || self::wdtIsFloat($values)) {
812 return 'float';
813 }
814 if (self::_detect($values, 'preg_match', WDT_EMAIL_REGEX)) {
815 return 'email';
816 }
817 if (self::_detect($values, 'preg_match', WDT_URL_REGEX)) {
818 return 'link';
819 }
820 return 'string';
821 }
822
823
824 /** @noinspection PhpUnusedPrivateMethodInspection
825 * Function that checks if the passed value is integer
826 * wdtIsInteger(23); //bool(true)
827 * wdtIsInteger("23"); //bool(true)
828 * @param $input
829 * @return bool
830 */
831 private static function wdtIsInteger($input)
832 {
833 return ctype_digit((string)$input);
834 }
835
836 /**
837 * Function that checks if the passed values are IP's
838 * @param $input
839 * @return bool
840 */
841 private static function wdtIsIP($input)
842 {
843 return (bool)filter_var($input, FILTER_VALIDATE_IP);
844 }
845
846 /**
847 * Function that checks if the passed values are float
848 * @param $values
849 * @return bool
850 */
851 private static function wdtIsFloat($values)
852 {
853 $count = 0;
854 for ($i = 0; $i < count($values); $i++) {
855 if (is_null($values[$i])) continue;
856 if (is_numeric(str_replace(array('.', ','), '', $values[$i]))) {
857 $count++;
858 }
859 }
860
861 return $count == count($values);
862 }
863
864
865 /** @noinspection PhpUnusedPrivateMethodInspection
866 * Function that checks if the passed value is date
867 * @param $input
868 * @return bool
869 */
870 private static function wdtIsDate($input)
871 {
872 return strlen($input) > 5 &&
873 (
874 strtotime($input) ||
875 strtotime(str_replace('/', '-', $input)) ||
876 strtotime(str_replace(array('.', '-'), '/', $input))
877 );
878 }
879
880 /** @noinspection PhpUnusedPrivateMethodInspection
881 * Function that checks if the passed values is datetime
882 * @param $input
883 * @return bool
884 */
885 private static function wdtIsDateTime($input)
886 {
887 return (
888 strtotime($input) ||
889 strtotime(str_replace('/', '-', $input)) ||
890 strtotime(str_replace(array('.', '-'), '/', $input))
891 ) &&
892 (
893 call_user_func('preg_match', WDT_TIME_12H_REGEX, substr($input, strpos($input, ':') - 2, 5)) ||
894 call_user_func('preg_match', WDT_TIME_24H_REGEX, substr($input, strpos($input, ':') - 2, 5))
895
896 );
897 }
898
899 /**
900 * @param $valuesArray
901 * @param $checkFunction
902 * @param string $regularExpression
903 * @return bool
904 * @throws WDTException
905 */
906 private static function _detect($valuesArray, $checkFunction, $regularExpression = '')
907 {
908 if (!is_callable($checkFunction)) {
909 throw new WDTException('Please provide a valid type detection function for wpDataTables');
910 }
911 $count = 0;
912 for ($i = 0; $i < count($valuesArray); $i++) {
913 if ($regularExpression != '') {
914 if ($valuesArray[$i] == null || call_user_func($checkFunction, $regularExpression, $valuesArray[$i])) {
915 $count++;
916 } else {
917 return false;
918 }
919 } else {
920 if ($valuesArray[$i] == null || call_user_func($checkFunction, $valuesArray[$i])) {
921 $count++;
922 } else {
923 return false;
924 }
925 }
926 }
927 if ($count == count($valuesArray)) {
928 return true;
929 }
930 return false;
931 }
932
933 /**
934 * Helper function that converts PHP to Moment Date Format
935 * @param $dateFormat
936 * @return string
937 */
938 public static function convertPhpToMomentDateFormat($dateFormat)
939 {
940 $replacements = array(
941 'd' => 'DD',
942 'D' => 'ddd',
943 'j' => 'D',
944 'l' => 'dddd',
945 'N' => 'E',
946 'S' => 'o',
947 'w' => 'e',
948 'z' => 'DDD',
949 'W' => 'W',
950 'F' => 'MMMM',
951 'm' => 'MM',
952 'M' => 'MMM',
953 'n' => 'M',
954 't' => '', // no equivalent
955 'L' => '', // no equivalent
956 'o' => 'YYYY',
957 'Y' => 'YYYY',
958 'y' => 'YY',
959 'a' => 'a',
960 'A' => 'A',
961 'B' => '', // no equivalent
962 'g' => 'h',
963 'G' => 'H',
964 'h' => 'hh',
965 'H' => 'HH',
966 'i' => 'mm',
967 's' => 'ss',
968 'u' => 'SSS',
969 'e' => 'zz', // deprecated since version 1.6.0 of moment.js
970 'I' => '', // no equivalent
971 'O' => '', // no equivalent
972 'P' => '', // no equivalent
973 'T' => '', // no equivalent
974 'Z' => '', // no equivalent
975 'c' => '', // no equivalent
976 'r' => '', // no equivalent
977 'U' => 'X',
978 );
979
980 return strtr($dateFormat, $replacements);
981 }
982
983 /**
984 * Helper method to wrap values in quotes for DB
985 */
986 public static function wrapQuotes($value)
987 {
988 $valueQuote = get_option('wdtUseSeparateCon') ? "'" : '';
989 return $valueQuote . $value . $valueQuote;
990 }
991
992 /**
993 * Helper method to detect the headers that are present in formula
994 * @param $formula
995 * @param $headers
996 * @return array
997 */
998 public static function getColHeadersInFormula($formula, $headers)
999 {
1000 $headersInFormula = array();
1001 foreach ($headers as $header) {
1002 if (strpos($formula, $header) !== false) {
1003 $headersInFormula[] = $header;
1004 }
1005 }
1006 return $headersInFormula;
1007 }
1008
1009 /**
1010 * Helper function which converts WP upload URL to Path
1011 * @param $uploadUrl
1012 * @return mixed
1013 */
1014 public static function urlToPath($uploadUrl)
1015 {
1016 $uploadsDir = wp_upload_dir();
1017 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
1018 $uploadPath = str_replace($uploadsDir['baseurl'], str_replace('\\', '/', $uploadsDir['basedir']), $uploadUrl);
1019 } else {
1020 $uploadPath = str_replace($uploadsDir['baseurl'], $uploadsDir['basedir'], $uploadUrl);
1021 }
1022 return $uploadPath;
1023 }
1024
1025 /**
1026 * Helper function which converts upload path to URL
1027 * @param $uploadPath
1028 * @return mixed
1029 */
1030 public static function pathToUrl($uploadPath)
1031 {
1032 $uploadsDir = wp_upload_dir();
1033 if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
1034 $uploadUrl = str_replace(str_replace('\\', '/', $uploadsDir['basedir']), $uploadsDir['baseurl'], $uploadPath);
1035 } else {
1036 $uploadUrl = str_replace($uploadsDir['basedir'], $uploadsDir['baseurl'], $uploadPath);
1037 }
1038 return $uploadUrl;
1039 }
1040
1041
1042 /**
1043 * Helper function that convert hex color to rgba
1044 * @param $color
1045 * @param bool $opacity
1046 * @return string
1047 */
1048 public static function hex2rgba($color, $opacity = false)
1049 {
1050
1051 $default = 'rgb(0,0,0)';
1052
1053 //Return default if no color provided
1054 if (empty($color))
1055 return $default;
1056
1057 //Sanitize $color if "#" is provided
1058 if ($color[0] == '#') {
1059 $color = substr($color, 1);
1060 }
1061
1062 //Check if color has 6 or 3 characters and get values
1063 if (strlen($color) == 6) {
1064 $hex = array($color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5]);
1065 } elseif (strlen($color) == 3) {
1066 $hex = array($color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2]);
1067 } else {
1068 return $default;
1069 }
1070
1071 //Convert hexadec to rgb
1072 $rgb = array_map('hexdec', $hex);
1073
1074 //Check if opacity is set(rgba or rgb)
1075 if ($opacity) {
1076 if (abs($opacity) > 1)
1077 $opacity = 1.0;
1078 $output = 'rgba(' . implode(",", $rgb) . ',' . $opacity . ')';
1079 } else {
1080 $output = 'rgb(' . implode(",", $rgb) . ')';
1081 }
1082
1083 //Return rgb(a) color string
1084 return $output;
1085 }
1086
1087 /**
1088 * Sanitizes the cell string and wraps it with quotes
1089 * @param $string
1090 *
1091 * @return string
1092 */
1093 public static function prepareStringCell($string)
1094 {
1095
1096 if (self::isHtml($string)) {
1097 $string = self::stripJsAttributes($string);
1098 }
1099 $string = self::wrapQuotes($string);
1100 return $string;
1101 }
1102
1103 /**
1104 * Check if passed string is HTML element
1105 * @param $string
1106 * @return bool
1107 */
1108 public static function isHtml($string)
1109 {
1110 return preg_match("/<[^<]+>/", $string, $m) != 0;
1111 }
1112
1113 /**
1114 * Function that strip JS attributes to prevent XSS attacks
1115 * @param $htmlString
1116 * @return bool|string
1117 */
1118 public static function stripJsAttributes($htmlString)
1119 {
1120 $htmlString = stripcslashes($htmlString);
1121 $htmlString = '<div>' . $htmlString . '</div>';
1122 if ( function_exists( 'mb_convert_encoding' ) ) {
1123 $domd = new DOMDocument();
1124 $domd_status = @$domd->loadHTML(mb_convert_encoding($htmlString, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR | LIBXML_NOWARNING);
1125 if ($domd_status) {
1126 foreach ($domd->getElementsByTagName('*') as $node) {
1127 $remove = array();
1128 foreach ($node->attributes as $attributeName => $attribute) {
1129 if (substr($attributeName, 0, 2) == 'on') {
1130 $remove[] = $attributeName;
1131 }
1132 }
1133 foreach ($remove as $i) {
1134 $node->removeAttribute($i);
1135 }
1136 }
1137 return substr($domd->saveHTML($domd->documentElement), 5, -6);
1138 }
1139 }
1140 return $htmlString;
1141 }
1142
1143 /**
1144 * Enqueue JS and CSS UI Kit files
1145 */
1146 public static function wdtUIKitEnqueue()
1147 {
1148 wp_enqueue_style('wdt-bootstrap', WDT_CSS_PATH . 'bootstrap/wpdatatables-bootstrap.min.css');
1149 wp_enqueue_style('wdt-bootstrap-select', WDT_CSS_PATH . 'bootstrap/bootstrap-select/bootstrap-select.min.css');
1150 wp_enqueue_style('wdt-bootstrap-tagsinput', WDT_CSS_PATH . 'bootstrap/bootstrap-tagsinput/bootstrap-tagsinput.css');
1151 wp_enqueue_style('wdt-bootstrap-datetimepicker', WDT_CSS_PATH . 'bootstrap/bootstrap-datetimepicker/bootstrap-datetimepicker.min.css');
1152 wp_enqueue_style('wdt-wp-bootstrap-datetimepicker', WDT_CSS_PATH . 'bootstrap/bootstrap-datetimepicker/wdt-bootstrap-datetimepicker.css');
1153 wp_enqueue_style('wdt-animate', WDT_CSS_PATH . 'animate/animate.min.css');
1154 wp_enqueue_style('wdt-uikit', WDT_CSS_PATH . 'uikit/uikit.css');
1155 wp_enqueue_style('wdt-wpdt-icons', WDT_ROOT_URL . 'assets/css/style.min.css', array(), WDT_CURRENT_VERSION);
1156 if (is_admin()) {
1157 wp_enqueue_style('wdt-bootstrap-tour-css', WDT_CSS_PATH . 'bootstrap/bootstrap-tour/bootstrap-tour.css', array(), WDT_CURRENT_VERSION);
1158 wp_enqueue_style('wdt-bootstrap-tour-guide-css', WDT_CSS_PATH . 'bootstrap/bootstrap-tour/bootstrap-tour-guide.css', array(), WDT_CURRENT_VERSION);
1159 }
1160
1161 if (!is_admin() && get_option('wdtIncludeBootstrap') == 1) {
1162 wp_enqueue_script('wdt-bootstrap', WDT_JS_PATH . 'bootstrap/bootstrap.min.js', array('jquery'), WDT_CURRENT_VERSION, true);
1163 } else if (is_admin() && get_option('wdtIncludeBootstrapBackEnd') == 1) {
1164 wp_enqueue_script('wdt-bootstrap', WDT_JS_PATH . 'bootstrap/bootstrap.min.js', array('jquery'), WDT_CURRENT_VERSION, true);
1165 } else {
1166 wp_enqueue_script('wdt-bootstrap', WDT_JS_PATH . 'bootstrap/noconf.bootstrap.min.js', array('jquery'), WDT_CURRENT_VERSION, true);
1167 }
1168 if (is_admin()) {
1169 wp_enqueue_script('wdt-bootstrap-tour', WDT_JS_PATH . 'bootstrap/bootstrap-tour/bootstrap-tour.js', array('jquery'), WDT_CURRENT_VERSION, true);
1170 wp_enqueue_script('wdt-bootstrap-tour-guide', WDT_JS_PATH . 'bootstrap/bootstrap-tour/bootstrap-tour-guide.js', array('jquery'), WDT_CURRENT_VERSION, true);
1171 wp_localize_script('wdt-bootstrap-tour-guide', 'wpdtTutorialStrings', WDTTools::getTutorialsTranslationStrings());
1172 }
1173 wp_enqueue_script('wdt-bootstrap-tagsinput', WDT_JS_PATH . 'bootstrap/bootstrap-tagsinput/bootstrap-tagsinput.js', array(), false, true);
1174 wp_enqueue_script('wdt-moment', WDT_JS_PATH . 'moment/moment.js', array(), false, true);
1175 wp_enqueue_script('wdt-bootstrap-datetimepicker', WDT_JS_PATH . 'bootstrap/bootstrap-datetimepicker/bootstrap-datetimepicker.min.js', array(), false, true);
1176 wp_enqueue_script('wdt-bootstrap-growl', WDT_JS_PATH . 'bootstrap/bootstrap-growl/bootstrap-growl.min.js', array(), false, true);
1177 wp_enqueue_script('wdt-bootstrap-select', WDT_JS_PATH . 'bootstrap/bootstrap-select/bootstrap-select.min.js', array('jquery', 'wdt-bootstrap'), WDT_CURRENT_VERSION, true);
1178 }
1179
1180 /**
1181 * Helper method to add PHP vars to JS vars
1182 * @param $varName
1183 * @param $phpVar
1184 */
1185 public static function exportJSVar($varName, $phpVar)
1186 {
1187 self::$jsVars[$varName] = $phpVar;
1188 }
1189
1190 /**
1191 * Helper method to print PHP vars to JS vars
1192 */
1193 public static function printJSVars()
1194 {
1195 if (!empty(self::$jsVars)) {
1196 $jsBlock = '<script type="text/javascript">';
1197 foreach (self::$jsVars as $varName => $jsVar) {
1198 $jsBlock .= "var {$varName} = " . json_encode($jsVar) . ";";
1199 }
1200 $jsBlock .= '</script>';
1201 echo $jsBlock;
1202 }
1203 }
1204
1205 /**
1206 * Helper method that converts provided String to Unix Timestamp
1207 * based on provided date format
1208 * @param $dateString
1209 * @param $dateFormat
1210 * @return false|int
1211 */
1212 public static function wdtConvertStringToUnixTimestamp($dateString, $dateFormat)
1213 {
1214 if ($dateString == '') return null;
1215 if (!$dateFormat) $dateFormat = get_option('wdtDateFormat');
1216
1217 if (null !== $dateFormat && substr($dateFormat, 0,5) === 'd/m/Y') {
1218 $returnDate = strtotime(str_replace('/', '-', $dateString));
1219 } else if (null !== $dateFormat && in_array($dateFormat, ['m.d.Y', 'm-d-Y', 'm-d-y','d.m.y','Y.m.d','d-m-Y'])) {
1220 $returnDate = strtotime(str_replace(['.', '-'], '/', $dateString));
1221 } else if (null !== $dateFormat && $dateFormat == 'm/Y') {
1222 $dateObject = DateTime::createFromFormat($dateFormat, $dateString);
1223 if (!$dateObject) return strtotime($dateString);
1224 $returnDate = $dateObject->getTimestamp();
1225 } else {
1226 $returnDate = strtotime($dateString);
1227 }
1228
1229 return $returnDate ?: '';
1230 }
1231
1232 /**
1233 * Show error message
1234 * @param $errorMessage
1235 * @return string
1236 */
1237 public static function wdtShowError($errorMessage)
1238 {
1239 self::wdtUIKitEnqueue();
1240 ob_start();
1241 include WDT_ROOT_PATH . 'templates/common/error.inc.php';
1242 $errorBlock = ob_get_contents();
1243 ob_end_clean();
1244 return $errorBlock;
1245 }
1246
1247 /**
1248 * Helper function to generate unique MySQL column headers
1249 * @param $header
1250 * @param $existing_headers
1251 * @return mixed|string
1252 */
1253 public static function generateMySQLColumnName($header, $existing_headers)
1254 {
1255 // Prepare the column MySQL title
1256 $column_header = self::slugify($header);
1257
1258 // Add index until column header becomes unique
1259 if (in_array($column_header, $existing_headers)) {
1260 $index = 0;
1261 do {
1262 $index++;
1263 $try_column_header = $column_header . $index;
1264 } while (in_array($try_column_header, $existing_headers));
1265 $column_header = $try_column_header;
1266 }
1267
1268 return $column_header;
1269 }
1270
1271 /**
1272 * Helper function to translate special UTF-8 to latin for MySQL
1273 * @param $text
1274 * @return mixed|string
1275 */
1276 public static function slugify($text)
1277 {
1278 // replace non letter or digits by _
1279 $text = preg_replace('#[^\\pL\d]+#u', '_', $text);
1280
1281 // trim
1282 $text = trim($text, '_');
1283
1284 // transliterate
1285 if (function_exists('iconv')) {
1286 $text = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text);
1287 }
1288
1289 // lowercase
1290 $text = strtolower($text);
1291
1292 // remove unwanted characters
1293 $text = preg_replace('#[^-\w]+#', '', $text);
1294
1295 // WP sanitize
1296 $text = str_replace(array('-', '_'), '', sanitize_title($text));
1297
1298 if (empty($text) || is_numeric($text)) {
1299 return 'wdtcolumn';
1300 }
1301
1302 return $text;
1303 }
1304
1305 /**
1306 * Get table count from database
1307 *
1308 * @param $filter
1309 * @return null|string
1310 */
1311 public static function getTablesCount($filter)
1312 {
1313 global $wpdb;
1314 $filter === 'table' ? $tableFromDB = 'wpdatatables' : $tableFromDB = 'wpdatacharts';
1315 $query = "SELECT COUNT(*) FROM {$wpdb->prefix}$tableFromDB";
1316 return (int)$wpdb->get_var($query);
1317 }
1318
1319 /**
1320 * Get data for last insert table from database
1321 *
1322 * @param $filter
1323 * @return stdClass
1324 */
1325 public static function getLastTableData($filter)
1326 {
1327 global $wpdb;
1328 $filter === 'table' ? $tableFromDB = 'wpdatatables' : $tableFromDB = 'wpdatacharts';
1329 $query = "SELECT MAX(id) FROM {$wpdb->prefix}$tableFromDB";
1330 $lastID = $wpdb->get_var($query);
1331 $chartQuery = $wpdb->prepare(
1332 "SELECT *
1333 FROM " . $wpdb->prefix . "wpdatacharts
1334 WHERE id = %d",
1335 $lastID
1336 );
1337
1338 if ($filter === 'table') {
1339 return WDTConfigController::loadTableFromDB($lastID);
1340 } else if ($filter === 'chart') {
1341 return $wpdb->get_row($chartQuery);
1342 }
1343
1344 }
1345
1346 /**
1347 * Convert Table type for readable content
1348 *
1349 * @param $tableType
1350 * @return string
1351 */
1352 public static function getConvertedTableType($tableType)
1353 {
1354 switch ($tableType) {
1355 case 'xls':
1356 return 'Excel';
1357 break;
1358 case 'csv':
1359 return 'CSV';
1360 break;
1361 case 'xml':
1362 return 'XML';
1363 break;
1364 case 'json':
1365 return 'JSON';
1366 break;
1367 case 'nested_json':
1368 return 'Nested JSON';
1369 break;
1370 case 'serialized':
1371 return 'Serialized PHP array';
1372 break;
1373 case 'ivyforms':
1374 if (!class_exists('IvyForms\\Services\\API\\IvyFormsAPI')) {
1375 return 'Unknown';
1376 }
1377 return 'IvyForms';
1378 default:
1379 if (in_array($tableType, WPDataTable::$allowedTableTypes)) {
1380 return ucfirst($tableType);
1381 }
1382 return 'Unknown';
1383 break;
1384 }
1385
1386 }
1387 }
1388
1389 add_action('admin_footer', array('WDTTools', 'printJSVars'), 100);
1390