PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.8
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.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 3.10.4 All 148 releases
← All changes | classes/Visualizer/Module/Chart.php +587 -83 3.1.33.4.8 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,26 @@
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 +
1065 + // delete this so that a JSON import can be later edited manually without a problem.
1066 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1067 +
634 1068 $source = null;
635 1069 $render = new Visualizer_Render_Page_Update();
636 1070 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
637 1071 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
@@ -637,18 +1071,28 @@
637 1071 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
638 1072 if ( isset( $_POST['vz-import-time'] ) ) {
639 1073 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
640 1074 }
1075 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
641 1076 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
642 1077 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
643 1078 } 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 );
1079 + $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1080 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1081 + } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
1082 + $source = $this->handleTabularData();
1083 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
645 1084 } else {
646 - $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
1085 + 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__ );
1086 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1087 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
647 1088 }
1089 +
1090 + 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__ );
1091 +
648 1092 if ( $source ) {
649 1093 if ( $source->fetch() ) {
650 - $content = $source->getData();
1094 + $content = $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
651 1095 $populate = true;
652 1096 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
653 1097 $json = unserialize( $content );
654 1098 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
@@ -654,8 +1098,9 @@
654 1098 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
655 1099 // if we populate the data even if it is empty, the chart will show "Table has no columns".
656 1100 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
657 1101 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__ );
1102 + 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 1103 $populate = false;
659 1104 }
660 1105 }
661 1106 if ( $populate ) {
@@ -664,14 +1109,30 @@
664 1109 wp_update_post( $chart->to_array() );
665 1110 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
666 1111 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
667 1112 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1113 +
1114 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Updated post for chart %d', $chart_id ), 'debug', __FILE__, __LINE__ );
1115 +
1116 + Visualizer_Module_Utility::set_defaults( $chart, null );
1117 +
1118 + $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1119 +
668 1120 $render->id = $chart->ID;
669 - $render->data = json_encode( $source->getRawData() );
1121 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
670 1122 $render->series = json_encode( $source->getSeries() );
1123 + $render->settings = json_encode( $settings );
671 1124 } else {
672 - $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
1125 + $error = $source->get_error();
1126 + if ( empty( $error ) ) {
1127 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1128 + }
1129 + $render->message = $error;
1130 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1131 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
673 1132 }
1133 + } else {
1134 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
674 1135 }
675 1136 $render->render();
676 1137 if ( ! $can_die ) {
677 1138 return;
@@ -687,27 +1148,18 @@
687 1148 * @access public
688 1149 */
689 1150 public function cloneChart() {
690 1151 $chart_id = $success = false;
691 - $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
1152 + $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
692 1153 $capable = current_user_can( 'edit_posts' );
693 1154 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 - );
1155 + $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
704 1156 if ( $chart_id ) {
705 1157 $chart = get_post( $chart_id );
706 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1158 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
707 1159 }
708 1160 }
709 - $redirect = wp_get_referer();
1161 + $redirect = remove_query_arg( 'vaction', wp_get_referer() );
710 1162 if ( $success ) {
711 1163 $new_chart_id = wp_insert_post(
712 1164 array(
713 1165 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
@@ -716,23 +1168,32 @@
716 1168 'post_status' => $chart->post_status,
717 1169 'post_content' => $chart->post_content,
718 1170 )
719 1171 );
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 ) );
1172 + if ( is_wp_error( $new_chart_id ) ) {
1173 + 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__ );
1174 + } else {
1175 + $post_meta = get_post_meta( $chart_id );
1176 + foreach ( $post_meta as $key => $value ) {
1177 + if ( strpos( $key, 'visualizer-' ) !== false ) {
1178 + add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1179 + }
1180 + }
726 1181 $redirect = add_query_arg(
727 1182 array(
728 1183 'page' => 'visualizer',
729 1184 'type' => filter_input( INPUT_GET, 'type' ),
1185 + 'vaction' => false,
730 1186 ),
731 - admin_url( 'upload.php' )
1187 + admin_url( 'admin.php' )
732 1188 );
733 1189 }
734 1190 }
1191 +
1192 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1193 + wp_die();
1194 + }
1195 +
735 1196 wp_redirect( $redirect );
736 1197 exit;
737 1198 }
738 1199
@@ -778,9 +1239,12 @@
778 1239 $data = $this->_getChartArray();
779 1240 $render = new Visualizer_Render_Page_Data();
780 1241 $render->chart = $this->_chart;
781 1242 $render->type = $data['type'];
782 - unset( $data['settings']['width'], $data['settings']['height'] );
1243 +
1244 + if ( $data && $data['settings'] ) {
1245 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1246 + }
783 1247 wp_enqueue_style( 'visualizer-frame' );
784 1248 wp_enqueue_script( 'visualizer-render' );
785 1249 wp_localize_script(
786 1250 'visualizer-render',
@@ -786,9 +1250,9 @@
786 1250 'visualizer-render',
787 1251 'visualizer',
788 1252 array(
789 1253 'l10n' => array(
790 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1254 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
791 1255 'loading' => esc_html__( 'Loading...', 'visualizer' ),
792 1256 ),
793 1257 'charts' => array(
794 1258 'canvas' => $data,
@@ -794,13 +1258,16 @@
794 1258 'canvas' => $data,
795 1259 ),
796 1260 )
797 1261 );
798 - // Added by Ash/Upwork
799 - if ( VISUALIZER_PRO ) {
1262 +
1263 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
1264 +
1265 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
800 1266 global $Visualizer_Pro;
801 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1267 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
802 1268 }
1269 +
803 1270 // Added by Ash/Upwork
804 1271 $this->_addAction( 'admin_head', 'renderFlattrScript' );
805 1272 wp_iframe( array( $render, 'render' ) );
806 1273 }
@@ -813,13 +1280,14 @@
813 1280 public function getQueryData() {
814 1281 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
815 1282
816 1283 $params = wp_parse_args( $_POST['params'] );
817 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1284 + $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1285 +
1286 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
818 1287 $html = $source->fetch( true );
819 - $error = '';
820 - if ( empty( $html ) ) {
821 - $error = $source->get_error();
1288 + $error = $source->get_error();
1289 + if ( ! empty( $error ) ) {
822 1290 wp_send_json_error( array( 'msg' => $error ) );
823 1291 }
824 1292 wp_send_json_success( array( 'table' => $html ) );
825 1293 }
@@ -842,21 +1310,42 @@
842 1310 ),
843 1311 )
844 1312 );
845 1313
1314 + $hours = filter_input(
1315 + INPUT_POST,
1316 + 'refresh',
1317 + FILTER_VALIDATE_INT,
1318 + array(
1319 + 'options' => array(
1320 + 'min_range' => -1,
1321 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1322 + ),
1323 + )
1324 + );
1325 +
1326 + if ( ! is_int( $hours ) ) {
1327 + $hours = -1;
1328 + }
1329 +
846 1330 $render = new Visualizer_Render_Page_Update();
847 1331 if ( $chart_id ) {
848 1332 $params = wp_parse_args( $_POST['params'] );
849 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1333 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
850 1334 $source->fetch( false );
851 1335 $error = $source->get_error();
852 1336 if ( empty( $error ) ) {
853 - $hours = $_POST['refresh'];
854 1337 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
855 1338 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
856 1339 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
857 1340 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
858 1341 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1342 + if ( isset( $params['db_type'] ) && $params['db_type'] !== Visualizer_Plugin::WP_DB_NAME ) {
1343 + $remote_db_params = $params;
1344 + unset( $remote_db_params['query'] );
1345 + unset( $remote_db_params['chart_id'] );
1346 + update_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS, $remote_db_params );
1347 + }
859 1348
860 1349 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
861 1350 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
862 1351 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
@@ -863,13 +1352,14 @@
863 1352
864 1353 wp_update_post(
865 1354 array(
866 1355 'ID' => $chart_id,
867 - 'post_content' => $source->getData(),
1356 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
868 1357 )
869 1358 );
870 - $render->data = json_encode( $source->getRawData() );
1359 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
871 1360 $render->series = json_encode( $source->getSeries() );
1361 + $render->id = $chart_id;
872 1362 } else {
873 1363 $render->message = $error;
874 1364 }
875 1365 }
@@ -898,9 +1388,23 @@
898 1388 ),
899 1389 )
900 1390 );
901 1391
902 - $hours = $_POST['refresh'];
1392 + $hours = filter_input(
1393 + INPUT_POST,
1394 + 'refresh',
1395 + FILTER_VALIDATE_INT,
1396 + array(
1397 + 'options' => array(
1398 + 'min_range' => -1,
1399 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1400 + ),
1401 + )
1402 + );
1403 +
1404 + if ( ! $hours ) {
1405 + $hours = -1;
1406 + }
903 1407
904 1408 do_action( 'visualizer_save_filter', $chart_id, $hours );
905 1409
906 1410 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {