PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.4.7
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.4.7
4.0.8 4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.2 3.1.3 3.10.0 3.10.1 3.10.10 3.10.11 3.10.12 3.10.13 3.10.14 3.10.15 3.10.2 3.10.3 All 149 releases
← All changes | classes/Visualizer/Module/Chart.php +648 -83 3.1.13.4.7 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,30 @@
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 +
599 1065 $source = null;
600 1066 $render = new Visualizer_Render_Page_Update();
601 1067 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
602 1068 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
@@ -602,18 +1068,28 @@
602 1068 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
603 1069 if ( isset( $_POST['vz-import-time'] ) ) {
604 1070 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
605 1071 }
1072 + // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
606 1073 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
607 1074 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
608 1075 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
609 - $source = apply_filters( 'visualizer_pro_handle_chart_data', $_POST['chart_data'], '' );
1076 + $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1077 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1078 + } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
1079 + $source = $this->handleTabularData();
1080 + update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
610 1081 } else {
611 - $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
1082 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'CSV file with chart data was not uploaded for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
1083 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
1084 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' ) );
612 1085 }
1086 +
1087 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Uploaded data for chart %d with source %s', $chart_id, print_r( $source, true ) ), 'debug', __FILE__, __LINE__ );
1088 +
613 1089 if ( $source ) {
614 1090 if ( $source->fetch() ) {
615 - $content = $source->getData();
1091 + $content = $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
616 1092 $populate = true;
617 1093 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
618 1094 $json = unserialize( $content );
619 1095 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
@@ -619,8 +1095,9 @@
619 1095 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
620 1096 // if we populate the data even if it is empty, the chart will show "Table has no columns".
621 1097 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
622 1098 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ), 'warn', __FILE__, __LINE__ );
1099 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ) );
623 1100 $populate = false;
624 1101 }
625 1102 }
626 1103 if ( $populate ) {
@@ -629,14 +1106,30 @@
629 1106 wp_update_post( $chart->to_array() );
630 1107 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
631 1108 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
632 1109 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1110 +
1111 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Updated post for chart %d', $chart_id ), 'debug', __FILE__, __LINE__ );
1112 +
1113 + Visualizer_Module_Utility::set_defaults( $chart, null );
1114 +
1115 + $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1116 +
633 1117 $render->id = $chart->ID;
634 - $render->data = json_encode( $source->getRawData() );
1118 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
635 1119 $render->series = json_encode( $source->getSeries() );
1120 + $render->settings = json_encode( $settings );
636 1121 } else {
637 - $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
1122 + $error = $source->get_error();
1123 + if ( empty( $error ) ) {
1124 + $error = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1125 + }
1126 + $render->message = $error;
1127 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1128 + update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
638 1129 }
1130 + } else {
1131 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
639 1132 }
640 1133 $render->render();
641 1134 if ( ! $can_die ) {
642 1135 return;
@@ -652,27 +1145,18 @@
652 1145 * @access public
653 1146 */
654 1147 public function cloneChart() {
655 1148 $chart_id = $success = false;
656 - $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
1149 + $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
657 1150 $capable = current_user_can( 'edit_posts' );
658 1151 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 - );
1152 + $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
669 1153 if ( $chart_id ) {
670 1154 $chart = get_post( $chart_id );
671 - $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1155 + $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
672 1156 }
673 1157 }
674 - $redirect = wp_get_referer();
1158 + $redirect = remove_query_arg( 'vaction', wp_get_referer() );
675 1159 if ( $success ) {
676 1160 $new_chart_id = wp_insert_post(
677 1161 array(
678 1162 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
@@ -681,23 +1165,32 @@
681 1165 'post_status' => $chart->post_status,
682 1166 'post_content' => $chart->post_content,
683 1167 )
684 1168 );
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 ) );
1169 + if ( is_wp_error( $new_chart_id ) ) {
1170 + do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Error while cloning chart %d = %s', $chart_id, print_r( $new_chart_id, true ) ), 'error', __FILE__, __LINE__ );
1171 + } else {
1172 + $post_meta = get_post_meta( $chart_id );
1173 + foreach ( $post_meta as $key => $value ) {
1174 + if ( strpos( $key, 'visualizer-' ) !== false ) {
1175 + add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1176 + }
1177 + }
691 1178 $redirect = add_query_arg(
692 1179 array(
693 1180 'page' => 'visualizer',
694 1181 'type' => filter_input( INPUT_GET, 'type' ),
1182 + 'vaction' => false,
695 1183 ),
696 - admin_url( 'upload.php' )
1184 + admin_url( 'admin.php' )
697 1185 );
698 1186 }
699 1187 }
1188 +
1189 + if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1190 + wp_die();
1191 + }
1192 +
700 1193 wp_redirect( $redirect );
701 1194 exit;
702 1195 }
703 1196
@@ -743,9 +1236,12 @@
743 1236 $data = $this->_getChartArray();
744 1237 $render = new Visualizer_Render_Page_Data();
745 1238 $render->chart = $this->_chart;
746 1239 $render->type = $data['type'];
747 - unset( $data['settings']['width'], $data['settings']['height'] );
1240 +
1241 + if ( $data && $data['settings'] ) {
1242 + unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1243 + }
748 1244 wp_enqueue_style( 'visualizer-frame' );
749 1245 wp_enqueue_script( 'visualizer-render' );
750 1246 wp_localize_script(
751 1247 'visualizer-render',
@@ -751,9 +1247,9 @@
751 1247 'visualizer-render',
752 1248 'visualizer',
753 1249 array(
754 1250 'l10n' => array(
755 - 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1251 + 'invalid_source' => esc_html__( 'You have entered an invalid URL. Please provide a valid URL.', 'visualizer' ),
756 1252 'loading' => esc_html__( 'Loading...', 'visualizer' ),
757 1253 ),
758 1254 'charts' => array(
759 1255 'canvas' => $data,
@@ -759,13 +1255,16 @@
759 1255 'canvas' => $data,
760 1256 ),
761 1257 )
762 1258 );
763 - // Added by Ash/Upwork
764 - if ( VISUALIZER_PRO ) {
1259 +
1260 + do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
1261 +
1262 + if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
765 1263 global $Visualizer_Pro;
766 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1264 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
767 1265 }
1266 +
768 1267 // Added by Ash/Upwork
769 1268 $this->_addAction( 'admin_head', 'renderFlattrScript' );
770 1269 wp_iframe( array( $render, 'render' ) );
771 1270 }
@@ -778,13 +1277,14 @@
778 1277 public function getQueryData() {
779 1278 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
780 1279
781 1280 $params = wp_parse_args( $_POST['params'] );
782 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1281 + $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1282 +
1283 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
783 1284 $html = $source->fetch( true );
784 - $error = '';
785 - if ( empty( $html ) ) {
786 - $error = $source->get_error();
1285 + $error = $source->get_error();
1286 + if ( ! empty( $error ) ) {
787 1287 wp_send_json_error( array( 'msg' => $error ) );
788 1288 }
789 1289 wp_send_json_success( array( 'table' => $html ) );
790 1290 }
@@ -807,21 +1307,42 @@
807 1307 ),
808 1308 )
809 1309 );
810 1310
1311 + $hours = filter_input(
1312 + INPUT_POST,
1313 + 'refresh',
1314 + FILTER_VALIDATE_INT,
1315 + array(
1316 + 'options' => array(
1317 + 'min_range' => -1,
1318 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1319 + ),
1320 + )
1321 + );
1322 +
1323 + if ( ! is_int( $hours ) ) {
1324 + $hours = -1;
1325 + }
1326 +
811 1327 $render = new Visualizer_Render_Page_Update();
812 1328 if ( $chart_id ) {
813 1329 $params = wp_parse_args( $_POST['params'] );
814 - $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1330 + $source = new Visualizer_Source_Query( stripslashes( $params['query'] ), $chart_id, $params );
815 1331 $source->fetch( false );
816 1332 $error = $source->get_error();
817 1333 if ( empty( $error ) ) {
818 - $hours = $_POST['refresh'];
819 1334 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
820 1335 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
821 1336 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
822 1337 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
823 1338 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1339 + if ( isset( $params['db_type'] ) && $params['db_type'] !== Visualizer_Plugin::WP_DB_NAME ) {
1340 + $remote_db_params = $params;
1341 + unset( $remote_db_params['query'] );
1342 + unset( $remote_db_params['chart_id'] );
1343 + update_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS, $remote_db_params );
1344 + }
824 1345
825 1346 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
826 1347 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
827 1348 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
@@ -828,18 +1349,62 @@
828 1349
829 1350 wp_update_post(
830 1351 array(
831 1352 'ID' => $chart_id,
832 - 'post_content' => $source->getData(),
1353 + 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
833 1354 )
834 1355 );
835 - $render->data = json_encode( $source->getRawData() );
1356 + $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
836 1357 $render->series = json_encode( $source->getSeries() );
1358 + $render->id = $chart_id;
837 1359 } else {
838 1360 $render->message = $error;
839 1361 }
840 1362 }
841 1363 $render->render();
1364 + if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1365 + defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1366 + }
1367 + }
1368 +
1369 +
1370 + /**
1371 + * Saves the filter query and the schedule.
1372 + *
1373 + * @access public
1374 + */
1375 + public function saveFilter() {
1376 + check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1377 +
1378 + $chart_id = filter_input(
1379 + INPUT_GET,
1380 + 'chart',
1381 + FILTER_VALIDATE_INT,
1382 + array(
1383 + 'options' => array(
1384 + 'min_range' => 1,
1385 + ),
1386 + )
1387 + );
1388 +
1389 + $hours = filter_input(
1390 + INPUT_POST,
1391 + 'refresh',
1392 + FILTER_VALIDATE_INT,
1393 + array(
1394 + 'options' => array(
1395 + 'min_range' => -1,
1396 + 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1397 + ),
1398 + )
1399 + );
1400 +
1401 + if ( ! $hours ) {
1402 + $hours = -1;
1403 + }
1404 +
1405 + do_action( 'visualizer_save_filter', $chart_id, $hours );
1406 +
842 1407 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
843 1408 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
844 1409 }
845 1410 }