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.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 +593 -83 3.1.33.5.1 View file →
@@ -60,12 +60,227 @@
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 +
64 70 $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY, 'saveFilter' );
71 +
72 + $this->_addFilter( 'visualizer_get_sidebar', 'getSidebar', 10, 2 );
73 +
65 74 }
66 75
67 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 + // Update schedules.
143 + $schedules = get_option( Visualizer_Plugin::CF_JSON_SCHEDULE, array() );
144 + $schedules[ $chart_id ] = time() + $time * HOUR_IN_SECONDS;
145 + update_option( Visualizer_Plugin::CF_JSON_SCHEDULE, $schedules );
146 + }
147 + wp_send_json_success();
148 + }
149 +
150 + /**
151 + * Get the root elements for JSON-endpoint.
152 + *
153 + * @since ?
154 + *
155 + * @access public
156 + */
157 + public function getJsonRoots() {
158 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
159 +
160 + $params = wp_parse_args( $_POST['params'] );
161 +
162 + $source = new Visualizer_Source_Json( $params );
163 +
164 + $roots = $source->fetchRoots();
165 + if ( empty( $roots ) ) {
166 + wp_send_json_error( array( 'msg' => $source->get_error() ) );
167 + }
168 +
169 + wp_send_json_success( array( 'url' => $params['url'], 'roots' => $roots ) );
170 + }
171 +
172 + /**
173 + * Get the data for the JSON-endpoint corresponding to the chosen root.
174 + *
175 + * @since ?
176 + *
177 + * @access public
178 + */
179 + public function getJsonData() {
180 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
181 +
182 + $params = wp_parse_args( $_POST['params'] );
183 +
184 + $chart_id = $params['chart'];
185 +
186 + if ( empty( $chart_id ) ) {
187 + wp_die();
188 + }
189 +
190 + $source = new Visualizer_Source_Json( $params );
191 + $source->fetch();
192 + $data = $source->getRawData();
193 +
194 + if ( empty( $data ) ) {
195 + wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
196 + }
197 +
198 + $data = Visualizer_Render_Layout::show( 'editor-table', $data, $chart_id, 'viz-json-table', false, false );
199 + wp_send_json_success( array( 'table' => $data, 'root' => $params['root'], 'url' => $params['url'], 'paging' => $source->getPaginationElements() ) );
200 + }
201 +
202 + /**
203 + * Updates the database with the correct post parameters for JSON-endpoint charts.
204 + *
205 + * @since ?
206 + *
207 + * @access public
208 + */
209 + public function setJsonData() {
210 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_DATA . Visualizer_Plugin::VERSION, 'security' );
211 +
212 + $params = $_POST;
213 + $chart_id = $_GET['chart'];
214 +
215 + if ( empty( $chart_id ) ) {
216 + wp_die();
217 + }
218 +
219 + $chart = get_post( $chart_id );
220 +
221 + $source = new Visualizer_Source_Json( $params );
222 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true );
223 + $source->fetchFromEditableTable();
224 +
225 + $content = $source->getData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
226 + $chart->post_content = $content;
227 + wp_update_post( $chart->to_array() );
228 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
229 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
230 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
231 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_URL, $params['url'] );
232 + update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_ROOT, $params['root'] );
233 +
234 + delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS );
235 + $headers = array( 'method' => $params['method'] );
236 + if ( ! empty( $params['auth'] ) ) {
237 + $headers['auth'] = $params['auth'];
238 + } elseif ( ! empty( $params['username'] ) && ! empty( $params['password'] ) ) {
239 + $headers['auth'] = array( 'username' => $params['username'], 'password' => $params['password'] );
240 + }
241 +
242 + add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS, $headers );
243 +
244 + delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING );
245 + if ( ! empty( $params['paging'] ) ) {
246 + add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
247 + }
248 +
249 + $time = filter_input(
250 + INPUT_POST,
251 + 'time',
252 + FILTER_VALIDATE_INT,
253 + array(
254 + 'options' => array(
255 + 'min_range' => -1,
256 + ),
257 + )
258 + );
259 +
260 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
261 +
262 + if ( -1 < $time ) {
263 + add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
264 + }
265 +
266 + // delete other source specific parameters.
267 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
268 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
269 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_URL );
270 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_SCHEDULE );
271 +
272 + $render = new Visualizer_Render_Page_Update();
273 + $render->id = $chart->ID;
274 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
275 + $render->series = json_encode( $source->getSeries() );
276 + $render->render();
277 +
278 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
279 + }
280 +
281 +
282 + /**
68 283 * Fetches charts from database.
69 284 *
70 285 * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
71 286 *
@@ -94,9 +309,9 @@
94 309 // 'filter' is from the modal from the add media button.
95 310 $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
96 311 }
97 312
98 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
313 + if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
99 314 $query_args['meta_query'] = array(
100 315 array(
101 316 'key' => Visualizer_Plugin::CF_CHART_TYPE,
102 317 'value' => $filter,
@@ -147,9 +362,9 @@
147 362 $chart = $this->_chart;
148 363 }
149 364 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
150 365 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
151 - $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( $chart->post_content ), $chart->ID, $type );
366 + $data = self::get_chart_data( $chart, $type );
152 367 $library = $this->load_chart_type( $chart->ID );
153 368
154 369 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
155 370 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
@@ -201,9 +416,9 @@
201 416 *
202 417 * @access public
203 418 */
204 419 public function deleteChart() {
205 - $is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
420 + $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
206 421 $input_method = $is_post ? INPUT_POST : INPUT_GET;
207 422 $chart_id = $success = false;
208 423 $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
209 424 $capable = current_user_can( 'delete_posts' );
@@ -219,9 +434,9 @@
219 434 )
220 435 );
221 436 if ( $chart_id ) {
222 437 $chart = get_post( $chart_id );
223 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
438 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
224 439 }
225 440 }
226 441 if ( $success ) {
227 442 wp_delete_post( $chart_id, true );
@@ -232,9 +447,9 @@
232 447 'success' => $success,
233 448 )
234 449 );
235 450 }
236 - wp_redirect( wp_get_referer() );
451 + wp_redirect( remove_query_arg( 'vaction', wp_get_referer() ) );
237 452 exit;
238 453 }
239 454
240 455 /**
@@ -274,11 +489,13 @@
274 489 * @access public
275 490 */
276 491 public function renderChartPages() {
277 492 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
493 + // Set current screen for the render chart.
494 + set_current_screen( 'visualizer_render_chart' );
278 495 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
279 496 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
280 - if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
497 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
281 498 $this->deleteOldCharts();
282 499 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
283 500 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
284 501 $source->fetch();
@@ -287,9 +504,9 @@
287 504 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
288 505 'post_title' => 'Visualization',
289 506 'post_author' => get_current_user_id(),
290 507 'post_status' => 'auto-draft',
291 - 'post_content' => $source->getData(),
508 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
292 509 )
293 510 );
294 511 if ( $chart_id && ! is_wp_error( $chart_id ) ) {
295 512 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
@@ -295,8 +512,9 @@
295 512 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
296 513 add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
297 514 add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
298 515 add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
516 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
299 517 add_post_meta(
300 518 $chart_id,
301 519 Visualizer_Plugin::CF_SETTINGS,
302 520 array(
@@ -308,16 +526,23 @@
308 526 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
309 527 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
310 528 }
311 529
312 - $this->load_chart_type( $chart_id );
530 + $lib = $this->load_chart_type( $chart_id );
313 531
532 + // the alpha color picker (RGBA) is not supported by google.
533 + $color_picker_dep = 'wp-color-picker';
534 + if ( in_array( $lib, array( 'chartjs', 'datatables' ), true ) && ! wp_script_is( 'wp-color-picker-alpha', 'registered' ) ) {
535 + wp_register_script( 'wp-color-picker-alpha', VISUALIZER_ABSURL . 'js/lib/wp-color-picker-alpha.min.js', array( 'wp-color-picker' ), Visualizer_Plugin::VERSION );
536 + $color_picker_dep = 'wp-color-picker-alpha';
537 + }
538 +
314 539 // enqueue and register scripts and styles
315 540 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
316 541 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
317 542
318 543 wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
319 - wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION, true );
544 + wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion', 'jquery-ui-tabs' ), Visualizer_Plugin::VERSION, true );
320 545 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
321 546 wp_register_script(
322 547 'visualizer-render',
323 548 VISUALIZER_ABSURL . 'js/render-facade.js',
@@ -328,19 +553,23 @@
328 553 wp_register_script(
329 554 'visualizer-preview',
330 555 VISUALIZER_ABSURL . 'js/preview.js',
331 556 array(
332 - 'wp-color-picker',
557 + $color_picker_dep,
333 558 'visualizer-render',
334 559 ),
335 560 Visualizer_Plugin::VERSION,
336 561 true
337 562 );
338 - // added by Ash/Upwork
339 - if ( VISUALIZER_PRO ) {
563 + wp_register_script( 'visualizer-editor-simple', VISUALIZER_ABSURL . 'js/simple-editor.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
564 +
565 + do_action( 'visualizer_add_scripts' );
566 +
567 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
340 568 global $Visualizer_Pro;
341 569 $Visualizer_Pro->_addScriptsAndStyles();
342 570 }
571 +
343 572 // dispatch pages
344 573 $this->_chart = get_post( $chart_id );
345 574 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
346 575
@@ -352,8 +581,9 @@
352 581 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
353 582 // if the cancel button is clicked.
354 583 $this->undoRevisions( $chart_id, true );
355 584 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
585 + $this->handlePermissions();
356 586 // if the save button is clicked.
357 587 $this->undoRevisions( $chart_id, false );
358 588 } else {
359 589 // if the edit button is clicked.
@@ -368,9 +598,9 @@
368 598 case 'visualizer': // fall through.
369 599 $this->_handleTypesPage();
370 600 break;
371 601 default:
372 - do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
602 + // this should never happen.
373 603 break;
374 604 }
375 605 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
376 606 }
@@ -377,25 +607,26 @@
377 607
378 608 /**
379 609 * Load code editor assets.
380 610 */
381 - private function loadCodeEditorAssets() {
611 + private function loadCodeEditorAssets( $chart_id ) {
382 612 global $wp_version;
383 613
384 - if ( ! VISUALIZER_PRO ) {
614 + $wp_scripts = wp_scripts();
615 +
616 + // data tables assets.
617 + wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
618 + wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
619 + 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 );
620 + wp_enqueue_script( 'visualizer-datatables' );
621 + wp_enqueue_style( 'visualizer-jquery-ui' );
622 +
623 + if ( ! Visualizer_Module::is_pro() ) {
385 624 return;
386 625 }
387 626
388 - $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping();
627 + $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping( $chart_id );
389 628
390 - // data tables assets.
391 - wp_register_script( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
392 - wp_register_style( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css', array(), Visualizer_Plugin::VERSION );
393 - wp_register_style( 'visualizer-datatables-ui', '//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css', array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
394 -
395 - wp_enqueue_script( 'visualizer-datatables' );
396 - wp_enqueue_style( 'visualizer-datatables-ui' );
397 -
398 629 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
399 630 // code mirror assets.
400 631 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
401 632 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
@@ -429,8 +660,25 @@
429 660 return $table_col_mapping;
430 661 }
431 662
432 663 /**
664 + * Handle permissions from the new conslidated settings sidebar.
665 + */
666 + private function handlePermissions() {
667 + if ( ! Visualizer_Module::is_pro() ) {
668 + return;
669 + }
670 +
671 + // we will not support old free and new pro.
672 + // handling new free and old pro.
673 + if ( has_action( 'visualizer_pro_handle_tab' ) ) {
674 + do_action( 'visualizer_pro_handle_tab', 'permissions', $this->_chart );
675 + } else {
676 + do_action( 'visualizer_handle_permissions', $this->_chart );
677 + }
678 + }
679 +
680 + /**
433 681 * Handle data and settings page
434 682 */
435 683 private function _handleDataAndSettingsPage() {
436 684 if ( isset( $_POST['map_api_key'] ) ) {
@@ -435,30 +683,47 @@
435 683 private function _handleDataAndSettingsPage() {
436 684 if ( isset( $_POST['map_api_key'] ) ) {
437 685 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
438 686 }
439 - if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
440 - if ( $this->_chart->post_status == 'auto-draft' ) {
687 +
688 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
689 + if ( $this->_chart->post_status === 'auto-draft' ) {
441 690 $this->_chart->post_status = 'publish';
442 691
443 692 // 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.
444 693 // we do not want any difference in data so disable revisions temporarily.
445 - add_filter( 'wp_revisions_to_keep', '__return_false' );
694 + $this->disableRevisionsTemporarily();
695 +
446 696 wp_update_post( $this->_chart->to_array() );
447 697 }
448 698 // save meta data only when it is NOT being canceled.
449 699 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
450 700 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
701 +
702 + // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
703 + // this will help in searching with the chart id.
704 + $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
705 + $title = null;
706 + if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
707 + $title = $settings['title'];
708 + if ( is_array( $title ) ) {
709 + $title = $settings['title']['text'];
710 + }
711 + }
712 + if ( empty( $title ) ) {
713 + $title = $this->_chart->ID;
714 + }
715 + $settings['internal_title'] = $title;
716 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
451 717 }
452 718 $render = new Visualizer_Render_Page_Send();
453 719 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
454 720 wp_iframe( array( $render, 'render' ) );
455 -
456 721 return;
457 722 }
458 723 $data = $this->_getChartArray();
459 724 $sidebar = '';
460 - $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
725 + $sidebar_class = $this->load_chart_class_name( $this->_chart->ID );
461 726 if ( class_exists( $sidebar_class, true ) ) {
462 727 $sidebar = new $sidebar_class( $data['settings'] );
463 728 $sidebar->__series = $data['series'];
464 729 $sidebar->__data = $data['data'];
@@ -463,14 +728,14 @@
463 728 $sidebar->__series = $data['series'];
464 729 $sidebar->__data = $data['data'];
465 730 } else {
466 731 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
467 - if ( $sidebar != '' ) {
732 + if ( $sidebar !== '' ) {
468 733 $sidebar->__series = $data['series'];
469 734 $sidebar->__data = $data['data'];
470 735 }
471 736 }
472 - unset( $data['settings']['width'], $data['settings']['height'] );
737 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
473 738 wp_enqueue_style( 'wp-color-picker' );
474 739 wp_enqueue_style( 'visualizer-frame' );
475 740 wp_enqueue_script( 'visualizer-preview' );
476 741 wp_enqueue_script( 'visualizer-chosen' );
@@ -475,17 +740,37 @@
475 740 wp_enqueue_script( 'visualizer-preview' );
476 741 wp_enqueue_script( 'visualizer-chosen' );
477 742 wp_enqueue_script( 'visualizer-render' );
478 743
479 - $table_col_mapping = $this->loadCodeEditorAssets();
744 + if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
745 + wp_enqueue_script( 'visualizer-editor-simple' );
746 + wp_localize_script(
747 + 'visualizer-editor-simple',
748 + 'visualizer1',
749 + array(
750 + 'ajax' => array(
751 + 'url' => admin_url( 'admin-ajax.php' ),
752 + 'nonces' => array(
753 + ),
754 + 'actions' => array(
755 + ),
756 + ),
757 + )
758 + );
759 + }
480 760
761 + $table_col_mapping = $this->loadCodeEditorAssets( $this->_chart->ID );
762 +
481 763 wp_localize_script(
482 764 'visualizer-render',
483 765 'visualizer',
484 766 array(
485 767 'l10n' => array(
486 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
768 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
487 769 'loading' => esc_html__( 'Loading...', 'visualizer' ),
770 + 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
771 + 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
772 + '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' ),
488 773 ),
489 774 'charts' => array(
490 775 'canvas' => $data,
491 776 'id' => $this->_chart->ID,
@@ -496,19 +781,28 @@
496 781 'url' => admin_url( 'admin-ajax.php' ),
497 782 'nonces' => array(
498 783 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
499 784 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
785 + 'json_get_roots' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION ),
786 + 'json_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION ),
787 + 'json_set_schedule' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION ),
500 788 ),
501 789 'actions' => array(
502 790 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
503 791 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
792 + 'json_get_roots' => Visualizer_Plugin::ACTION_JSON_GET_ROOTS,
793 + 'json_get_data' => Visualizer_Plugin::ACTION_JSON_GET_DATA,
794 + 'json_set_schedule' => Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE,
504 795 ),
505 796 ),
506 797 'db_query' => array(
507 798 'tables' => $table_col_mapping,
508 799 ),
509 - 'is_pro' => VISUALIZER_PRO,
800 + 'is_pro' => Visualizer_Module::is_pro(),
510 801 'page_type' => 'chart',
802 + 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
803 + 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
804 + 'is_front' => false,
511 805 )
512 806 );
513 807
514 808 $render = new Visualizer_Render_Page_Data();
@@ -516,21 +810,25 @@
516 810 $render->type = $data['type'];
517 811 $render->custom_css = $data['css'];
518 812 $render->sidebar = $sidebar;
519 813 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
520 - $render->button = filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART
814 + $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
521 815 ? esc_html__( 'Save Chart', 'visualizer' )
522 816 : esc_html__( 'Create Chart', 'visualizer' );
523 - if ( filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART ) {
817 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
524 818 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
525 819 }
526 820 } else {
527 821 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
528 822 }
529 - if ( VISUALIZER_PRO ) {
823 +
824 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
825 +
826 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
530 827 global $Visualizer_Pro;
531 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
828 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
532 829 }
830 +
533 831 $this->_addAction( 'admin_head', 'renderFlattrScript' );
534 832 wp_iframe( array( $render, 'render' ) );
535 833 }
536 834
@@ -542,21 +840,32 @@
542 840 * @access private
543 841 */
544 842 private function _handleTypesPage() {
545 843 // process post request
546 - if ( $_SERVER['REQUEST_METHOD'] == 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
844 + if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
547 845 $type = filter_input( INPUT_POST, 'type' );
548 - if ( in_array( $type, Visualizer_Plugin::getChartTypes() ) ) {
846 + $library = filter_input( INPUT_POST, 'chart-library' );
847 + if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
848 + if ( empty( $library ) ) {
849 + // library cannot be empty.
850 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
851 + return;
852 + }
853 +
549 854 // save new chart type
550 855 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
856 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_LIBRARY, $library );
551 857 // if the chart has default data, update it with appropriate default data for new type
552 858 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
553 859 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
554 860 $source->fetch();
555 - $this->_chart->post_content = $source->getData();
861 + $this->_chart->post_content = $source->getData( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
556 862 wp_update_post( $this->_chart->to_array() );
557 863 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
558 864 }
865 +
866 + Visualizer_Module_Utility::set_defaults( $this->_chart );
867 +
559 868 // redirect to next tab
560 869 // changed by Ash/Upwork
561 870 wp_redirect( add_query_arg( 'tab', 'settings' ) );
562 871
@@ -564,9 +873,9 @@
564 873 }
565 874 }
566 875 $render = new Visualizer_Render_Page_Types();
567 876 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
568 - $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
877 + $render->types = Visualizer_Module_Admin::_getChartTypesLocalized( false, false, false, 'types' );
569 878 $render->chart = $this->_chart;
570 879 wp_enqueue_style( 'visualizer-frame' );
571 880 wp_enqueue_script( 'visualizer-frame' );
572 881 wp_iframe( array( $render, 'render' ) );
@@ -582,10 +891,123 @@
582 891 */
583 892 public function renderFlattrScript() {
584 893 echo '';
585 894 }
586 - // changed by Ash/Upwork
895 +
587 896 /**
897 + * Processes the CSV that is sent in the request as a string.
898 + *
899 + * @since 3.2.0
900 + */
901 + private function handleCSVasString( $data, $editor_type ) {
902 + $source = null;
903 +
904 + switch ( $editor_type ) {
905 + case 'text':
906 + // data coming in from the text editor.
907 + $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
908 + $handle = fopen( $tmpfile, 'w' );
909 + $values = preg_split( '/[\n\r]+/', stripslashes( trim( $data ) ) );
910 + if ( $values ) {
911 + foreach ( $values as $row ) {
912 + if ( empty( $row ) ) {
913 + continue;
914 + }
915 + // don't use fpucsv here because we need to just dump the data
916 + // minus the empty rows
917 + // because fputcsv needs to tokenize
918 + // we can standardize the CSV enclosure here and replace all ' with "
919 + // we can assume that if there are an even number of ' they should be changed to "
920 + // but that will screw up words like fo'c'sle
921 + // so here let's just assume ' will NOT be used for enclosures
922 + fwrite( $handle, $row );
923 + fwrite( $handle, PHP_EOL );
924 + }
925 + }
926 + $source = new Visualizer_Source_Csv( $tmpfile );
927 + fclose( $handle );
928 + break;
929 + case 'table':
930 + // Import from Chart
931 + // fall-through.
932 + case 'excel':
933 + // data coming in from the excel editor.
934 + $source = apply_filters( 'visualizer_pro_handle_chart_data', $data, '' );
935 + break;
936 + }
937 + return $source;
938 + }
939 +
940 + /**
941 + * Parses the data uploaded as an HTML table.
942 + *
943 + * @since 3.2.0
944 + *
945 + * @access private
946 + */
947 + private function handleTabularData() {
948 + $csv = array();
949 + // the datatable mentions the headers twice, so lets remove the duplicates.
950 + $headers = array_unique( array_filter( $_POST['header'] ) );
951 + $types = $_POST['type'];
952 +
953 + // capture all the indexes that correspond to excluded columns.
954 + $exclude = array();
955 + $index = 0;
956 + foreach ( $types as $type ) {
957 + if ( empty( $type ) ) {
958 + $exclude[] = $index;
959 + }
960 + $index++;
961 + }
962 +
963 + // when N headers are being renamed, the number of headers increases by N
964 + // because of the way datatable duplicates header information
965 + // so unset the headers that have been renamed.
966 + if ( count( $headers ) !== count( $types ) ) {
967 + $to = count( $headers );
968 + for ( $i = count( $types ); $i < $to; $i++ ) {
969 + unset( $headers[ $i + 1 ] );
970 + }
971 + }
972 +
973 + $columns = array();
974 + for ( $i = 0; $i < count( $headers ); $i++ ) {
975 + if ( ! isset( $_POST[ 'data' . $i ] ) ) {
976 + continue;
977 + }
978 + $columns[ $i ] = $_POST[ 'data' . $i ];
979 + }
980 +
981 + $csv[] = $headers;
982 + $csv[] = $types;
983 + for ( $j = 0; $j < count( $columns[0] ); $j++ ) {
984 + $row = array();
985 + for ( $i = 0; $i < count( $headers ); $i++ ) {
986 + $row[] = sanitize_text_field( $columns[ $i ][ $j ] );
987 + }
988 + $csv[] = $row;
989 + }
990 +
991 + $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
992 + $handle = fopen( $tmpfile, 'w' );
993 +
994 + if ( $csv ) {
995 + $index = 0;
996 + foreach ( $csv as $row ) {
997 + // remove all the cells corresponding to the excluded headers.
998 + foreach ( $exclude as $j ) {
999 + unset( $row[ $j ] );
1000 + }
1001 + fputcsv( $handle, $row );
1002 + }
1003 + }
1004 + $source = new Visualizer_Source_Csv( $tmpfile );
1005 + fclose( $handle );
1006 + return $source;
1007 + }
1008 +
1009 + /**
588 1010 * Parses uploaded CSV file and saves new data for the chart.
589 1011 *
590 1012 * @since 1.0.0
591 1013 *
@@ -607,9 +1029,9 @@
607 1029
608 1030 // check chart, if chart exists
609 1031 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
610 1032 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
611 - if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
1033 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
612 1034 if ( ! $can_die ) {
613 1035 return;
614 1036 }
615 1037 status_header( 400 );
@@ -615,8 +1037,10 @@
615 1037 status_header( 400 );
616 1038 exit;
617 1039 }
618 1040
1041 + 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__ );
1042 +
619 1043 if ( ! isset( $_POST['vz-import-time'] ) ) {
620 1044 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
621 1045 }
622 1046
@@ -628,10 +1052,26 @@
628 1052
629 1053 // delete "import from db" specific parameters.
630 1054 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
631 1055 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
1056 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS );
632 1057 }
633 1058
1059 + // delete json related data.
1060 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL );
1061 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT );
1062 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING );
1063 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_HEADERS );
1064 +
1065 + // delete last error
1066 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR );
1067 +
1068 + // delete editor related data.
1069 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR );
1070 +
1071 + // delete this so that a JSON import can be later edited manually without a problem.
1072 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1073 +
634 1074 $source = null;
635 1075 $render = new Visualizer_Render_Page_Update();
636 1076 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
637 1077 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
@@ -637,18 +1077,28 @@
637 1077 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
638 1078 if ( isset( $_POST['vz-import-time'] ) ) {
639 1079 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
640 1080 }
1081 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
641 1082 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
642 1083 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
643 1084 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
644 - $source = apply_filters( 'visualizer_pro_handle_chart_data', $_POST['chart_data'], '', $chart_id, $_POST );
1085 + $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1086 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1087 + } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
1088 + $source = $this->handleTabularData();
1089 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
645 1090 } else {
646 - $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
1091 + 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__ );
1092 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1093 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
647 1094 }
1095 +
1096 + 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__ );
1097 +
648 1098 if ( $source ) {
649 1099 if ( $source->fetch() ) {
650 - $content = $source->getData();
1100 + $content = $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
651 1101 $populate = true;
652 1102 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
653 1103 $json = unserialize( $content );
654 1104 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
@@ -654,8 +1104,9 @@
654 1104 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
655 1105 // if we populate the data even if it is empty, the chart will show "Table has no columns".
656 1106 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
657 1107 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__ );
1108 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ) );
658 1109 $populate = false;
659 1110 }
660 1111 }
661 1112 if ( $populate ) {
@@ -664,14 +1115,30 @@
664 1115 wp_update_post( $chart->to_array() );
665 1116 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
666 1117 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
667 1118 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1119 +
1120 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Updated post for chart %d', $chart_id ), 'debug', __FILE__, __LINE__ );
1121 +
1122 + Visualizer_Module_Utility::set_defaults( $chart, null );
1123 +
1124 + $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1125 +
668 1126 $render->id = $chart->ID;
669 - $render->data = json_encode( $source->getRawData() );
1127 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
670 1128 $render->series = json_encode( $source->getSeries() );
1129 + $render->settings = json_encode( $settings );
671 1130 } else {
672 - $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
1131 + $error = $source->get_error();
1132 + if ( empty( $error ) ) {
1133 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1134 + }
1135 + $render->message = $error;
1136 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1137 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
673 1138 }
1139 + } else {
1140 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
674 1141 }
675 1142 $render->render();
676 1143 if ( ! $can_die ) {
677 1144 return;
@@ -687,27 +1154,18 @@
687 1154 * @access public
688 1155 */
689 1156 public function cloneChart() {
690 1157 $chart_id = $success = false;
691 - $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
1158 + $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
692 1159 $capable = current_user_can( 'edit_posts' );
693 1160 if ( $nonce && $capable ) {
694 - $chart_id = filter_input(
695 - INPUT_GET,
696 - 'chart',
697 - FILTER_VALIDATE_INT,
698 - array(
699 - 'options' => array(
700 - 'min_range' => 1,
701 - ),
702 - )
703 - );
1161 + $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
704 1162 if ( $chart_id ) {
705 1163 $chart = get_post( $chart_id );
706 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1164 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
707 1165 }
708 1166 }
709 - $redirect = wp_get_referer();
1167 + $redirect = remove_query_arg( 'vaction', wp_get_referer() );
710 1168 if ( $success ) {
711 1169 $new_chart_id = wp_insert_post(
712 1170 array(
713 1171 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
@@ -716,23 +1174,32 @@
716 1174 'post_status' => $chart->post_status,
717 1175 'post_content' => $chart->post_content,
718 1176 )
719 1177 );
720 - if ( $new_chart_id && ! is_wp_error( $new_chart_id ) ) {
721 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_CHART_TYPE, get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true ) );
722 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, get_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, true ) );
723 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SOURCE, get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true ) );
724 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SERIES, get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true ) );
725 - add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SETTINGS, get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) );
1178 + if ( is_wp_error( $new_chart_id ) ) {
1179 + 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__ );
1180 + } else {
1181 + $post_meta = get_post_meta( $chart_id );
1182 + foreach ( $post_meta as $key => $value ) {
1183 + if ( strpos( $key, 'visualizer-' ) !== false ) {
1184 + add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1185 + }
1186 + }
726 1187 $redirect = add_query_arg(
727 1188 array(
728 1189 'page' => 'visualizer',
729 1190 'type' => filter_input( INPUT_GET, 'type' ),
1191 + 'vaction' => false,
730 1192 ),
731 - admin_url( 'upload.php' )
1193 + admin_url( 'admin.php' )
732 1194 );
733 1195 }
734 1196 }
1197 +
1198 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1199 + wp_die();
1200 + }
1201 +
735 1202 wp_redirect( $redirect );
736 1203 exit;
737 1204 }
738 1205
@@ -778,9 +1245,12 @@
778 1245 $data = $this->_getChartArray();
779 1246 $render = new Visualizer_Render_Page_Data();
780 1247 $render->chart = $this->_chart;
781 1248 $render->type = $data['type'];
782 - unset( $data['settings']['width'], $data['settings']['height'] );
1249 +
1250 + if ( $data && $data['settings'] ) {
1251 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1252 + }
783 1253 wp_enqueue_style( 'visualizer-frame' );
784 1254 wp_enqueue_script( 'visualizer-render' );
785 1255 wp_localize_script(
786 1256 'visualizer-render',
@@ -786,9 +1256,9 @@
786 1256 'visualizer-render',
787 1257 'visualizer',
788 1258 array(
789 1259 'l10n' => array(
790 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1260 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
791 1261 'loading' => esc_html__( 'Loading...', 'visualizer' ),
792 1262 ),
793 1263 'charts' => array(
794 1264 'canvas' => $data,
@@ -794,13 +1264,16 @@
794 1264 'canvas' => $data,
795 1265 ),
796 1266 )
797 1267 );
798 - // Added by Ash/Upwork
799 - if ( VISUALIZER_PRO ) {
1268 +
1269 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
1270 +
1271 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
800 1272 global $Visualizer_Pro;
801 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1273 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
802 1274 }
1275 +
803 1276 // Added by Ash/Upwork
804 1277 $this->_addAction( 'admin_head', 'renderFlattrScript' );
805 1278 wp_iframe( array( $render, 'render' ) );
806 1279 }
@@ -813,13 +1286,14 @@
813 1286 public function getQueryData() {
814 1287 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
815 1288
816 1289 $params = wp_parse_args( $_POST['params'] );
817 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1290 + $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1291 +
1292 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
818 1293 $html = $source->fetch( true );
819 - $error = '';
820 - if ( empty( $html ) ) {
821 - $error = $source->get_error();
1294 + $error = $source->get_error();
1295 + if ( ! empty( $error ) ) {
822 1296 wp_send_json_error( array( 'msg' => $error ) );
823 1297 }
824 1298 wp_send_json_success( array( 'table' => $html ) );
825 1299 }
@@ -842,21 +1316,42 @@
842 1316 ),
843 1317 )
844 1318 );
845 1319
1320 + $hours = filter_input(
1321 + INPUT_POST,
1322 + 'refresh',
1323 + FILTER_VALIDATE_INT,
1324 + array(
1325 + 'options' => array(
1326 + 'min_range' => -1,
1327 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1328 + ),
1329 + )
1330 + );
1331 +
1332 + if ( ! is_int( $hours ) ) {
1333 + $hours = -1;
1334 + }
1335 +
846 1336 $render = new Visualizer_Render_Page_Update();
847 1337 if ( $chart_id ) {
848 1338 $params = wp_parse_args( $_POST['params'] );
849 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1339 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
850 1340 $source->fetch( false );
851 1341 $error = $source->get_error();
852 1342 if ( empty( $error ) ) {
853 - $hours = $_POST['refresh'];
854 1343 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
855 1344 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
856 1345 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
857 1346 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
858 1347 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1348 + if ( isset( $params['db_type'] ) && $params['db_type'] !== Visualizer_Plugin::WP_DB_NAME ) {
1349 + $remote_db_params = $params;
1350 + unset( $remote_db_params['query'] );
1351 + unset( $remote_db_params['chart_id'] );
1352 + update_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS, $remote_db_params );
1353 + }
859 1354
860 1355 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
861 1356 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
862 1357 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
@@ -863,13 +1358,14 @@
863 1358
864 1359 wp_update_post(
865 1360 array(
866 1361 'ID' => $chart_id,
867 - 'post_content' => $source->getData(),
1362 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
868 1363 )
869 1364 );
870 - $render->data = json_encode( $source->getRawData() );
1365 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
871 1366 $render->series = json_encode( $source->getSeries() );
1367 + $render->id = $chart_id;
872 1368 } else {
873 1369 $render->message = $error;
874 1370 }
875 1371 }
@@ -898,9 +1394,23 @@
898 1394 ),
899 1395 )
900 1396 );
901 1397
902 - $hours = $_POST['refresh'];
1398 + $hours = filter_input(
1399 + INPUT_POST,
1400 + 'refresh',
1401 + FILTER_VALIDATE_INT,
1402 + array(
1403 + 'options' => array(
1404 + 'min_range' => -1,
1405 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1406 + ),
1407 + )
1408 + );
1409 +
1410 + if ( 0 !== $hours && empty( $hours ) ) {
1411 + $hours = -1;
1412 + }
903 1413
904 1414 do_action( 'visualizer_save_filter', $chart_id, $hours );
905 1415
906 1416 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {