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 +651 -83 3.1.03.4.8 View file →
@@ -60,11 +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 +
70 + $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY, 'saveFilter' );
71 +
72 + $this->_addFilter( 'visualizer_get_sidebar', 'getSidebar', 10, 2 );
73 +
64 74 }
65 75
66 76 /**
77 + * Generates the HTML of the sidebar for the chart.
78 + *
79 + * @since ?
80 + *
81 + * @access public
82 + */
83 + public function getSidebar( $sidebar, $chart_id ) {
84 + $chart = get_post( $chart_id );
85 + $data = $this->_getChartArray( $chart );
86 + $sidebar = '';
87 + $sidebar_class = $this->load_chart_class_name( $chart_id );
88 + if ( class_exists( $sidebar_class, true ) ) {
89 + $sidebar = new $sidebar_class( $data['settings'] );
90 + $sidebar->__series = $data['series'];
91 + $sidebar->__data = $data['data'];
92 + } else {
93 + $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
94 + if ( $sidebar !== '' ) {
95 + $sidebar->__series = $data['series'];
96 + $sidebar->__data = $data['data'];
97 + }
98 + }
99 + return str_replace( "'", '"', $sidebar->__toString() );
100 + }
101 +
102 + /**
103 + * Sets the schedule for how JSON-endpoint charts should be updated.
104 + *
105 + * @since ?
106 + *
107 + * @access public
108 + */
109 + public function setJsonSchedule() {
110 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION, 'security' );
111 +
112 + $chart_id = filter_input(
113 + INPUT_POST,
114 + 'chart',
115 + FILTER_VALIDATE_INT,
116 + array(
117 + 'options' => array(
118 + 'min_range' => 1,
119 + ),
120 + )
121 + );
122 +
123 + if ( ! $chart_id ) {
124 + wp_send_json_error();
125 + }
126 +
127 + $time = filter_input(
128 + INPUT_POST,
129 + 'time',
130 + FILTER_VALIDATE_INT,
131 + array(
132 + 'options' => array(
133 + 'min_range' => -1,
134 + ),
135 + )
136 + );
137 +
138 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
139 +
140 + if ( -1 < $time ) {
141 + add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
142 + }
143 + wp_send_json_success();
144 + }
145 +
146 + /**
147 + * Get the root elements for JSON-endpoint.
148 + *
149 + * @since ?
150 + *
151 + * @access public
152 + */
153 + public function getJsonRoots() {
154 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
155 +
156 + $params = wp_parse_args( $_POST['params'] );
157 +
158 + $source = new Visualizer_Source_Json( $params );
159 +
160 + $roots = $source->fetchRoots();
161 + if ( empty( $roots ) ) {
162 + wp_send_json_error( array( 'msg' => $source->get_error() ) );
163 + }
164 +
165 + wp_send_json_success( array( 'url' => $params['url'], 'roots' => $roots ) );
166 + }
167 +
168 + /**
169 + * Get the data for the JSON-endpoint corresponding to the chosen root.
170 + *
171 + * @since ?
172 + *
173 + * @access public
174 + */
175 + public function getJsonData() {
176 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
177 +
178 + $params = wp_parse_args( $_POST['params'] );
179 +
180 + $chart_id = $params['chart'];
181 +
182 + if ( empty( $chart_id ) ) {
183 + wp_die();
184 + }
185 +
186 + $source = new Visualizer_Source_Json( $params );
187 + $source->fetch();
188 + $data = $source->getRawData();
189 +
190 + if ( empty( $data ) ) {
191 + wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
192 + }
193 +
194 + $data = Visualizer_Render_Layout::show( 'editor-table', $data, $chart_id, 'viz-json-table', false, false );
195 + wp_send_json_success( array( 'table' => $data, 'root' => $params['root'], 'url' => $params['url'], 'paging' => $source->getPaginationElements() ) );
196 + }
197 +
198 + /**
199 + * Updates the database with the correct post parameters for JSON-endpoint charts.
200 + *
201 + * @since ?
202 + *
203 + * @access public
204 + */
205 + public function setJsonData() {
206 + check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_DATA . Visualizer_Plugin::VERSION, 'security' );
207 +
208 + $params = $_POST;
209 + $chart_id = $_GET['chart'];
210 +
211 + if ( empty( $chart_id ) ) {
212 + wp_die();
213 + }
214 +
215 + $chart = get_post( $chart_id );
216 +
217 + $source = new Visualizer_Source_Json( $params );
218 + 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 + /**
67 279 * Fetches charts from database.
68 280 *
69 281 * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
70 282 *
@@ -93,9 +305,9 @@
93 305 // 'filter' is from the modal from the add media button.
94 306 $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
95 307 }
96 308
97 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
309 + if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
98 310 $query_args['meta_query'] = array(
99 311 array(
100 312 'key' => Visualizer_Plugin::CF_CHART_TYPE,
101 313 'value' => $filter,
@@ -146,9 +358,9 @@
146 358 $chart = $this->_chart;
147 359 }
148 360 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
149 361 $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 );
362 + $data = self::get_chart_data( $chart, $type );
151 363 $library = $this->load_chart_type( $chart->ID );
152 364
153 365 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
154 366 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
@@ -162,8 +374,10 @@
162 374 $css = $arguments[0];
163 375 $settings = $arguments[1];
164 376 }
165 377
378 + $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
379 +
166 380 return array(
167 381 'type' => $type,
168 382 'series' => $series,
169 383 'settings' => $settings,
@@ -169,8 +383,9 @@
169 383 'settings' => $settings,
170 384 'data' => $data,
171 385 'library' => $library,
172 386 'css' => $css,
387 + 'date_formats' => $date_formats,
173 388 );
174 389 }
175 390
176 391 /**
@@ -197,9 +412,9 @@
197 412 *
198 413 * @access public
199 414 */
200 415 public function deleteChart() {
201 - $is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
416 + $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
202 417 $input_method = $is_post ? INPUT_POST : INPUT_GET;
203 418 $chart_id = $success = false;
204 419 $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
205 420 $capable = current_user_can( 'delete_posts' );
@@ -215,9 +430,9 @@
215 430 )
216 431 );
217 432 if ( $chart_id ) {
218 433 $chart = get_post( $chart_id );
219 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
434 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
220 435 }
221 436 }
222 437 if ( $success ) {
223 438 wp_delete_post( $chart_id, true );
@@ -228,13 +443,41 @@
228 443 'success' => $success,
229 444 )
230 445 );
231 446 }
232 - wp_redirect( wp_get_referer() );
447 + wp_redirect( remove_query_arg( 'vaction', wp_get_referer() ) );
233 448 exit;
234 449 }
235 450
236 451 /**
452 + * Delete charts that are still in auto-draft mode.
453 + */
454 + private function deleteOldCharts() {
455 + $query = new WP_Query(
456 + array(
457 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
458 + 'post_status' => 'auto-draft',
459 + 'fields' => 'ids',
460 + 'update_post_meta_cache' => false,
461 + 'update_post_term_cache' => false,
462 + 'posts_per_page' => 50,
463 + 'date_query' => array(
464 + array(
465 + 'before' => 'today',
466 + ),
467 + ),
468 + )
469 + );
470 +
471 + if ( $query->have_posts() ) {
472 + $ids = array();
473 + while ( $query->have_posts() ) {
474 + wp_delete_post( $query->next_post(), true );
475 + }
476 + }
477 + }
478 +
479 + /**
237 480 * Renders appropriate page for chart builder. Creates new auto draft chart
238 481 * if no chart has been specified.
239 482 *
240 483 * @since 1.0.0
@@ -244,9 +487,10 @@
244 487 public function renderChartPages() {
245 488 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
246 489 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
247 490 $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 ) {
491 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
492 + $this->deleteOldCharts();
249 493 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
250 494 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
251 495 $source->fetch();
252 496 $chart_id = wp_insert_post(
@@ -254,9 +498,9 @@
254 498 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
255 499 'post_title' => 'Visualization',
256 500 'post_author' => get_current_user_id(),
257 501 'post_status' => 'auto-draft',
258 - 'post_content' => $source->getData(),
502 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
259 503 )
260 504 );
261 505 if ( $chart_id && ! is_wp_error( $chart_id ) ) {
262 506 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
@@ -262,8 +506,9 @@
262 506 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
263 507 add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
264 508 add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
265 509 add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
510 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
266 511 add_post_meta(
267 512 $chart_id,
268 513 Visualizer_Plugin::CF_SETTINGS,
269 514 array(
@@ -275,16 +520,23 @@
275 520 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
276 521 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
277 522 }
278 523
279 - $this->load_chart_type( $chart_id );
524 + $lib = $this->load_chart_type( $chart_id );
280 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 +
281 533 // enqueue and register scripts and styles
282 534 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
283 535 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
284 536
285 537 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 );
538 + wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion', 'jquery-ui-tabs' ), Visualizer_Plugin::VERSION, true );
287 539 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
288 540 wp_register_script(
289 541 'visualizer-render',
290 542 VISUALIZER_ABSURL . 'js/render-facade.js',
@@ -295,19 +547,23 @@
295 547 wp_register_script(
296 548 'visualizer-preview',
297 549 VISUALIZER_ABSURL . 'js/preview.js',
298 550 array(
299 - 'wp-color-picker',
551 + $color_picker_dep,
300 552 'visualizer-render',
301 553 ),
302 554 Visualizer_Plugin::VERSION,
303 555 true
304 556 );
305 - // added by Ash/Upwork
306 - 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' ) ) {
307 562 global $Visualizer_Pro;
308 563 $Visualizer_Pro->_addScriptsAndStyles();
309 564 }
565 +
310 566 // dispatch pages
311 567 $this->_chart = get_post( $chart_id );
312 568 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
313 569
@@ -319,8 +575,9 @@
319 575 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
320 576 // if the cancel button is clicked.
321 577 $this->undoRevisions( $chart_id, true );
322 578 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
579 + $this->handlePermissions();
323 580 // if the save button is clicked.
324 581 $this->undoRevisions( $chart_id, false );
325 582 } else {
326 583 // if the edit button is clicked.
@@ -335,9 +592,9 @@
335 592 case 'visualizer': // fall through.
336 593 $this->_handleTypesPage();
337 594 break;
338 595 default:
339 - do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
596 + // this should never happen.
340 597 break;
341 598 }
342 599 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
343 600 }
@@ -344,25 +601,26 @@
344 601
345 602 /**
346 603 * Load code editor assets.
347 604 */
348 - private function loadCodeEditorAssets() {
605 + private function loadCodeEditorAssets( $chart_id ) {
349 606 global $wp_version;
350 607
351 - 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() ) {
352 618 return;
353 619 }
354 620
355 - $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 );
356 622
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 623 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
366 624 // code mirror assets.
367 625 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
368 626 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
@@ -396,8 +654,25 @@
396 654 return $table_col_mapping;
397 655 }
398 656
399 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 + /**
400 675 * Handle data and settings page
401 676 */
402 677 private function _handleDataAndSettingsPage() {
403 678 if ( isset( $_POST['map_api_key'] ) ) {
@@ -402,30 +677,47 @@
402 677 private function _handleDataAndSettingsPage() {
403 678 if ( isset( $_POST['map_api_key'] ) ) {
404 679 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
405 680 }
406 - if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
407 - 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' ) {
408 684 $this->_chart->post_status = 'publish';
409 685
410 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.
411 687 // we do not want any difference in data so disable revisions temporarily.
412 - add_filter( 'wp_revisions_to_keep', '__return_false' );
688 + $this->disableRevisionsTemporarily();
689 +
413 690 wp_update_post( $this->_chart->to_array() );
414 691 }
415 692 // save meta data only when it is NOT being canceled.
416 693 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
417 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 );
418 711 }
419 712 $render = new Visualizer_Render_Page_Send();
420 713 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
421 714 wp_iframe( array( $render, 'render' ) );
422 -
423 715 return;
424 716 }
425 717 $data = $this->_getChartArray();
426 718 $sidebar = '';
427 - $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
719 + $sidebar_class = $this->load_chart_class_name( $this->_chart->ID );
428 720 if ( class_exists( $sidebar_class, true ) ) {
429 721 $sidebar = new $sidebar_class( $data['settings'] );
430 722 $sidebar->__series = $data['series'];
431 723 $sidebar->__data = $data['data'];
@@ -430,14 +722,14 @@
430 722 $sidebar->__series = $data['series'];
431 723 $sidebar->__data = $data['data'];
432 724 } else {
433 725 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
434 - if ( $sidebar != '' ) {
726 + if ( $sidebar !== '' ) {
435 727 $sidebar->__series = $data['series'];
436 728 $sidebar->__data = $data['data'];
437 729 }
438 730 }
439 - unset( $data['settings']['width'], $data['settings']['height'] );
731 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
440 732 wp_enqueue_style( 'wp-color-picker' );
441 733 wp_enqueue_style( 'visualizer-frame' );
442 734 wp_enqueue_script( 'visualizer-preview' );
443 735 wp_enqueue_script( 'visualizer-chosen' );
@@ -442,17 +734,37 @@
442 734 wp_enqueue_script( 'visualizer-preview' );
443 735 wp_enqueue_script( 'visualizer-chosen' );
444 736 wp_enqueue_script( 'visualizer-render' );
445 737
446 - $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 + }
447 754
755 + $table_col_mapping = $this->loadCodeEditorAssets( $this->_chart->ID );
756 +
448 757 wp_localize_script(
449 758 'visualizer-render',
450 759 'visualizer',
451 760 array(
452 761 'l10n' => array(
453 - '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' ),
454 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' ),
455 767 ),
456 768 'charts' => array(
457 769 'canvas' => $data,
458 770 'id' => $this->_chart->ID,
@@ -463,19 +775,28 @@
463 775 'url' => admin_url( 'admin-ajax.php' ),
464 776 'nonces' => array(
465 777 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
466 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 ),
467 782 ),
468 783 'actions' => array(
469 784 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
470 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,
471 789 ),
472 790 ),
473 791 'db_query' => array(
474 792 'tables' => $table_col_mapping,
475 793 ),
476 - 'is_pro' => VISUALIZER_PRO,
794 + 'is_pro' => Visualizer_Module::is_pro(),
477 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,
478 799 )
479 800 );
480 801
481 802 $render = new Visualizer_Render_Page_Data();
@@ -483,21 +804,25 @@
483 804 $render->type = $data['type'];
484 805 $render->custom_css = $data['css'];
485 806 $render->sidebar = $sidebar;
486 807 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
487 - $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
488 809 ? esc_html__( 'Save Chart', 'visualizer' )
489 810 : esc_html__( 'Create Chart', 'visualizer' );
490 - if ( filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART ) {
811 + if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
491 812 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
492 813 }
493 814 } else {
494 815 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
495 816 }
496 - 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' ) ) {
497 821 global $Visualizer_Pro;
498 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
822 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
499 823 }
824 +
500 825 $this->_addAction( 'admin_head', 'renderFlattrScript' );
501 826 wp_iframe( array( $render, 'render' ) );
502 827 }
503 828
@@ -509,21 +834,32 @@
509 834 * @access private
510 835 */
511 836 private function _handleTypesPage() {
512 837 // process post request
513 - 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' ) ) ) {
514 839 $type = filter_input( INPUT_POST, 'type' );
515 - 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 +
516 848 // save new chart type
517 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 );
518 851 // if the chart has default data, update it with appropriate default data for new type
519 852 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
520 853 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
521 854 $source->fetch();
522 - $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 ) );
523 856 wp_update_post( $this->_chart->to_array() );
524 857 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
525 858 }
859 +
860 + Visualizer_Module_Utility::set_defaults( $this->_chart );
861 +
526 862 // redirect to next tab
527 863 // changed by Ash/Upwork
528 864 wp_redirect( add_query_arg( 'tab', 'settings' ) );
529 865
@@ -531,9 +867,9 @@
531 867 }
532 868 }
533 869 $render = new Visualizer_Render_Page_Types();
534 870 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
535 - $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
871 + $render->types = Visualizer_Module_Admin::_getChartTypesLocalized( false, false, false, 'types' );
536 872 $render->chart = $this->_chart;
537 873 wp_enqueue_style( 'visualizer-frame' );
538 874 wp_enqueue_script( 'visualizer-frame' );
539 875 wp_iframe( array( $render, 'render' ) );
@@ -549,10 +885,123 @@
549 885 */
550 886 public function renderFlattrScript() {
551 887 echo '';
552 888 }
553 - // changed by Ash/Upwork
889 +
554 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 + /**
555 1004 * Parses uploaded CSV file and saves new data for the chart.
556 1005 *
557 1006 * @since 1.0.0
558 1007 *
@@ -574,9 +1023,9 @@
574 1023
575 1024 // check chart, if chart exists
576 1025 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
577 1026 $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 ) {
1027 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
579 1028 if ( ! $can_die ) {
580 1029 return;
581 1030 }
582 1031 status_header( 400 );
@@ -582,8 +1031,10 @@
582 1031 status_header( 400 );
583 1032 exit;
584 1033 }
585 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 +
586 1037 if ( ! isset( $_POST['vz-import-time'] ) ) {
587 1038 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
588 1039 }
589 1040
@@ -588,15 +1039,33 @@
588 1039 }
589 1040
590 1041 if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
591 1042 // delete the filters in case this chart is being uploaded from other data sources
592 - delete_post_meta( $chart_id, 'visualizer-filter-config' );
1043 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
1044 + delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
1045 + delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
593 1046
594 1047 // delete "import from db" specific parameters.
595 1048 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
596 1049 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
1050 + delete_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS );
597 1051 }
598 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 +
599 1068 $source = null;
600 1069 $render = new Visualizer_Render_Page_Update();
601 1070 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
602 1071 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
@@ -602,18 +1071,28 @@
602 1071 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
603 1072 if ( isset( $_POST['vz-import-time'] ) ) {
604 1073 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
605 1074 }
1075 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
606 1076 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
607 1077 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
608 1078 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
609 - $source = apply_filters( 'visualizer_pro_handle_chart_data', $_POST['chart_data'], '' );
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'] );
610 1084 } else {
611 - $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' ) );
612 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 +
613 1092 if ( $source ) {
614 1093 if ( $source->fetch() ) {
615 - $content = $source->getData();
1094 + $content = $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
616 1095 $populate = true;
617 1096 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
618 1097 $json = unserialize( $content );
619 1098 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
@@ -619,8 +1098,9 @@
619 1098 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
620 1099 // if we populate the data even if it is empty, the chart will show "Table has no columns".
621 1100 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
622 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'] ) );
623 1103 $populate = false;
624 1104 }
625 1105 }
626 1106 if ( $populate ) {
@@ -629,14 +1109,30 @@
629 1109 wp_update_post( $chart->to_array() );
630 1110 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
631 1111 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
632 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 +
633 1120 $render->id = $chart->ID;
634 - $render->data = json_encode( $source->getRawData() );
1121 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
635 1122 $render->series = json_encode( $source->getSeries() );
1123 + $render->settings = json_encode( $settings );
636 1124 } else {
637 - $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 );
638 1132 }
1133 + } else {
1134 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
639 1135 }
640 1136 $render->render();
641 1137 if ( ! $can_die ) {
642 1138 return;
@@ -652,27 +1148,18 @@
652 1148 * @access public
653 1149 */
654 1150 public function cloneChart() {
655 1151 $chart_id = $success = false;
656 - $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 );
657 1153 $capable = current_user_can( 'edit_posts' );
658 1154 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 - );
1155 + $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
669 1156 if ( $chart_id ) {
670 1157 $chart = get_post( $chart_id );
671 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1158 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
672 1159 }
673 1160 }
674 - $redirect = wp_get_referer();
1161 + $redirect = remove_query_arg( 'vaction', wp_get_referer() );
675 1162 if ( $success ) {
676 1163 $new_chart_id = wp_insert_post(
677 1164 array(
678 1165 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
@@ -681,23 +1168,32 @@
681 1168 'post_status' => $chart->post_status,
682 1169 'post_content' => $chart->post_content,
683 1170 )
684 1171 );
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 ) );
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 + }
691 1181 $redirect = add_query_arg(
692 1182 array(
693 1183 'page' => 'visualizer',
694 1184 'type' => filter_input( INPUT_GET, 'type' ),
1185 + 'vaction' => false,
695 1186 ),
696 - admin_url( 'upload.php' )
1187 + admin_url( 'admin.php' )
697 1188 );
698 1189 }
699 1190 }
1191 +
1192 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1193 + wp_die();
1194 + }
1195 +
700 1196 wp_redirect( $redirect );
701 1197 exit;
702 1198 }
703 1199
@@ -743,9 +1239,12 @@
743 1239 $data = $this->_getChartArray();
744 1240 $render = new Visualizer_Render_Page_Data();
745 1241 $render->chart = $this->_chart;
746 1242 $render->type = $data['type'];
747 - 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 + }
748 1247 wp_enqueue_style( 'visualizer-frame' );
749 1248 wp_enqueue_script( 'visualizer-render' );
750 1249 wp_localize_script(
751 1250 'visualizer-render',
@@ -751,9 +1250,9 @@
751 1250 'visualizer-render',
752 1251 'visualizer',
753 1252 array(
754 1253 'l10n' => array(
755 - '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' ),
756 1255 'loading' => esc_html__( 'Loading...', 'visualizer' ),
757 1256 ),
758 1257 'charts' => array(
759 1258 'canvas' => $data,
@@ -759,13 +1258,16 @@
759 1258 'canvas' => $data,
760 1259 ),
761 1260 )
762 1261 );
763 - // Added by Ash/Upwork
764 - 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' ) ) {
765 1266 global $Visualizer_Pro;
766 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1267 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
767 1268 }
1269 +
768 1270 // Added by Ash/Upwork
769 1271 $this->_addAction( 'admin_head', 'renderFlattrScript' );
770 1272 wp_iframe( array( $render, 'render' ) );
771 1273 }
@@ -778,13 +1280,14 @@
778 1280 public function getQueryData() {
779 1281 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
780 1282
781 1283 $params = wp_parse_args( $_POST['params'] );
782 - $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 );
783 1287 $html = $source->fetch( true );
784 - $error = '';
785 - if ( empty( $html ) ) {
786 - $error = $source->get_error();
1288 + $error = $source->get_error();
1289 + if ( ! empty( $error ) ) {
787 1290 wp_send_json_error( array( 'msg' => $error ) );
788 1291 }
789 1292 wp_send_json_success( array( 'table' => $html ) );
790 1293 }
@@ -807,21 +1310,42 @@
807 1310 ),
808 1311 )
809 1312 );
810 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 +
811 1330 $render = new Visualizer_Render_Page_Update();
812 1331 if ( $chart_id ) {
813 1332 $params = wp_parse_args( $_POST['params'] );
814 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1333 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
815 1334 $source->fetch( false );
816 1335 $error = $source->get_error();
817 1336 if ( empty( $error ) ) {
818 - $hours = $_POST['refresh'];
819 1337 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
820 1338 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
821 1339 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
822 1340 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
823 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 + }
824 1348
825 1349 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
826 1350 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
827 1351 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
@@ -828,18 +1352,62 @@
828 1352
829 1353 wp_update_post(
830 1354 array(
831 1355 'ID' => $chart_id,
832 - 'post_content' => $source->getData(),
1356 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
833 1357 )
834 1358 );
835 - $render->data = json_encode( $source->getRawData() );
1359 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
836 1360 $render->series = json_encode( $source->getSeries() );
1361 + $render->id = $chart_id;
837 1362 } else {
838 1363 $render->message = $error;
839 1364 }
840 1365 }
841 1366 $render->render();
1367 + if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1368 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1369 + }
1370 + }
1371 +
1372 +
1373 + /**
1374 + * Saves the filter query and the schedule.
1375 + *
1376 + * @access public
1377 + */
1378 + public function saveFilter() {
1379 + check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1380 +
1381 + $chart_id = filter_input(
1382 + INPUT_GET,
1383 + 'chart',
1384 + FILTER_VALIDATE_INT,
1385 + array(
1386 + 'options' => array(
1387 + 'min_range' => 1,
1388 + ),
1389 + )
1390 + );
1391 +
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 + }
1407 +
1408 + do_action( 'visualizer_save_filter', $chart_id, $hours );
1409 +
842 1410 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
843 1411 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
844 1412 }
845 1413 }