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