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