PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.3
4.0.8 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 All 149 releases
← All changes | classes/Visualizer/Module/Chart.php +639 -76 3.1.03.4.3 View file →
@@ -60,11 +60,222 @@
60 60 $this->_addAjaxAction( Visualizer_Plugin::ACTION_EXPORT_DATA, 'exportData' );
61 61
62 62 $this->_addAjaxAction( Visualizer_Plugin::ACTION_FETCH_DB_DATA, 'getQueryData' );
63 63 $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_DB_QUERY, 'saveQuery' );
64 +
65 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_JSON_GET_ROOTS, 'getJsonRoots' );
66 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_JSON_GET_DATA, 'getJsonData' );
67 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_JSON_SET_DATA, 'setJsonData' );
68 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE, 'setJsonSchedule' );
69 +
70 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY, 'saveFilter' );
71 +
72 + $this->_addFilter( 'visualizer_get_sidebar', 'getSidebar', 10, 2 );
73 +
64 74 }
65 75
66 76 /**
77 + * Generates the HTML of the sidebar for the chart.
78 + *
79 + * @since ?
80 + *
81 + * @access public
82 + */
83 + public function getSidebar( $sidebar, $chart_id ) {
84 + $chart = get_post( $chart_id );
85 + $data = $this->_getChartArray( $chart );
86 + $sidebar = '';
87 + $sidebar_class = $this->load_chart_class_name( $chart_id );
88 + if ( class_exists( $sidebar_class, true ) ) {
89 + $sidebar = new $sidebar_class( $data['settings'] );
90 + $sidebar->__series = $data['series'];
91 + $sidebar->__data = $data['data'];
92 + } else {
93 + $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
94 + if ( $sidebar !== '' ) {
95 + $sidebar->__series = $data['series'];
96 + $sidebar->__data = $data['data'];
97 + }
98 + }
99 + return str_replace( "'", '"', $sidebar->__toString() );
100 + }
101 +
102 + /**
103 + * Sets the schedule for how JSON-endpoint charts should be updated.
104 + *
105 + * @since ?
106 + *
107 + * @access public
108 + */
109 + public function setJsonSchedule() {
110 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION, 'security' );
111 +
112 + $chart_id = filter_input(
113 + INPUT_POST,
114 + 'chart',
115 + FILTER_VALIDATE_INT,
116 + array(
117 + 'options' => array(
118 + 'min_range' => 1,
119 + ),
120 + )
121 + );
122 +
123 + if ( ! $chart_id ) {
124 + wp_send_json_error();
125 + }
126 +
127 + $time = filter_input(
128 + INPUT_POST,
129 + 'time',
130 + FILTER_VALIDATE_INT,
131 + array(
132 + 'options' => array(
133 + 'min_range' => -1,
134 + ),
135 + )
136 + );
137 +
138 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
139 +
140 + if ( -1 < $time ) {
141 + add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
142 + }
143 + wp_send_json_success();
144 + }
145 +
146 + /**
147 + * Get the root elements for JSON-endpoint.
148 + *
149 + * @since ?
150 + *
151 + * @access public
152 + */
153 + public function getJsonRoots() {
154 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
155 +
156 + $params = wp_parse_args( $_POST['params'] );
157 +
158 + $source = new Visualizer_Source_Json( $params );
159 +
160 + $roots = $source->fetchRoots();
161 + if ( empty( $roots ) ) {
162 + wp_send_json_error( array( 'msg' => $source->get_error() ) );
163 + }
164 +
165 + wp_send_json_success( array( 'url' => $params['url'], 'roots' => $roots ) );
166 + }
167 +
168 + /**
169 + * Get the data for the JSON-endpoint corresponding to the chosen root.
170 + *
171 + * @since ?
172 + *
173 + * @access public
174 + */
175 + public function getJsonData() {
176 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
177 +
178 + $params = wp_parse_args( $_POST['params'] );
179 +
180 + $chart_id = $params['chart'];
181 +
182 + if ( empty( $chart_id ) ) {
183 + wp_die();
184 + }
185 +
186 + $source = new Visualizer_Source_Json( $params );
187 + $source->fetch();
188 + $data = $source->getRawData();
189 +
190 + if ( empty( $data ) ) {
191 + wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
192 + }
193 +
194 + $data = Visualizer_Render_Layout::show( 'editor-table', $data, $chart_id, 'viz-json-table', false, false );
195 + wp_send_json_success( array( 'table' => $data, 'root' => $params['root'], 'url' => $params['url'], 'paging' => $source->getPaginationElements() ) );
196 + }
197 +
198 + /**
199 + * Updates the database with the correct post parameters for JSON-endpoint charts.
200 + *
201 + * @since ?
202 + *
203 + * @access public
204 + */
205 + public function setJsonData() {
206 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_DATA . Visualizer_Plugin::VERSION, 'security' );
207 +
208 + $params = $_POST;
209 + $chart_id = $_GET['chart'];
210 +
211 + if ( empty( $chart_id ) ) {
212 + wp_die();
213 + }
214 +
215 + $chart = get_post( $chart_id );
216 +
217 + $source = new Visualizer_Source_Json( $params );
218 + $source->fetchFromEditableTable();
219 +
220 + $content = $source->getData();
221 + $chart->post_content = $content;
222 + wp_update_post( $chart->to_array() );
223 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
224 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
225 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
226 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_URL, $params['url'] );
227 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_ROOT, $params['root'] );
228 +
229 + delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS );
230 + $headers = array( 'method' => $params['method'] );
231 + if ( ! empty( $params['auth'] ) ) {
232 + $headers['auth'] = $params['auth'];
233 + } elseif ( ! empty( $params['username'] ) && ! empty( $params['password'] ) ) {
234 + $headers['auth'] = array( 'username' => $params['username'], 'password' => $params['password'] );
235 + }
236 +
237 + add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS, $headers );
238 +
239 + delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING );
240 + if ( ! empty( $params['paging'] ) ) {
241 + add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
242 + }
243 +
244 + $time = filter_input(
245 + INPUT_POST,
246 + 'time',
247 + FILTER_VALIDATE_INT,
248 + array(
249 + 'options' => array(
250 + 'min_range' => -1,
251 + ),
252 + )
253 + );
254 +
255 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
256 +
257 + if ( -1 < $time ) {
258 + add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
259 + }
260 +
261 + // delete other source specific parameters.
262 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
263 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
264 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_URL );
265 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_SCHEDULE );
266 +
267 + $render = new Visualizer_Render_Page_Update();
268 + $render->id = $chart->ID;
269 + $render->data = json_encode( $source->getRawData() );
270 + $render->series = json_encode( $source->getSeries() );
271 + $render->render();
272 +
273 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
274 + }
275 +
276 +
277 + /**
67 278 * Fetches charts from database.
68 279 *
69 280 * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
70 281 *
@@ -93,9 +304,9 @@
93 304 // 'filter' is from the modal from the add media button.
94 305 $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
95 306 }
96 307
97 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
308 + if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
98 309 $query_args['meta_query'] = array(
99 310 array(
100 311 'key' => Visualizer_Plugin::CF_CHART_TYPE,
101 312 'value' => $filter,
@@ -146,9 +357,9 @@
146 357 $chart = $this->_chart;
147 358 }
148 359 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
149 360 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
150 - $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( $chart->post_content ), $chart->ID, $type );
361 + $data = self::get_chart_data( $chart, $type );
151 362 $library = $this->load_chart_type( $chart->ID );
152 363
153 364 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
154 365 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
@@ -162,8 +373,10 @@
162 373 $css = $arguments[0];
163 374 $settings = $arguments[1];
164 375 }
165 376
377 + $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
378 +
166 379 return array(
167 380 'type' => $type,
168 381 'series' => $series,
169 382 'settings' => $settings,
@@ -169,8 +382,9 @@
169 382 'settings' => $settings,
170 383 'data' => $data,
171 384 'library' => $library,
172 385 'css' => $css,
386 + 'date_formats' => $date_formats,
173 387 );
174 388 }
175 389
176 390 /**
@@ -197,9 +411,9 @@
197 411 *
198 412 * @access public
199 413 */
200 414 public function deleteChart() {
201 - $is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
415 + $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
202 416 $input_method = $is_post ? INPUT_POST : INPUT_GET;
203 417 $chart_id = $success = false;
204 418 $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
205 419 $capable = current_user_can( 'delete_posts' );
@@ -215,9 +429,9 @@
215 429 )
216 430 );
217 431 if ( $chart_id ) {
218 432 $chart = get_post( $chart_id );
219 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
433 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
220 434 }
221 435 }
222 436 if ( $success ) {
223 437 wp_delete_post( $chart_id, true );
@@ -228,13 +442,41 @@
228 442 'success' => $success,
229 443 )
230 444 );
231 445 }
232 - wp_redirect( wp_get_referer() );
446 + wp_redirect( remove_query_arg( 'vaction', wp_get_referer() ) );
233 447 exit;
234 448 }
235 449
236 450 /**
451 + * Delete charts that are still in auto-draft mode.
452 + */
453 + private function deleteOldCharts() {
454 + $query = new WP_Query(
455 + array(
456 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
457 + 'post_status' => 'auto-draft',
458 + 'fields' => 'ids',
459 + 'update_post_meta_cache' => false,
460 + 'update_post_term_cache' => false,
461 + 'posts_per_page' => 50,
462 + 'date_query' => array(
463 + array(
464 + 'before' => 'today',
465 + ),
466 + ),
467 + )
468 + );
469 +
470 + if ( $query->have_posts() ) {
471 + $ids = array();
472 + while ( $query->have_posts() ) {
473 + wp_delete_post( $query->next_post(), true );
474 + }
475 + }
476 + }
477 +
478 + /**
237 479 * Renders appropriate page for chart builder. Creates new auto draft chart
238 480 * if no chart has been specified.
239 481 *
240 482 * @since 1.0.0
@@ -244,9 +486,10 @@
244 486 public function renderChartPages() {
245 487 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
246 488 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
247 489 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
248 - if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
490 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
491 + $this->deleteOldCharts();
249 492 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
250 493 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
251 494 $source->fetch();
252 495 $chart_id = wp_insert_post(
@@ -262,8 +505,9 @@
262 505 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
263 506 add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
264 507 add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
265 508 add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
509 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
266 510 add_post_meta(
267 511 $chart_id,
268 512 Visualizer_Plugin::CF_SETTINGS,
269 513 array(
@@ -275,16 +519,23 @@
275 519 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
276 520 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
277 521 }
278 522
279 - $this->load_chart_type( $chart_id );
523 + $lib = $this->load_chart_type( $chart_id );
280 524
525 + // the alpha color picker (RGBA) is not supported by google.
526 + $color_picker_dep = 'wp-color-picker';
527 + if ( in_array( $lib, array( 'chartjs', 'datatables' ), true ) && ! wp_script_is( 'wp-color-picker-alpha', 'registered' ) ) {
528 + wp_register_script( 'wp-color-picker-alpha', VISUALIZER_ABSURL . 'js/lib/wp-color-picker-alpha.min.js', array( 'wp-color-picker' ), Visualizer_Plugin::VERSION );
529 + $color_picker_dep = 'wp-color-picker-alpha';
530 + }
531 +
281 532 // enqueue and register scripts and styles
282 533 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
283 534 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
284 535
285 536 wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
286 - wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION, true );
537 + wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion', 'jquery-ui-tabs' ), Visualizer_Plugin::VERSION, true );
287 538 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
288 539 wp_register_script(
289 540 'visualizer-render',
290 541 VISUALIZER_ABSURL . 'js/render-facade.js',
@@ -295,19 +546,23 @@
295 546 wp_register_script(
296 547 'visualizer-preview',
297 548 VISUALIZER_ABSURL . 'js/preview.js',
298 549 array(
299 - 'wp-color-picker',
550 + $color_picker_dep,
300 551 'visualizer-render',
301 552 ),
302 553 Visualizer_Plugin::VERSION,
303 554 true
304 555 );
305 - // added by Ash/Upwork
306 - if ( VISUALIZER_PRO ) {
556 + wp_register_script( 'visualizer-editor-simple', VISUALIZER_ABSURL . 'js/simple-editor.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
557 +
558 + do_action( 'visualizer_add_scripts' );
559 +
560 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
307 561 global $Visualizer_Pro;
308 562 $Visualizer_Pro->_addScriptsAndStyles();
309 563 }
564 +
310 565 // dispatch pages
311 566 $this->_chart = get_post( $chart_id );
312 567 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
313 568
@@ -319,8 +574,9 @@
319 574 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
320 575 // if the cancel button is clicked.
321 576 $this->undoRevisions( $chart_id, true );
322 577 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
578 + $this->handlePermissions();
323 579 // if the save button is clicked.
324 580 $this->undoRevisions( $chart_id, false );
325 581 } else {
326 582 // if the edit button is clicked.
@@ -335,9 +591,9 @@
335 591 case 'visualizer': // fall through.
336 592 $this->_handleTypesPage();
337 593 break;
338 594 default:
339 - do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
595 + // this should never happen.
340 596 break;
341 597 }
342 598 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
343 599 }
@@ -344,25 +600,26 @@
344 600
345 601 /**
346 602 * Load code editor assets.
347 603 */
348 - private function loadCodeEditorAssets() {
604 + private function loadCodeEditorAssets( $chart_id ) {
349 605 global $wp_version;
350 606
351 - if ( ! VISUALIZER_PRO ) {
607 + $wp_scripts = wp_scripts();
608 +
609 + // data tables assets.
610 + wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
611 + wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
612 + wp_register_style( 'visualizer-jquery-ui', sprintf( '//ajax.googleapis.com/ajax/libs/jqueryui/%s/themes/smoothness/jquery-ui.css', $wp_scripts->registered['jquery-ui-core']->ver ), array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
613 + wp_enqueue_script( 'visualizer-datatables' );
614 + wp_enqueue_style( 'visualizer-jquery-ui' );
615 +
616 + if ( ! Visualizer_Module::is_pro() ) {
352 617 return;
353 618 }
354 619
355 - $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping();
620 + $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping( $chart_id );
356 621
357 - // data tables assets.
358 - wp_register_script( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
359 - wp_register_style( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css', array(), Visualizer_Plugin::VERSION );
360 - wp_register_style( 'visualizer-datatables-ui', '//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css', array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
361 -
362 - wp_enqueue_script( 'visualizer-datatables' );
363 - wp_enqueue_style( 'visualizer-datatables-ui' );
364 -
365 622 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
366 623 // code mirror assets.
367 624 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
368 625 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
@@ -396,8 +653,25 @@
396 653 return $table_col_mapping;
397 654 }
398 655
399 656 /**
657 + * Handle permissions from the new conslidated settings sidebar.
658 + */
659 + private function handlePermissions() {
660 + if ( ! Visualizer_Module::is_pro() ) {
661 + return;
662 + }
663 +
664 + // we will not support old free and new pro.
665 + // handling new free and old pro.
666 + if ( has_action( 'visualizer_pro_handle_tab' ) ) {
667 + do_action( 'visualizer_pro_handle_tab', 'permissions', $this->_chart );
668 + } else {
669 + do_action( 'visualizer_handle_permissions', $this->_chart );
670 + }
671 + }
672 +
673 + /**
400 674 * Handle data and settings page
401 675 */
402 676 private function _handleDataAndSettingsPage() {
403 677 if ( isset( $_POST['map_api_key'] ) ) {
@@ -402,10 +676,11 @@
402 676 private function _handleDataAndSettingsPage() {
403 677 if ( isset( $_POST['map_api_key'] ) ) {
404 678 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
405 679 }
406 - if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
407 - if ( $this->_chart->post_status == 'auto-draft' ) {
680 +
681 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
682 + if ( $this->_chart->post_status === 'auto-draft' ) {
408 683 $this->_chart->post_status = 'publish';
409 684
410 685 // ensure that a revision is not created. If a revision is created it will have the proper data and the parent of the revision will have default data.
411 686 // we do not want any difference in data so disable revisions temporarily.
@@ -414,18 +689,33 @@
414 689 }
415 690 // save meta data only when it is NOT being canceled.
416 691 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
417 692 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
693 +
694 + // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
695 + // this will help in searching with the chart id.
696 + $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
697 + $title = null;
698 + if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
699 + $title = $settings['title'];
700 + if ( is_array( $title ) ) {
701 + $title = $settings['title']['text'];
702 + }
703 + }
704 + if ( empty( $title ) ) {
705 + $title = $this->_chart->ID;
706 + }
707 + $settings['internal_title'] = $title;
708 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
418 709 }
419 710 $render = new Visualizer_Render_Page_Send();
420 711 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
421 712 wp_iframe( array( $render, 'render' ) );
422 -
423 713 return;
424 714 }
425 715 $data = $this->_getChartArray();
426 716 $sidebar = '';
427 - $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
717 + $sidebar_class = $this->load_chart_class_name( $this->_chart->ID );
428 718 if ( class_exists( $sidebar_class, true ) ) {
429 719 $sidebar = new $sidebar_class( $data['settings'] );
430 720 $sidebar->__series = $data['series'];
431 721 $sidebar->__data = $data['data'];
@@ -430,14 +720,14 @@
430 720 $sidebar->__series = $data['series'];
431 721 $sidebar->__data = $data['data'];
432 722 } else {
433 723 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
434 - if ( $sidebar != '' ) {
724 + if ( $sidebar !== '' ) {
435 725 $sidebar->__series = $data['series'];
436 726 $sidebar->__data = $data['data'];
437 727 }
438 728 }
439 - unset( $data['settings']['width'], $data['settings']['height'] );
729 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
440 730 wp_enqueue_style( 'wp-color-picker' );
441 731 wp_enqueue_style( 'visualizer-frame' );
442 732 wp_enqueue_script( 'visualizer-preview' );
443 733 wp_enqueue_script( 'visualizer-chosen' );
@@ -442,17 +732,37 @@
442 732 wp_enqueue_script( 'visualizer-preview' );
443 733 wp_enqueue_script( 'visualizer-chosen' );
444 734 wp_enqueue_script( 'visualizer-render' );
445 735
446 - $table_col_mapping = $this->loadCodeEditorAssets();
736 + if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
737 + wp_enqueue_script( 'visualizer-editor-simple' );
738 + wp_localize_script(
739 + 'visualizer-editor-simple',
740 + 'visualizer1',
741 + array(
742 + 'ajax' => array(
743 + 'url' => admin_url( 'admin-ajax.php' ),
744 + 'nonces' => array(
745 + ),
746 + 'actions' => array(
747 + ),
748 + ),
749 + )
750 + );
751 + }
447 752
753 + $table_col_mapping = $this->loadCodeEditorAssets( $this->_chart->ID );
754 +
448 755 wp_localize_script(
449 756 'visualizer-render',
450 757 'visualizer',
451 758 array(
452 759 'l10n' => array(
453 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
760 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
454 761 'loading' => esc_html__( 'Loading...', 'visualizer' ),
762 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
763 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
764 + 'save_settings' => __( 'You have modified the chart\'s settings. To modify the source/data again, you must save this chart and reopen it for editing. If you continue without saving the chart, you may lose your changes.', 'visualizer' ),
455 765 ),
456 766 'charts' => array(
457 767 'canvas' => $data,
458 768 'id' => $this->_chart->ID,
@@ -463,19 +773,28 @@
463 773 'url' => admin_url( 'admin-ajax.php' ),
464 774 'nonces' => array(
465 775 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
466 776 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
777 + 'json_get_roots' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION ),
778 + 'json_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION ),
779 + 'json_set_schedule' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION ),
467 780 ),
468 781 'actions' => array(
469 782 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
470 783 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
784 + 'json_get_roots' => Visualizer_Plugin::ACTION_JSON_GET_ROOTS,
785 + 'json_get_data' => Visualizer_Plugin::ACTION_JSON_GET_DATA,
786 + 'json_set_schedule' => Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE,
471 787 ),
472 788 ),
473 789 'db_query' => array(
474 790 'tables' => $table_col_mapping,
475 791 ),
476 - 'is_pro' => VISUALIZER_PRO,
792 + 'is_pro' => Visualizer_Module::is_pro(),
477 793 'page_type' => 'chart',
794 + 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
795 + 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
796 + 'is_front' => false,
478 797 )
479 798 );
480 799
481 800 $render = new Visualizer_Render_Page_Data();
@@ -483,21 +802,25 @@
483 802 $render->type = $data['type'];
484 803 $render->custom_css = $data['css'];
485 804 $render->sidebar = $sidebar;
486 805 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
487 - $render->button = filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART
806 + $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
488 807 ? esc_html__( 'Save Chart', 'visualizer' )
489 808 : esc_html__( 'Create Chart', 'visualizer' );
490 - if ( filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART ) {
809 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
491 810 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
492 811 }
493 812 } else {
494 813 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
495 814 }
496 - if ( VISUALIZER_PRO ) {
815 +
816 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
817 +
818 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
497 819 global $Visualizer_Pro;
498 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
820 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
499 821 }
822 +
500 823 $this->_addAction( 'admin_head', 'renderFlattrScript' );
501 824 wp_iframe( array( $render, 'render' ) );
502 825 }
503 826
@@ -509,13 +832,21 @@
509 832 * @access private
510 833 */
511 834 private function _handleTypesPage() {
512 835 // process post request
513 - if ( $_SERVER['REQUEST_METHOD'] == 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
836 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
514 837 $type = filter_input( INPUT_POST, 'type' );
515 - if ( in_array( $type, Visualizer_Plugin::getChartTypes() ) ) {
838 + $library = filter_input( INPUT_POST, 'chart-library' );
839 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
840 + if ( empty( $library ) ) {
841 + // library cannot be empty.
842 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
843 + return;
844 + }
845 +
516 846 // save new chart type
517 847 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
848 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_LIBRARY, $library );
518 849 // if the chart has default data, update it with appropriate default data for new type
519 850 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
520 851 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
521 852 $source->fetch();
@@ -522,8 +853,11 @@
522 853 $this->_chart->post_content = $source->getData();
523 854 wp_update_post( $this->_chart->to_array() );
524 855 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
525 856 }
857 +
858 + Visualizer_Module_Utility::set_defaults( $this->_chart );
859 +
526 860 // redirect to next tab
527 861 // changed by Ash/Upwork
528 862 wp_redirect( add_query_arg( 'tab', 'settings' ) );
529 863
@@ -531,9 +865,9 @@
531 865 }
532 866 }
533 867 $render = new Visualizer_Render_Page_Types();
534 868 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
535 - $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
869 + $render->types = Visualizer_Module_Admin::_getChartTypesLocalized( false, false, false, 'types' );
536 870 $render->chart = $this->_chart;
537 871 wp_enqueue_style( 'visualizer-frame' );
538 872 wp_enqueue_script( 'visualizer-frame' );
539 873 wp_iframe( array( $render, 'render' ) );
@@ -549,10 +883,123 @@
549 883 */
550 884 public function renderFlattrScript() {
551 885 echo '';
552 886 }
553 - // changed by Ash/Upwork
887 +
554 888 /**
889 + * Processes the CSV that is sent in the request as a string.
890 + *
891 + * @since 3.2.0
892 + */
893 + private function handleCSVasString( $data, $editor_type ) {
894 + $source = null;
895 +
896 + switch ( $editor_type ) {
897 + case 'text':
898 + // data coming in from the text editor.
899 + $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
900 + $handle = fopen( $tmpfile, 'w' );
901 + $values = preg_split( '/[\n\r]+/', stripslashes( trim( $data ) ) );
902 + if ( $values ) {
903 + foreach ( $values as $row ) {
904 + if ( empty( $row ) ) {
905 + continue;
906 + }
907 + // don't use fpucsv here because we need to just dump the data
908 + // minus the empty rows
909 + // because fputcsv needs to tokenize
910 + // we can standardize the CSV enclosure here and replace all ' with "
911 + // we can assume that if there are an even number of ' they should be changed to "
912 + // but that will screw up words like fo'c'sle
913 + // so here let's just assume ' will NOT be used for enclosures
914 + fwrite( $handle, $row );
915 + fwrite( $handle, PHP_EOL );
916 + }
917 + }
918 + $source = new Visualizer_Source_Csv( $tmpfile );
919 + fclose( $handle );
920 + break;
921 + case 'table':
922 + // Import from Chart
923 + // fall-through.
924 + case 'excel':
925 + // data coming in from the excel editor.
926 + $source = apply_filters( 'visualizer_pro_handle_chart_data', $data, '' );
927 + break;
928 + }
929 + return $source;
930 + }
931 +
932 + /**
933 + * Parses the data uploaded as an HTML table.
934 + *
935 + * @since 3.2.0
936 + *
937 + * @access private
938 + */
939 + private function handleTabularData() {
940 + $csv = array();
941 + // the datatable mentions the headers twice, so lets remove the duplicates.
942 + $headers = array_unique( array_filter( $_POST['header'] ) );
943 + $types = $_POST['type'];
944 +
945 + // capture all the indexes that correspond to excluded columns.
946 + $exclude = array();
947 + $index = 0;
948 + foreach ( $types as $type ) {
949 + if ( empty( $type ) ) {
950 + $exclude[] = $index;
951 + }
952 + $index++;
953 + }
954 +
955 + // when N headers are being renamed, the number of headers increases by N
956 + // because of the way datatable duplicates header information
957 + // so unset the headers that have been renamed.
958 + if ( count( $headers ) !== count( $types ) ) {
959 + $to = count( $headers );
960 + for ( $i = count( $types ); $i < $to; $i++ ) {
961 + unset( $headers[ $i + 1 ] );
962 + }
963 + }
964 +
965 + $columns = array();
966 + for ( $i = 0; $i < count( $headers ); $i++ ) {
967 + if ( ! isset( $_POST[ 'data' . $i ] ) ) {
968 + continue;
969 + }
970 + $columns[ $i ] = $_POST[ 'data' . $i ];
971 + }
972 +
973 + $csv[] = $headers;
974 + $csv[] = $types;
975 + for ( $j = 0; $j < count( $columns[0] ); $j++ ) {
976 + $row = array();
977 + for ( $i = 0; $i < count( $headers ); $i++ ) {
978 + $row[] = sanitize_text_field( $columns[ $i ][ $j ] );
979 + }
980 + $csv[] = $row;
981 + }
982 +
983 + $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
984 + $handle = fopen( $tmpfile, 'w' );
985 +
986 + if ( $csv ) {
987 + $index = 0;
988 + foreach ( $csv as $row ) {
989 + // remove all the cells corresponding to the excluded headers.
990 + foreach ( $exclude as $j ) {
991 + unset( $row[ $j ] );
992 + }
993 + fputcsv( $handle, $row );
994 + }
995 + }
996 + $source = new Visualizer_Source_Csv( $tmpfile );
997 + fclose( $handle );
998 + return $source;
999 + }
1000 +
1001 + /**
555 1002 * Parses uploaded CSV file and saves new data for the chart.
556 1003 *
557 1004 * @since 1.0.0
558 1005 *
@@ -574,9 +1021,9 @@
574 1021
575 1022 // check chart, if chart exists
576 1023 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
577 1024 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
578 - if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
1025 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
579 1026 if ( ! $can_die ) {
580 1027 return;
581 1028 }
582 1029 status_header( 400 );
@@ -582,8 +1029,10 @@
582 1029 status_header( 400 );
583 1030 exit;
584 1031 }
585 1032
1033 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Uploading data for chart %d with POST = %s and GET = %s', $chart_id, print_r( $_POST, true ), print_r( $_GET, true ) ), 'debug', __FILE__, __LINE__ );
1034 +
586 1035 if ( ! isset( $_POST['vz-import-time'] ) ) {
587 1036 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
588 1037 }
589 1038
@@ -588,15 +1037,30 @@
588 1037 }
589 1038
590 1039 if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
591 1040 // delete the filters in case this chart is being uploaded from other data sources
592 - delete_post_meta( $chart_id, 'visualizer-filter-config' );
1041 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
1042 + delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
1043 + delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
593 1044
594 1045 // delete "import from db" specific parameters.
595 1046 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
596 1047 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
1048 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS );
597 1049 }
598 1050
1051 + // delete json related data.
1052 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL );
1053 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT );
1054 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING );
1055 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_HEADERS );
1056 +
1057 + // delete last error
1058 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR );
1059 +
1060 + // delete editor related data.
1061 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR );
1062 +
599 1063 $source = null;
600 1064 $render = new Visualizer_Render_Page_Update();
601 1065 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
602 1066 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
@@ -602,15 +1066,25 @@
602 1066 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
603 1067 if ( isset( $_POST['vz-import-time'] ) ) {
604 1068 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
605 1069 }
1070 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
606 1071 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
607 1072 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
608 1073 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
609 - $source = apply_filters( 'visualizer_pro_handle_chart_data', $_POST['chart_data'], '' );
1074 + $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1075 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1076 + } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
1077 + $source = $this->handleTabularData();
1078 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
610 1079 } else {
611 - $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
1080 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'CSV file with chart data was not uploaded for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
1081 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1082 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
612 1083 }
1084 +
1085 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Uploaded data for chart %d with source %s', $chart_id, print_r( $source, true ) ), 'debug', __FILE__, __LINE__ );
1086 +
613 1087 if ( $source ) {
614 1088 if ( $source->fetch() ) {
615 1089 $content = $source->getData();
616 1090 $populate = true;
@@ -619,8 +1093,9 @@
619 1093 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
620 1094 // if we populate the data even if it is empty, the chart will show "Table has no columns".
621 1095 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
622 1096 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ), 'warn', __FILE__, __LINE__ );
1097 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ) );
623 1098 $populate = false;
624 1099 }
625 1100 }
626 1101 if ( $populate ) {
@@ -629,14 +1104,30 @@
629 1104 wp_update_post( $chart->to_array() );
630 1105 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
631 1106 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
632 1107 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1108 +
1109 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Updated post for chart %d', $chart_id ), 'debug', __FILE__, __LINE__ );
1110 +
1111 + Visualizer_Module_Utility::set_defaults( $chart, null );
1112 +
1113 + $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1114 +
633 1115 $render->id = $chart->ID;
634 1116 $render->data = json_encode( $source->getRawData() );
635 1117 $render->series = json_encode( $source->getSeries() );
1118 + $render->settings = json_encode( $settings );
636 1119 } else {
637 - $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
1120 + $error = $source->get_error();
1121 + if ( empty( $error ) ) {
1122 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1123 + }
1124 + $render->message = $error;
1125 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1126 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
638 1127 }
1128 + } else {
1129 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
639 1130 }
640 1131 $render->render();
641 1132 if ( ! $can_die ) {
642 1133 return;
@@ -652,27 +1143,18 @@
652 1143 * @access public
653 1144 */
654 1145 public function cloneChart() {
655 1146 $chart_id = $success = false;
656 - $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
1147 + $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
657 1148 $capable = current_user_can( 'edit_posts' );
658 1149 if ( $nonce && $capable ) {
659 - $chart_id = filter_input(
660 - INPUT_GET,
661 - 'chart',
662 - FILTER_VALIDATE_INT,
663 - array(
664 - 'options' => array(
665 - 'min_range' => 1,
666 - ),
667 - )
668 - );
1150 + $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
669 1151 if ( $chart_id ) {
670 1152 $chart = get_post( $chart_id );
671 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1153 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
672 1154 }
673 1155 }
674 - $redirect = wp_get_referer();
1156 + $redirect = remove_query_arg( 'vaction', wp_get_referer() );
675 1157 if ( $success ) {
676 1158 $new_chart_id = wp_insert_post(
677 1159 array(
678 1160 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
@@ -681,23 +1163,32 @@
681 1163 'post_status' => $chart->post_status,
682 1164 'post_content' => $chart->post_content,
683 1165 )
684 1166 );
685 - if ( $new_chart_id && ! is_wp_error( $new_chart_id ) ) {
686 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_CHART_TYPE, get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true ) );
687 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, get_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, true ) );
688 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SOURCE, get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true ) );
689 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SERIES, get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true ) );
690 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SETTINGS, get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) );
1167 + if ( is_wp_error( $new_chart_id ) ) {
1168 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Error while cloning chart %d = %s', $chart_id, print_r( $new_chart_id, true ) ), 'error', __FILE__, __LINE__ );
1169 + } else {
1170 + $post_meta = get_post_meta( $chart_id );
1171 + foreach ( $post_meta as $key => $value ) {
1172 + if ( strpos( $key, 'visualizer-' ) !== false ) {
1173 + add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1174 + }
1175 + }
691 1176 $redirect = add_query_arg(
692 1177 array(
693 1178 'page' => 'visualizer',
694 1179 'type' => filter_input( INPUT_GET, 'type' ),
1180 + 'vaction' => false,
695 1181 ),
696 - admin_url( 'upload.php' )
1182 + admin_url( 'admin.php' )
697 1183 );
698 1184 }
699 1185 }
1186 +
1187 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1188 + wp_die();
1189 + }
1190 +
700 1191 wp_redirect( $redirect );
701 1192 exit;
702 1193 }
703 1194
@@ -743,9 +1234,12 @@
743 1234 $data = $this->_getChartArray();
744 1235 $render = new Visualizer_Render_Page_Data();
745 1236 $render->chart = $this->_chart;
746 1237 $render->type = $data['type'];
747 - unset( $data['settings']['width'], $data['settings']['height'] );
1238 +
1239 + if ( $data && $data['settings'] ) {
1240 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1241 + }
748 1242 wp_enqueue_style( 'visualizer-frame' );
749 1243 wp_enqueue_script( 'visualizer-render' );
750 1244 wp_localize_script(
751 1245 'visualizer-render',
@@ -751,9 +1245,9 @@
751 1245 'visualizer-render',
752 1246 'visualizer',
753 1247 array(
754 1248 'l10n' => array(
755 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1249 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
756 1250 'loading' => esc_html__( 'Loading...', 'visualizer' ),
757 1251 ),
758 1252 'charts' => array(
759 1253 'canvas' => $data,
@@ -759,13 +1253,16 @@
759 1253 'canvas' => $data,
760 1254 ),
761 1255 )
762 1256 );
763 - // Added by Ash/Upwork
764 - if ( VISUALIZER_PRO ) {
1257 +
1258 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
1259 +
1260 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
765 1261 global $Visualizer_Pro;
766 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1262 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
767 1263 }
1264 +
768 1265 // Added by Ash/Upwork
769 1266 $this->_addAction( 'admin_head', 'renderFlattrScript' );
770 1267 wp_iframe( array( $render, 'render' ) );
771 1268 }
@@ -778,13 +1275,14 @@
778 1275 public function getQueryData() {
779 1276 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
780 1277
781 1278 $params = wp_parse_args( $_POST['params'] );
782 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1279 + $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1280 +
1281 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
783 1282 $html = $source->fetch( true );
784 - $error = '';
785 - if ( empty( $html ) ) {
786 - $error = $source->get_error();
1283 + $error = $source->get_error();
1284 + if ( ! empty( $error ) ) {
787 1285 wp_send_json_error( array( 'msg' => $error ) );
788 1286 }
789 1287 wp_send_json_success( array( 'table' => $html ) );
790 1288 }
@@ -807,21 +1305,42 @@
807 1305 ),
808 1306 )
809 1307 );
810 1308
1309 + $hours = filter_input(
1310 + INPUT_POST,
1311 + 'refresh',
1312 + FILTER_VALIDATE_INT,
1313 + array(
1314 + 'options' => array(
1315 + 'min_range' => -1,
1316 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1317 + ),
1318 + )
1319 + );
1320 +
1321 + if ( ! is_int( $hours ) ) {
1322 + $hours = -1;
1323 + }
1324 +
811 1325 $render = new Visualizer_Render_Page_Update();
812 1326 if ( $chart_id ) {
813 1327 $params = wp_parse_args( $_POST['params'] );
814 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1328 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
815 1329 $source->fetch( false );
816 1330 $error = $source->get_error();
817 1331 if ( empty( $error ) ) {
818 - $hours = $_POST['refresh'];
819 1332 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
820 1333 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
821 1334 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
822 1335 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
823 1336 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1337 + if ( isset( $params['db_type'] ) && $params['db_type'] !== Visualizer_Plugin::WP_DB_NAME ) {
1338 + $remote_db_params = $params;
1339 + unset( $remote_db_params['query'] );
1340 + unset( $remote_db_params['chart_id'] );
1341 + update_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS, $remote_db_params );
1342 + }
824 1343
825 1344 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
826 1345 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
827 1346 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
@@ -833,13 +1352,57 @@
833 1352 )
834 1353 );
835 1354 $render->data = json_encode( $source->getRawData() );
836 1355 $render->series = json_encode( $source->getSeries() );
1356 + $render->id = $chart_id;
837 1357 } else {
838 1358 $render->message = $error;
839 1359 }
840 1360 }
841 1361 $render->render();
1362 + if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1363 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1364 + }
1365 + }
1366 +
1367 +
1368 + /**
1369 + * Saves the filter query and the schedule.
1370 + *
1371 + * @access public
1372 + */
1373 + public function saveFilter() {
1374 + check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1375 +
1376 + $chart_id = filter_input(
1377 + INPUT_GET,
1378 + 'chart',
1379 + FILTER_VALIDATE_INT,
1380 + array(
1381 + 'options' => array(
1382 + 'min_range' => 1,
1383 + ),
1384 + )
1385 + );
1386 +
1387 + $hours = filter_input(
1388 + INPUT_POST,
1389 + 'refresh',
1390 + FILTER_VALIDATE_INT,
1391 + array(
1392 + 'options' => array(
1393 + 'min_range' => -1,
1394 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1395 + ),
1396 + )
1397 + );
1398 +
1399 + if ( ! $hours ) {
1400 + $hours = -1;
1401 + }
1402 +
1403 + do_action( 'visualizer_save_filter', $chart_id, $hours );
1404 +
842 1405 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
843 1406 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
844 1407 }
845 1408 }