PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.5.1
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.5.1
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 3.10.4 All 148 releases
visualizer / classes / Visualizer / Gutenberg / Block.php

Block.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.5.1, at classes/Visualizer/Gutenberg/Block.php

826 lines 25.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Copyright 2018 ThemeIsle (email : friends@themeisle.com) |
4 // +----------------------------------------------------------------------+
5 // | This program is free software; you can redistribute it and/or modify |
6 // | it under the terms of the GNU General Public License, version 2, as |
7 // | published by the Free Software Foundation. |
8 // | |
9 // | This program is distributed in the hope that it will be useful, |
10 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 // | GNU General Public License for more details. |
13 // | |
14 // | You should have received a copy of the GNU General Public License |
15 // | along with this program; if not, write to the Free Software |
16 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
17 // | MA 02110-1301 USA |
18 // +----------------------------------------------------------------------+
19 // | Author: Hardeep Asrani <hardeep@themeisle.com> |
20 // +----------------------------------------------------------------------+
21 /**
22 * All the Gutenberg block related code.
23 *
24 * @category Visualizer
25 * @package Gutenberg
26 *
27 * @since 3.1.0
28 */
29 class Visualizer_Gutenberg_Block {
30
31 /**
32 * A reference to an instance of this class.
33 *
34 * @var Visualizer_Gutenberg_Block The one Visualizer_Gutenberg_Block instance.
35 */
36 private static $instance;
37
38 /**
39 * Visualizer plugin version.
40 *
41 * @var string $version The current version of the plugin.
42 */
43 protected $version;
44
45 /**
46 * Returns an instance of this class.
47 */
48 public static function get_instance() {
49 if ( null === self::$instance ) {
50 self::$instance = new Visualizer_Gutenberg_Block();
51 }
52 return self::$instance;
53 }
54
55 /**
56 * Initializes the plugin by setting filters and administration functions.
57 */
58 private function __construct() {
59 $this->version = Visualizer_Plugin::VERSION;
60 add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_gutenberg_scripts' ) );
61 add_action( 'init', array( $this, 'register_block_type' ) );
62 add_action( 'rest_api_init', array( $this, 'register_rest_endpoints' ) );
63 add_filter( 'rest_visualizer_query', array( $this, 'add_rest_query_vars' ), 9, 2 );
64 }
65
66 /**
67 * Enqueue front end and editor JavaScript and CSS
68 */
69 public function enqueue_gutenberg_scripts() {
70 global $wp_version;
71
72 $blockPath = VISUALIZER_ABSURL . 'classes/Visualizer/Gutenberg/build/block.js';
73 $handsontableJS = VISUALIZER_ABSURL . 'classes/Visualizer/Gutenberg/build/handsontable.js';
74 $stylePath = VISUALIZER_ABSURL . 'classes/Visualizer/Gutenberg/build/block.css';
75 $handsontableCSS = VISUALIZER_ABSURL . 'classes/Visualizer/Gutenberg/build/handsontable.css';
76
77 if ( VISUALIZER_TEST_JS_CUSTOMIZATION ) {
78 $version = filemtime( VISUALIZER_ABSPATH . '/classes/Visualizer/Gutenberg/build/block.js' );
79 } else {
80 $version = $this->version;
81 }
82
83 // Enqueue the bundled block JS file
84 wp_enqueue_script( 'handsontable', $handsontableJS );
85 wp_enqueue_script( 'visualizer-gutenberg-block', $blockPath, array( 'wp-api', 'handsontable', 'visualizer-datatables', 'moment' ), $version, true );
86
87 $type = 'community';
88
89 if ( Visualizer_Module::is_pro() ) {
90 $type = 'pro';
91 if ( apply_filters( 'visualizer_is_business', false ) ) {
92 $type = 'business';
93 }
94 }
95
96 $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping( null, false );
97
98 $translation_array = array(
99 'isPro' => $type,
100 'proTeaser' => Visualizer_Plugin::PRO_TEASER_URL,
101 'absurl' => VISUALIZER_ABSURL,
102 'charts' => Visualizer_Module_Admin::_getChartTypesLocalized(),
103 'adminPage' => menu_page_url( 'visualizer', false ),
104 'sqlTable' => $table_col_mapping,
105 'chartsPerPage' => defined( 'TI_CYPRESS_TESTING' ) ? 20 : 6,
106 );
107 wp_localize_script( 'visualizer-gutenberg-block', 'visualizerLocalize', $translation_array );
108
109 // Enqueue frontend and editor block styles
110 wp_enqueue_style( 'handsontable', $handsontableCSS );
111 wp_enqueue_style( 'visualizer-gutenberg-block', $stylePath, array( 'visualizer-datatables' ), $version );
112
113 if ( version_compare( $wp_version, '4.9.0', '>' ) ) {
114
115 wp_enqueue_code_editor(
116 array(
117 'type' => 'sql',
118 'codemirror' => array(
119 'autofocus' => true,
120 'lineWrapping' => true,
121 'dragDrop' => false,
122 'matchBrackets' => true,
123 'autoCloseBrackets' => true,
124 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
125 'hintOptions' => array( 'tables' => $table_col_mapping ),
126 ),
127 )
128 );
129 }
130 }
131 /**
132 * Hook server side rendering into render callback
133 */
134 public function register_block_type() {
135 register_block_type(
136 'visualizer/chart', array(
137 'render_callback' => array( $this, 'gutenberg_block_callback' ),
138 'attributes' => array(
139 'id' => array(
140 'type' => 'number',
141 ),
142 'lazy' => array(
143 'type' => 'string',
144 ),
145 ),
146 )
147 );
148 }
149
150 /**
151 * Gutenberg Block Callback Function
152 */
153 public function gutenberg_block_callback( $atts ) {
154 // no id, no fun.
155 if ( ! isset( $atts['id'] ) ) {
156 return '';
157 }
158
159 $atts = shortcode_atts(
160 array(
161 'id' => false,
162 'lazy' => apply_filters( 'visualizer_lazy_by_default', false, $atts['id'] ),
163 // we are deliberating excluding the class attribute from here
164 // as this will be handled by the custom class in Gutenberg
165 ),
166 $atts
167 );
168
169 // no id, no fun.
170 if ( ! $atts['id'] ) {
171 return '';
172 }
173
174 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
175 if ( $atts['lazy'] == -1 || $atts['lazy'] == false ) {
176 $atts['lazy'] = 'no';
177 }
178
179 // we don't want the chart in the editor lazy-loading.
180 if ( is_admin() ) {
181 unset( $atts['lazy'] );
182 }
183
184 $shortcode = '[visualizer';
185 foreach ( $atts as $name => $value ) {
186 $shortcode .= sprintf( ' %s="%s"', $name, $value );
187 }
188 $shortcode .= ']';
189
190 return $shortcode;
191 }
192
193 /**
194 * Hook server side rendering into render callback
195 */
196 public function register_rest_endpoints() {
197 register_rest_field(
198 'visualizer',
199 'chart_data',
200 array(
201 'get_callback' => array( $this, 'get_visualizer_data' ),
202 )
203 );
204
205 register_rest_route(
206 'visualizer/v' . VISUALIZER_REST_VERSION,
207 '/get-query-data',
208 array(
209 'methods' => 'GET',
210 'callback' => array( $this, 'get_query_data' ),
211 'permission_callback' => function () {
212 return current_user_can( 'edit_posts' );
213 },
214 )
215 );
216
217 register_rest_route(
218 'visualizer/v' . VISUALIZER_REST_VERSION,
219 '/get-json-root',
220 array(
221 'methods' => 'GET',
222 'callback' => array( $this, 'get_json_root_data' ),
223 'args' => array(
224 'url' => array(
225 'sanitize_callback' => 'esc_url_raw',
226 ),
227 ),
228 'permission_callback' => function () {
229 return current_user_can( 'edit_posts' );
230 },
231 )
232 );
233
234 register_rest_route(
235 'visualizer/v' . VISUALIZER_REST_VERSION,
236 '/get-json-data',
237 array(
238 'methods' => 'GET',
239 'callback' => array( $this, 'get_json_data' ),
240 'args' => array(
241 'url' => array(
242 'sanitize_callback' => 'esc_url_raw',
243 ),
244 'chart' => array(
245 'sanitize_callback' => 'absint',
246 ),
247 ),
248 'permission_callback' => function () {
249 return current_user_can( 'edit_posts' );
250 },
251 )
252 );
253
254 register_rest_route(
255 'visualizer/v' . VISUALIZER_REST_VERSION,
256 '/set-json-data',
257 array(
258 'methods' => 'GET',
259 'callback' => array( $this, 'set_json_data' ),
260 'args' => array(
261 'url' => array(
262 'sanitize_callback' => 'esc_url_raw',
263 ),
264 ),
265 'permission_callback' => function () {
266 return current_user_can( 'edit_posts' );
267 },
268 )
269 );
270
271 register_rest_route(
272 'visualizer/v' . VISUALIZER_REST_VERSION,
273 '/update-chart',
274 array(
275 'methods' => 'POST',
276 'callback' => array( $this, 'update_chart_data' ),
277 'args' => array(
278 'id' => array(
279 'sanitize_callback' => 'absint',
280 ),
281 ),
282 'permission_callback' => function () {
283 return current_user_can( 'edit_posts' );
284 },
285 )
286 );
287
288 register_rest_route(
289 'visualizer/v' . VISUALIZER_REST_VERSION,
290 '/upload-data',
291 array(
292 'methods' => 'POST',
293 'callback' => array( $this, 'upload_csv_data' ),
294 'args' => array(
295 'url' => array(
296 'sanitize_callback' => 'esc_url_raw',
297 ),
298 ),
299 'permission_callback' => function () {
300 return current_user_can( 'edit_posts' );
301 },
302 )
303 );
304
305 register_rest_route(
306 'visualizer/v' . VISUALIZER_REST_VERSION,
307 '/get-permission-data',
308 array(
309 'methods' => 'GET',
310 'callback' => array( $this, 'get_permission_data' ),
311 'args' => array(
312 'type' => array(
313 'sanitize_callback' => 'sanitize_text_field',
314 ),
315 ),
316 'permission_callback' => function () {
317 return current_user_can( 'edit_posts' );
318 },
319 )
320 );
321 }
322
323 /**
324 * Get Post Meta Fields
325 */
326 public function get_visualizer_data( $post ) {
327 if ( ! current_user_can( 'edit_posts' ) ) {
328 return false;
329 }
330
331 $data = array();
332 $post_id = $post['id'];
333
334 $data['visualizer-chart-type'] = get_post_meta( $post_id, Visualizer_Plugin::CF_CHART_TYPE, true );
335
336 $library = get_post_meta( $post_id, Visualizer_Plugin::CF_CHART_LIBRARY, true );
337 $data['visualizer-chart-library'] = $library;
338
339 $data['visualizer-source'] = get_post_meta( $post_id, Visualizer_Plugin::CF_SOURCE, true );
340
341 $data['visualizer-default-data'] = get_post_meta( $post_id, Visualizer_Plugin::CF_DEFAULT_DATA, true );
342
343 // faetch and update settings
344 $data['visualizer-settings'] = get_post_meta( $post_id, Visualizer_Plugin::CF_SETTINGS, true );
345
346 // handle series filter hooks
347 $data['visualizer-series'] = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $post_id, Visualizer_Plugin::CF_SERIES, true ), $post_id, $data['visualizer-chart-type'] );
348
349 // handle settings filter hooks
350 $data['visualizer-settings'] = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $data['visualizer-settings'], $post_id, $data['visualizer-chart-type'] );
351
352 // handle data filter hooks
353 $data['visualizer-data'] = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( html_entity_decode( get_the_content( $post_id ) ) ), $post_id, $data['visualizer-chart-type'] );
354
355 // we are going to format only for tabular charts, because we are not sure of the effect on others.
356 // this is to solve the case where boolean data shows up as all-ticks on gutenberg.
357 if ( in_array( $data['visualizer-chart-type'], array( 'tabular' ), true ) ) {
358 $data['visualizer-data'] = $this->format_chart_data( $data['visualizer-data'], $data['visualizer-series'] );
359 }
360
361 $data['visualizer-data-exploded'] = '';
362 // handle annotations for google charts
363 if ( 'GoogleCharts' === $library ) {
364 // this will contain the data of both axis.
365 $settings = $data['visualizer-settings'];
366 // this will contain data only of Y axis.
367 $series = $data['visualizer-series'];
368 $annotations = array();
369 if ( isset( $settings['series'] ) ) {
370 foreach ( $settings['series'] as $index => $serie ) {
371 // skip X axis data.
372 if ( $index === 0 ) {
373 continue;
374 }
375 if ( ! empty( $serie['role'] ) ) {
376 // this series is some kind of annotation, so let's collect its index.
377 // the index will be +1 because the X axis value is index 0, which is being ignored.
378 $annotations[ 'role' . ( intval( $index ) + 1 ) ] = $serie['role'];
379
380 if ( isset( $data['visualizer-series'][ intval( $index ) + 1 ] ) ) {
381 $data['visualizer-series'][ intval( $index ) + 1 ]['role'] = $serie['role'];
382 }
383 }
384 }
385 }
386 if ( ! empty( $annotations ) ) {
387 $exploded_data = array();
388 $series_names = array();
389 foreach ( $series as $index => $serie ) {
390 // skip X axis data.
391 if ( $index === 0 ) {
392 continue;
393 }
394 if ( array_key_exists( 'role' . $index, $annotations ) ) {
395 $series_names[] = (object) array( 'role' => $annotations[ 'role' . $index ], 'type' => $serie['type'] );
396 } else {
397 $series_names[] = $serie['label'];
398 }
399 }
400 $exploded_data[] = $series_names;
401
402 foreach ( $data['visualizer-data'] as $datum ) {
403 // skip X axis data.
404 unset( $datum[0] );
405 $exploded_data[] = $datum;
406 }
407 $data['visualizer-data-exploded'] = array( $exploded_data );
408 }
409 }
410
411 $import = get_post_meta( $post_id, Visualizer_Plugin::CF_CHART_URL, true );
412
413 $schedule = get_post_meta( $post_id, Visualizer_Plugin::CF_CHART_SCHEDULE, true );
414
415 $db_schedule = get_post_meta( $post_id, Visualizer_Plugin::CF_DB_SCHEDULE, true );
416
417 $db_query = get_post_meta( $post_id, Visualizer_Plugin::CF_DB_QUERY, true );
418
419 $json_url = get_post_meta( $post_id, Visualizer_Plugin::CF_JSON_URL, true );
420
421 $json_headers = get_post_meta( $post_id, Visualizer_Plugin::CF_JSON_HEADERS, true );
422
423 $json_schedule = get_post_meta( $post_id, Visualizer_Plugin::CF_JSON_SCHEDULE, true );
424
425 $json_root = get_post_meta( $post_id, Visualizer_Plugin::CF_JSON_ROOT, true );
426
427 $json_paging = get_post_meta( $post_id, Visualizer_Plugin::CF_JSON_PAGING, true );
428
429 if ( ! empty( $import ) && ! empty( $schedule ) ) {
430 $data['visualizer-chart-url'] = $import;
431 $data['visualizer-chart-schedule'] = $schedule;
432 }
433
434 if ( ! empty( $db_schedule ) && ! empty( $db_query ) ) {
435 $data['visualizer-db-schedule'] = $db_schedule;
436 $data['visualizer-db-query'] = $db_query;
437 }
438
439 if ( ! empty( $json_url ) ) {
440 $data['visualizer-json-schedule'] = $json_schedule;
441 $data['visualizer-json-url'] = $json_url;
442 $data['visualizer-json-headers'] = $json_headers;
443 $data['visualizer-json-root'] = $json_root;
444
445 if ( Visualizer_Module::is_pro() && ! empty( $json_paging ) ) {
446 $data['visualizer-json-paging'] = $json_paging;
447 }
448 }
449
450 if ( Visualizer_Module::is_pro() ) {
451 $permissions = get_post_meta( $post_id, Visualizer_PRO::CF_PERMISSIONS, true );
452
453 if ( empty( $permissions ) ) {
454 $permissions = array( 'permissions' => array(
455 'read' => 'all',
456 'edit' => 'roles',
457 'edit-specific' => array( 'administrator' ),
458 ),
459 );
460 }
461
462 $data['visualizer-permissions'] = $permissions;
463 }
464
465 return $data;
466 }
467
468 /**
469 * Returns the data for the query.
470 *
471 * @access public
472 */
473 public function get_query_data( $data ) {
474 if ( ! current_user_can( 'edit_posts' ) ) {
475 return false;
476 }
477
478 $source = new Visualizer_Source_Query( stripslashes( $data['query'] ) );
479 $html = $source->fetch( true );
480 $source->fetch( false );
481 $name = $source->getSourceName();
482 $series = $source->getSeries();
483 $data = $source->getRawData();
484 $error = '';
485 if ( empty( $html ) ) {
486 $error = $source->get_error();
487 wp_send_json_error( array( 'msg' => $error ) );
488 }
489 wp_send_json_success( array( 'table' => $html, 'name' => $name, 'series' => $series, 'data' => $data ) );
490 }
491
492 /**
493 * Returns the JSON root.
494 *
495 * @access public
496 */
497 public function get_json_root_data( $data ) {
498 if ( ! current_user_can( 'edit_posts' ) ) {
499 return false;
500 }
501
502 $source = new Visualizer_Source_Json( $data );
503
504 $roots = $source->fetchRoots();
505 if ( empty( $roots ) ) {
506 wp_send_json_error( array( 'msg' => $source->get_error() ) );
507 }
508
509 wp_send_json_success( array( 'url' => $data['url'], 'roots' => $roots ) );
510 }
511
512 /**
513 * Returns the JSON data.
514 *
515 * @access public
516 */
517 public function get_json_data( $data ) {
518 if ( ! current_user_can( 'edit_posts' ) ) {
519 return false;
520 }
521
522 $chart_id = $data['chart'];
523
524 if ( empty( $chart_id ) ) {
525 wp_die();
526 }
527
528 $source = new Visualizer_Source_Json( $data );
529 $source->fetch();
530 $table = $source->getRawData();
531
532 if ( empty( $table ) ) {
533 wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
534 }
535
536 $table = Visualizer_Render_Layout::show( 'editor-table', $table, $chart_id, 'viz-json-table', false, false );
537 wp_send_json_success( array( 'table' => $table, 'root' => $data['root'], 'url' => $data['url'], 'paging' => $source->getPaginationElements() ) );
538 }
539
540 /**
541 * Set the JSON data.
542 *
543 * @access public
544 */
545 public function set_json_data( $data ) {
546 if ( ! current_user_can( 'edit_posts' ) ) {
547 return false;
548 }
549
550 $source = new Visualizer_Source_Json( $data );
551
552 $table = $source->fetch();
553 if ( empty( $table ) ) {
554 wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
555 }
556
557 $source->fetchFromEditableTable();
558 $name = $source->getSourceName();
559 $series = json_encode( $source->getSeries() );
560 $data = json_encode( $source->getRawData() );
561 wp_send_json_success( array( 'name' => $name, 'series' => $series, 'data' => $data ) );
562 }
563
564 /**
565 * Rest Callback Method
566 */
567 public function update_chart_data( $data ) {
568 if ( ! current_user_can( 'edit_posts' ) ) {
569 return false;
570 }
571
572 if ( $data['id'] && ! is_wp_error( $data['id'] ) ) {
573 if ( get_post_type( $data['id'] ) !== Visualizer_Plugin::CPT_VISUALIZER ) {
574 return new WP_Error( 'invalid_post_type', 'Invalid post type.' );
575 }
576 $chart_type = sanitize_text_field( $data['visualizer-chart-type'] );
577 $source_type = sanitize_text_field( $data['visualizer-source'] );
578
579 update_post_meta( $data['id'], Visualizer_Plugin::CF_CHART_TYPE, $chart_type );
580 update_post_meta( $data['id'], Visualizer_Plugin::CF_SOURCE, $source_type );
581 update_post_meta( $data['id'], Visualizer_Plugin::CF_DEFAULT_DATA, $data['visualizer-default-data'] );
582 update_post_meta( $data['id'], Visualizer_Plugin::CF_SERIES, $data['visualizer-series'] );
583 update_post_meta( $data['id'], Visualizer_Plugin::CF_SETTINGS, $data['visualizer-settings'] );
584
585 if ( $data['visualizer-chart-url'] && $data['visualizer-chart-schedule'] ) {
586 $chart_url = esc_url_raw( $data['visualizer-chart-url'] );
587 $chart_schedule = intval( $data['visualizer-chart-schedule'] );
588 update_post_meta( $data['id'], Visualizer_Plugin::CF_CHART_URL, $chart_url );
589 apply_filters( 'visualizer_pro_chart_schedule', $data['id'], $chart_url, $chart_schedule );
590 } else {
591 delete_post_meta( $data['id'], Visualizer_Plugin::CF_CHART_URL );
592 apply_filters( 'visualizer_pro_remove_schedule', $data['id'] );
593 }
594
595 // let's check if this is not an external db chart
596 // as there is no support for that in the block editor interface
597 $external_params = get_post_meta( $data['id'], Visualizer_Plugin::CF_REMOTE_DB_PARAMS, true );
598 if ( empty( $external_params ) ) {
599 if ( $source_type === 'Visualizer_Source_Query' ) {
600 $db_schedule = intval( $data['visualizer-db-schedule'] );
601 $db_query = $data['visualizer-db-query'];
602 update_post_meta( $data['id'], Visualizer_Plugin::CF_DB_SCHEDULE, $db_schedule );
603 update_post_meta( $data['id'], Visualizer_Plugin::CF_DB_QUERY, stripslashes( $db_query ) );
604 } else {
605 delete_post_meta( $data['id'], Visualizer_Plugin::CF_DB_SCHEDULE );
606 delete_post_meta( $data['id'], Visualizer_Plugin::CF_DB_QUERY );
607 }
608 }
609
610 if ( $source_type === 'Visualizer_Source_Json' ) {
611 $json_schedule = intval( $data['visualizer-json-schedule'] );
612 $json_url = esc_url_raw( $data['visualizer-json-url'] );
613 $json_headers = esc_url_raw( $data['visualizer-json-headers'] );
614 $json_root = $data['visualizer-json-root'];
615 $json_paging = $data['visualizer-json-paging'];
616
617 update_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_SCHEDULE, $json_schedule );
618 update_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_URL, $json_url );
619 update_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_HEADERS, $json_headers );
620 update_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_ROOT, $json_root );
621
622 if ( ! empty( $json_paging ) ) {
623 update_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_PAGING, $json_paging );
624 } else {
625 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_PAGING );
626 }
627 } else {
628 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_SCHEDULE );
629 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_URL );
630 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_HEADERS );
631 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_ROOT );
632 delete_post_meta( $data['id'], Visualizer_Plugin::CF_JSON_PAGING );
633 }
634
635 if ( Visualizer_Module::is_pro() ) {
636 update_post_meta( $data['id'], Visualizer_PRO::CF_PERMISSIONS, $data['visualizer-permissions'] );
637 }
638
639 if ( $data['visualizer-chart-url'] ) {
640 $chart_url = esc_url_raw( $data['visualizer-chart-url'] );
641 $content['source'] = $chart_url;
642 $content['data'] = $this->format_chart_data( $data['visualizer-data'], $data['visualizer-series'] );
643 } else {
644 $content = $this->format_chart_data( $data['visualizer-data'], $data['visualizer-series'] );
645 }
646
647 $chart = array(
648 'ID' => $data['id'],
649 'post_content' => serialize( $content ),
650 );
651
652 wp_update_post( $chart );
653
654 $revisions = wp_get_post_revisions( $data['id'], array( 'order' => 'ASC' ) );
655
656 if ( count( $revisions ) > 1 ) {
657 $revision_ids = array_keys( $revisions );
658
659 // delete all revisions.
660 foreach ( $revision_ids as $id ) {
661 wp_delete_post_revision( $id );
662 }
663 }
664
665 return new \WP_REST_Response( array( 'success' => sprintf( 'Chart updated' ) ) );
666 }
667 }
668
669 /**
670 * Format chart data.
671 *
672 * Note: No matter how tempted, don't use the similar method from Visualizer_Source. That works on a different structure.
673 */
674 public function format_chart_data( $data, $series ) {
675 foreach ( $series as $i => $row ) {
676 // if no value exists for the seires, then add null
677 if ( ! isset( $series[ $i ] ) ) {
678 $series[ $i ] = null;
679 }
680
681 if ( is_null( $series[ $i ] ) ) {
682 continue;
683 }
684
685 switch ( $row['type'] ) {
686 case 'number':
687 foreach ( $data as $o => $col ) {
688 $data[ $o ][ $i ] = ( is_numeric( $col[ $i ] ) ) ? floatval( $col[ $i ] ) : ( is_numeric( str_replace( ',', '', $col[ $i ] ) ) ? floatval( str_replace( ',', '', $col[ $i ] ) ) : null );
689 }
690 break;
691 case 'boolean':
692 foreach ( $data as $o => $col ) {
693 $data[ $o ][ $i ] = ! empty( $col[ $i ] ) ? filter_var( $col[ $i ], FILTER_VALIDATE_BOOLEAN ) : false;
694 }
695 break;
696 case 'timeofday':
697 foreach ( $data as $o => $col ) {
698 $date = new DateTime( '1984-03-16T' . $col[ $i ] );
699 if ( $date ) {
700 $data[ $o ][ $i ] = array(
701 intval( $date->format( 'H' ) ),
702 intval( $date->format( 'i' ) ),
703 intval( $date->format( 's' ) ),
704 0,
705 );
706 }
707 }
708 break;
709 case 'string':
710 foreach ( $data as $o => $col ) {
711 $data[ $o ][ $i ] = $this->toUTF8( $col[ $i ] );
712 }
713 break;
714 }
715 }
716
717 return $data;
718 }
719
720 /**
721 * Use toUTF8 function
722 */
723 public function toUTF8( $datum ) {
724 if ( ! function_exists( 'mb_detect_encoding' ) || mb_detect_encoding( $datum ) !== 'ASCII' ) {
725 $datum = \ForceUTF8\Encoding::toUTF8( $datum );
726 }
727 return $datum;
728 }
729
730 /**
731 * Handle remote CSV data
732 */
733 public function upload_csv_data( $data ) {
734 if ( ! current_user_can( 'edit_posts' ) ) {
735 return false;
736 }
737
738 if ( $data['url'] && ! is_wp_error( $data['url'] ) && filter_var( $data['url'], FILTER_VALIDATE_URL ) ) {
739 $source = new Visualizer_Source_Csv_Remote( $data['url'] );
740 if ( $source->fetch() ) {
741 $temp = $source->getData();
742 if ( is_string( $temp ) && is_array( unserialize( $temp ) ) ) {
743 $content['series'] = $source->getSeries();
744 $content['data'] = $source->getRawData();
745 return $content;
746 } else {
747 return new \WP_REST_Response( array( 'failed' => sprintf( 'Invalid CSV URL' ) ) );
748 }
749 } else {
750 return new \WP_REST_Response( array( 'failed' => sprintf( 'Invalid CSV URL' ) ) );
751 }
752 } else {
753 return new \WP_REST_Response( array( 'failed' => sprintf( 'Invalid CSV URL' ) ) );
754 }
755 }
756
757 /**
758 * Get permission data
759 */
760 public function get_permission_data( $data ) {
761 if ( ! current_user_can( 'edit_posts' ) ) {
762 return false;
763 }
764
765 $options = array();
766 switch ( $data['type'] ) {
767 case 'users':
768 $query = new WP_User_Query(
769 array(
770 'number' => 1000,
771 'orderby' => 'display_name',
772 'fields' => array( 'ID', 'display_name' ),
773 'count_total' => false,
774 )
775 );
776 $users = $query->get_results();
777 if ( ! empty( $users ) ) {
778 $i = 0;
779 foreach ( $users as $user ) {
780 $options[ $i ]['value'] = $user->ID;
781 $options[ $i ]['label'] = $user->display_name;
782 $i++;
783 }
784 }
785 break;
786 case 'roles':
787 if ( ! function_exists( 'get_editable_roles' ) ) {
788 require_once ABSPATH . 'wp-admin/includes/user.php';
789 }
790 $roles = get_editable_roles();
791 if ( ! empty( $roles ) ) {
792 $i = 0;
793 foreach ( get_editable_roles() as $name => $info ) {
794 $options[ $i ]['value'] = $name;
795 $options[ $i ]['label'] = $name;
796 $i++;
797 }
798 }
799 break;
800 }
801 return $options;
802 }
803
804 /**
805 * Filter Rest Query
806 */
807 public function add_rest_query_vars( $args, \WP_REST_Request $request ) {
808 if ( isset( $request['meta_key'] ) && isset( $request['meta_value'] ) ) {
809 $args['meta_query'] = array(
810 'relation' => 'OR',
811 array(
812 'key' => $request->get_param( 'meta_key' ),
813 'value' => $request->get_param( 'meta_value' ),
814 'compare' => '!=',
815 ),
816 array(
817 'key' => $request->get_param( 'meta_key' ),
818 'value' => $request->get_param( 'meta_value' ),
819 'compare' => 'NOT EXISTS',
820 ),
821 );
822 }
823 return $args;
824 }
825 }
826