PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 1.7.6
Visualizer – Tables & Charts Manager with Built-in AI Generator v1.7.6
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 +317 -1491 4.0.61.7.6 View file →
@@ -1,5 +1,6 @@
1 1 <?php
2 +
2 3 // +----------------------------------------------------------------------+
3 4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
4 5 // +----------------------------------------------------------------------+
5 6 // | This program is free software; you can redistribute it and/or modify |
@@ -45,13 +46,13 @@
45 46 *
46 47 * @since 1.0.0
47 48 *
48 49 * @access public
49 - *
50 50 * @param Visualizer_Plugin $plugin The instance of the plugin.
51 51 */
52 52 public function __construct( Visualizer_Plugin $plugin ) {
53 53 parent::__construct( $plugin );
54 +
54 55 $this->_addAjaxAction( Visualizer_Plugin::ACTION_GET_CHARTS, 'getCharts' );
55 56 $this->_addAjaxAction( Visualizer_Plugin::ACTION_DELETE_CHART, 'deleteChart' );
56 57 $this->_addAjaxAction( Visualizer_Plugin::ACTION_CREATE_CHART, 'renderChartPages' );
57 58 $this->_addAjaxAction( Visualizer_Plugin::ACTION_EDIT_CHART, 'renderChartPages' );
@@ -56,304 +57,82 @@
56 57 $this->_addAjaxAction( Visualizer_Plugin::ACTION_CREATE_CHART, 'renderChartPages' );
57 58 $this->_addAjaxAction( Visualizer_Plugin::ACTION_EDIT_CHART, 'renderChartPages' );
58 59 $this->_addAjaxAction( Visualizer_Plugin::ACTION_UPLOAD_DATA, 'uploadData' );
59 60 $this->_addAjaxAction( Visualizer_Plugin::ACTION_CLONE_CHART, 'cloneChart' );
61 +
62 + // Added by Ash/Upwork
60 63 $this->_addAjaxAction( Visualizer_Plugin::ACTION_EXPORT_DATA, 'exportData' );
61 -
62 - $this->_addAjaxAction( Visualizer_Plugin::ACTION_FETCH_DB_DATA, 'getQueryData' );
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 - }
74 -
75 - /**
76 - * Generates the HTML of the sidebar for the chart.
77 - *
78 - * @since ?
79 - *
80 - * @access public
81 - */
82 - public function getSidebar( $sidebar, $chart_id ) {
83 - $chart = get_post( $chart_id );
84 - $data = $this->_getChartArray( $chart );
85 - $sidebar = '';
86 - $sidebar_class = $this->load_chart_class_name( $chart_id );
87 - if ( class_exists( $sidebar_class, true ) ) {
88 - $sidebar = new $sidebar_class( $data['settings'] );
89 - $sidebar->__series = $data['series'];
90 - $sidebar->__data = $data['data'];
91 - } else {
92 - $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
93 - if ( $sidebar !== '' ) {
94 - $sidebar->__series = $data['series'];
95 - $sidebar->__data = $data['data'];
96 - }
64 + if ( defined( 'Visualizer_Pro' ) ) {
65 + global $Visualizer_Pro;
66 + list($action, $name, $class) = $Visualizer_Pro->_getAjaxAction( $this );
67 + $this->_addAjaxAction( $action, $name, $class );
97 68 }
98 - return str_replace( "'", '"', $sidebar->__toString() );
69 + // Added by Ash/Upwork
99 70 }
100 71
101 72 /**
102 - * Sets the schedule for how JSON-endpoint charts should be updated.
73 + * Sends json response.
103 74 *
104 - * @since ?
75 + * @since 1.0.0
105 76 *
106 - * @access public
77 + * @access private
78 + * @param array $results The response array.
107 79 */
108 - public function setJsonSchedule() {
109 - check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION, 'security' );
80 + public function _sendResponse( $results ) {
81 + header( 'Content-type: application/json' );
82 + nocache_headers();
110 83
111 - $chart_id = isset( $_POST['chart'] ) ? filter_var(
112 - $_POST['chart'],
113 - FILTER_VALIDATE_INT,
114 - array(
115 - 'options' => array(
116 - 'min_range' => 1,
117 - ),
118 - )
119 - ) : false;
120 -
121 - if ( ! $chart_id ) {
122 - wp_send_json_error();
123 - }
124 -
125 - if ( ! self::can_edit_chart( $chart_id ) ) {
126 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ), 403 );
127 - }
128 -
129 - $time = filter_input(
130 - INPUT_POST,
131 - 'time',
132 - FILTER_VALIDATE_INT,
133 - array(
134 - 'options' => array(
135 - 'min_range' => -1,
136 - ),
137 - )
138 - );
139 -
140 - if ( Visualizer_Module::is_pro() ) {
141 - $is_woocommerce_report = filter_input(
142 - INPUT_POST,
143 - 'is_woocommerce_report',
144 - FILTER_VALIDATE_BOOLEAN
145 - );
146 -
147 - if ( $is_woocommerce_report ) {
148 - update_post_meta( $chart_id, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE, true );
149 - } else {
150 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_IS_WOOCOMMERCE_SOURCE );
151 - }
152 - }
153 -
154 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
155 -
156 - if ( -1 < $time ) {
157 - add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
158 - // Update schedules.
159 - $schedules = get_option( Visualizer_Plugin::CF_JSON_SCHEDULE, array() );
160 - $schedules[ $chart_id ] = time() + $time * HOUR_IN_SECONDS;
161 - update_option( Visualizer_Plugin::CF_JSON_SCHEDULE, $schedules );
162 - }
163 - wp_send_json_success();
84 + echo json_encode( $results );
85 + exit;
164 86 }
165 87
166 88 /**
167 - * Get the root elements for JSON-endpoint.
89 + * Returns chart data required for rendering.
168 90 *
169 - * @since ?
91 + * @since 1.0.0
170 92 *
171 - * @access public
93 + * @access private
94 + * @param WP_Post $chart The chart object.
95 + * @return array The array of chart data.
172 96 */
173 - public function getJsonRoots() {
174 - check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
175 -
176 - if ( ! current_user_can( 'edit_posts' ) ) {
177 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ) );
97 + private function _getChartArray( WP_Post $chart = null ) {
98 + if ( is_null( $chart ) ) {
99 + $chart = $this->_chart;
178 100 }
179 101
180 - $params = wp_parse_args( $_POST['params'] );
102 + $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
103 + $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
104 + $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( $chart->post_content ), $chart->ID, $type );
181 105
182 - $source = new Visualizer_Source_Json( $params );
183 -
184 - $roots = $source->fetchRoots();
185 - if ( empty( $roots ) ) {
186 - wp_send_json_error( array( 'msg' => $source->get_error() ) );
187 - }
188 -
189 - wp_send_json_success( array( 'url' => $params['url'], 'roots' => $roots ) );
190 - }
191 -
192 - /**
193 - * Get the data for the JSON-endpoint corresponding to the chosen root.
194 - *
195 - * @since ?
196 - *
197 - * @access public
198 - */
199 - public function getJsonData() {
200 - check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
201 -
202 - if ( ! current_user_can( 'edit_posts' ) ) {
203 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ) );
204 - }
205 -
206 - $params = wp_parse_args( $_POST['params'] );
207 -
208 - $chart_id = $params['chart'];
209 -
210 - $chart = $chart_id ? get_post( $chart_id ) : null;
211 - if ( ! $chart || Visualizer_Plugin::CPT_VISUALIZER !== $chart->post_type || ! current_user_can( 'edit_post', $chart_id ) ) {
212 - wp_die();
213 - }
214 -
215 - $source = new Visualizer_Source_Json( $params );
216 - $source->fetch();
217 - $data = $source->getRawData();
218 -
219 - if ( empty( $data ) ) {
220 - wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
221 - }
222 -
223 - $data = Visualizer_Render_Layout::show( 'editor-table', $data, $chart_id, 'viz-json-table', false, false );
224 - wp_send_json_success( array( 'table' => $data, 'root' => $params['root'], 'url' => $params['url'], 'paging' => $source->getPaginationElements() ) );
225 - }
226 -
227 - /**
228 - * Updates the database with the correct post parameters for JSON-endpoint charts.
229 - *
230 - * @since ?
231 - *
232 - * @access public
233 - */
234 - public function setJsonData() {
235 - check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_DATA . Visualizer_Plugin::VERSION, 'security' );
236 -
237 - $params = $_POST;
238 - $chart_id = isset( $_GET['chart'] ) ? absint( $_GET['chart'] ) : 0;
239 -
240 - if ( ! self::can_edit_chart( $chart_id ) ) {
241 - wp_die( esc_html__( 'You do not have permission to perform this action.', 'visualizer' ), '', array( 'response' => 403 ) );
242 - }
243 -
244 - $chart = get_post( $chart_id );
245 -
246 - $source = new Visualizer_Source_Json( $params );
247 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true );
248 - $source->fetchFromEditableTable();
249 -
250 - $content = $source->getData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
251 - $chart->post_content = $content;
252 - wp_update_post( $chart->to_array() );
253 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
254 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
255 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
256 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_URL, $params['url'] );
257 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_ROOT, $params['root'] );
258 -
259 - delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS );
260 - $headers = array( 'method' => $params['method'] );
261 - if ( ! empty( $params['auth'] ) ) {
262 - $headers['auth'] = $params['auth'];
263 - } elseif ( ! empty( $params['username'] ) && ! empty( $params['password'] ) ) {
264 - $headers['auth'] = array( 'username' => $params['username'], 'password' => $params['password'] );
265 - }
266 -
267 - add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_HEADERS, $headers );
268 -
269 - delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING );
270 - if ( ! empty( $params['paging'] ) ) {
271 - add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
272 - }
273 -
274 - if ( Visualizer_Module::is_pro() ) {
275 - if ( ! empty( $params['vz_woo_source'] ) ) {
276 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE, $params['vz_woo_source'] );
277 - } else {
278 - delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_WOOCOMMERCE_SOURCE );
279 - }
280 - }
281 -
282 - $time = filter_input(
283 - INPUT_POST,
284 - 'time',
285 - FILTER_VALIDATE_INT,
286 - array(
287 - 'options' => array(
288 - 'min_range' => -1,
289 - ),
290 - )
106 + return array(
107 + 'type' => $type,
108 + 'series' => $series,
109 + 'settings' => get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true ),
110 + 'data' => $data,
291 111 );
292 -
293 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
294 -
295 - if ( -1 < $time ) {
296 - add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
297 - }
298 -
299 - // delete other source specific parameters.
300 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
301 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
302 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_URL );
303 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_SCHEDULE );
304 -
305 - $render = new Visualizer_Render_Page_Update();
306 - $render->id = $chart->ID;
307 - $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
308 - $render->series = json_encode( $source->getSeries() );
309 - $render->render();
310 -
311 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
312 112 }
313 113
314 -
315 114 /**
316 115 * Fetches charts from database.
317 116 *
318 - * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
319 - *
320 117 * @since 1.0.0
321 118 *
322 119 * @access public
323 120 */
324 121 public function getCharts() {
325 - check_ajax_referer( Visualizer_Plugin::ACTION_GET_CHARTS, 'nonce' );
326 -
327 - if ( ! current_user_can( 'edit_posts' ) ) {
328 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ), 403 );
329 - }
330 -
331 122 $query_args = array(
332 123 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
333 124 'posts_per_page' => 9,
334 - 'paged' => filter_input(
335 - INPUT_GET,
336 - 'page',
337 - FILTER_VALIDATE_INT,
338 - array(
339 - 'options' => array(
340 - 'min_range' => 1,
341 - 'default' => 1,
342 - ),
343 - )
344 - ),
125 + 'paged' => filter_input( INPUT_GET, 'page', FILTER_VALIDATE_INT, array(
126 + 'options' => array(
127 + 'min_range' => 1,
128 + 'default' => 1,
129 + ),
130 + ) ),
345 131 );
346 - if ( ! current_user_can( 'edit_others_posts' ) ) {
347 - $query_args['author'] = get_current_user_id();
348 - }
349 - $filter = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
350 - if ( empty( $filter ) ) {
351 - // 'filter' is from the modal from the add media button.
352 - $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
353 - }
354 132
355 - if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
133 + $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
134 + if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
356 135 $query_args['meta_query'] = array(
357 136 array(
358 137 'key' => Visualizer_Plugin::CF_CHART_TYPE,
359 138 'value' => $filter,
@@ -360,104 +139,29 @@
360 139 'compare' => '=',
361 140 ),
362 141 );
363 142 }
364 - $query = new WP_Query( $query_args );
143 +
144 + $query = new WP_Query( $query_args );
145 +
365 146 $charts = array();
366 147 while ( $query->have_posts() ) {
367 - $chart = $query->next_post();
368 - $chart_data = $this->_getChartArray( $chart );
148 + $chart = $query->next_post();
149 +
150 + $chart_data = $this->_getChartArray( $chart );
369 151 $chart_data['id'] = $chart->ID;
370 - $chart_data['library'] = $this->load_chart_type( $chart->ID );
371 - $css = '';
372 - $settings = $chart_data['settings'];
373 - $arguments = $this->get_inline_custom_css( 'visualizer-chart-' . $chart->ID, $settings );
374 - if ( ! empty( $arguments ) ) {
375 - $css = $arguments[0];
376 - $settings = $arguments[1];
377 - }
378 - $chart_data['settings'] = $settings;
379 - $chart_data['css'] = $css;
380 - $charts[] = $chart_data;
381 - }
382 - self::_sendResponse(
383 - array(
384 - 'success' => true,
385 - 'data' => $charts,
386 - 'total' => $query->max_num_pages,
387 - )
388 - );
389 - }
390 152
391 - /**
392 - * Returns chart data required for rendering.
393 - *
394 - * @since 1.0.0
395 - *
396 - * @access private
397 - *
398 - * @param WP_Post|null $chart The chart object.
399 - *
400 - * @return array The array of chart data.
401 - */
402 - private function _getChartArray( $chart = null ) {
403 - if ( is_null( $chart ) ) {
404 - $chart = $this->_chart;
153 + $charts[] = $chart_data;
405 154 }
406 - $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
407 - $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
408 - $data = self::get_chart_data( $chart, $type );
409 - $library = $this->load_chart_type( $chart->ID );
410 155
411 - $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
412 - $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
413 - if ( ! empty( $atts['settings'] ) ) {
414 - $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
415 - }
416 -
417 - $css = '';
418 - $arguments = $this->get_inline_custom_css( 'visualizer-' . $chart->ID, $settings );
419 - if ( ! empty( $arguments ) ) {
420 - $css = $arguments[0];
421 - $settings = $arguments[1];
422 - }
423 -
424 - $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
425 -
426 - $code = '';
427 - if ( 'd3' === $library ) {
428 - $code = get_post_meta( $chart->ID, Visualizer_Module_AIBuilder::CF_D3_CODE, true );
429 - }
430 -
431 - return array(
432 - 'type' => $type,
433 - 'series' => $series,
434 - 'settings' => $settings,
435 - 'data' => $data,
436 - 'library' => $library,
437 - 'code' => $code,
438 - 'css' => $css,
439 - 'date_formats' => $date_formats,
440 - );
156 + $this->_sendResponse( array(
157 + 'success' => true,
158 + 'data' => $charts,
159 + 'total' => $query->max_num_pages,
160 + ) );
441 161 }
442 162
443 163 /**
444 - * Sends json response.
445 - *
446 - * @since 1.0.0
447 - *
448 - * @access private
449 - *
450 - * @param array $results The response array.
451 - */
452 - public static function _sendResponse( $results ) {
453 - header( 'Content-type: application/json' );
454 - nocache_headers();
455 - echo json_encode( $results );
456 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
457 - }
458 -
459 - /**
460 164 * Deletes a chart from database.
461 165 *
462 166 * @since 1.0.0
463 167 * @uses wp_delete_post() To delete a chart.
@@ -464,88 +168,35 @@
464 168 *
465 169 * @access public
466 170 */
467 171 public function deleteChart() {
468 - $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
469 - $input = $is_post ? $_POST : $_GET;
470 - $chart_id = $success = false;
471 - $nonce = isset( $input['nonce'] ) && wp_verify_nonce( $input['nonce'] );
472 - if ( $nonce ) {
473 - $chart_id = isset( $input['chart'] ) ? filter_var(
474 - $input['chart'],
475 - FILTER_VALIDATE_INT,
476 - array(
477 - 'options' => array(
478 - 'min_range' => 1,
479 - ),
480 - )
481 - ) : false;
172 + $is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
173 + $input_method = $is_post ? INPUT_POST : INPUT_GET;
174 +
175 + $chart_id = $success = false;
176 + $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
177 + $capable = current_user_can( 'delete_posts' );
178 + if ( $nonce && $capable ) {
179 + $chart_id = filter_input( $input_method, 'chart', FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1 ) ) );
482 180 if ( $chart_id ) {
483 - $chart = get_post( $chart_id );
484 - $success = $chart
485 - && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER
486 - && (
487 - current_user_can( 'delete_post', $chart_id )
488 - || ( (int) $chart->post_author === get_current_user_id() && current_user_can( 'delete_posts' ) )
489 - );
181 + $chart = get_post( $chart_id );
182 + $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
490 183 }
491 184 }
185 +
492 186 if ( $success ) {
493 - global $sitepress;
494 - if ( Visualizer_Module::is_pro() && ( function_exists( 'icl_get_languages' ) && $sitepress instanceof \SitePress ) ) {
495 - $trid = $sitepress->get_element_trid( $chart_id, 'post_' . Visualizer_Plugin::CPT_VISUALIZER );
496 - $translations = $sitepress->get_element_translations( $trid );
497 - if ( ! empty( $translations ) ) {
498 - foreach ( $translations as $translated_post ) {
499 - wp_delete_post( $translated_post->element_id, true );
500 - }
501 - } else {
502 - wp_delete_post( $chart_id, true );
503 - }
504 - } else {
505 - wp_delete_post( $chart_id, true );
506 - }
187 + wp_delete_post( $chart_id, true );
507 188 }
189 +
508 190 if ( $is_post ) {
509 - self::_sendResponse(
510 - array(
511 - 'success' => $success,
512 - )
513 - );
191 + $this->_sendResponse( array( 'success' => $success ) );
514 192 }
515 - wp_redirect( remove_query_arg( 'vaction', wp_get_referer() ) );
193 +
194 + wp_redirect( wp_get_referer() );
516 195 exit;
517 196 }
518 197
519 198 /**
520 - * Delete charts that are still in auto-draft mode.
521 - */
522 - private function deleteOldCharts() {
523 - $query = new WP_Query(
524 - array(
525 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
526 - 'post_status' => 'auto-draft',
527 - 'fields' => 'ids',
528 - 'update_post_meta_cache' => false,
529 - 'update_post_term_cache' => false,
530 - 'posts_per_page' => 50,
531 - 'date_query' => array(
532 - array(
533 - 'before' => 'today',
534 - ),
535 - ),
536 - )
537 - );
538 -
539 - if ( $query->have_posts() ) {
540 - $ids = array();
541 - while ( $query->have_posts() ) {
542 - wp_delete_post( $query->next_post(), true );
543 - }
544 - }
545 - }
546 -
547 - /**
548 199 * Renders appropriate page for chart builder. Creates new auto draft chart
549 200 * if no chart has been specified.
550 201 *
551 202 * @since 1.0.0
@@ -552,267 +203,150 @@
552 203 *
553 204 * @access public
554 205 */
555 206 public function renderChartPages() {
556 - if ( ! current_user_can( 'edit_posts' ) ) {
557 - wp_die( __( 'You do not have permission to access this page.', 'visualizer' ) );
558 - }
207 + define( 'IFRAME_REQUEST', 1 );
559 208
560 - defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
561 - if ( ! defined( 'ET_BUILDER_PRODUCT_VERSION' ) && function_exists( 'et_get_theme_version' ) ) {
562 - define( 'ET_BUILDER_PRODUCT_VERSION', et_get_theme_version() );
563 - }
564 - // Set current screen for the render chart.
565 - set_current_screen( 'visualizer_render_chart' );
566 209 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
567 - $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
568 - if ( ! empty( $_POST ) ) {
569 - $_POST = map_deep( $_POST, 'wp_strip_all_tags' );
570 - }
571 - $chart = $chart_id ? get_post( $chart_id ) : null;
572 - if ( $chart && ! self::can_edit_chart( $chart_id ) ) {
573 - wp_die( esc_html__( 'You do not have permission to access this page.', 'visualizer' ), '', array( 'response' => 403 ) );
574 - }
575 - if ( ! $chart_id || ! $chart || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
576 - if ( empty( $_GET['lang'] ) || empty( $_GET['parent_chart_id'] ) ) {
577 - $this->deleteOldCharts();
578 - $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
579 - $chart_status = Visualizer_Module_Admin::checkChartStatus( $default_type );
580 - if ( ! $chart_status ) {
581 - $default_type = 'line';
582 - }
583 - $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
584 - $source->fetch();
585 - $chart_id = wp_insert_post(
586 - array(
587 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
588 - 'post_title' => 'Visualization',
589 - 'post_author' => get_current_user_id(),
590 - 'post_status' => 'auto-draft',
591 - 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
592 - )
593 - );
594 - if ( $chart_id && ! is_wp_error( $chart_id ) ) {
595 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
596 - add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
597 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
598 - add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
599 - add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
600 - add_post_meta(
601 - $chart_id,
602 - Visualizer_Plugin::CF_SETTINGS,
603 - array(
604 - 'focusTarget' => 'datum',
605 - )
606 - );
210 + $chart_id = filter_input( INPUT_GET, 'chart', FILTER_VALIDATE_INT );
211 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
212 + $default_type = 'line';
607 213
608 - do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
609 - }
610 - } else {
611 - $parent_chart_id = filter_var( $_GET['parent_chart_id'], FILTER_VALIDATE_INT );
612 - $success = false;
613 - if ( $parent_chart_id && self::can_edit_chart( $parent_chart_id ) ) {
614 - $parent_chart = get_post( $parent_chart_id );
615 - $success = $parent_chart && $parent_chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
616 - }
617 - if ( $success ) {
618 - $new_chart_id = wp_insert_post(
619 - array(
620 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
621 - 'post_title' => 'Visualization',
622 - 'post_author' => get_current_user_id(),
623 - 'post_status' => $parent_chart->post_status,
624 - 'post_content' => $parent_chart->post_content,
625 - )
626 - );
214 + $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
215 + $source->fetch();
627 216
628 - if ( is_wp_error( $new_chart_id ) ) {
629 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Error while cloning chart %d = %s', $parent_chart_id, print_r( $new_chart_id, true ) ), 'error', __FILE__, __LINE__ );
630 - } else {
631 - $post_meta = get_post_meta( $parent_chart_id );
632 - $chart_id = $new_chart_id;
633 - foreach ( $post_meta as $key => $value ) {
634 - if ( strpos( $key, 'visualizer-' ) !== false ) {
635 - add_post_meta( $new_chart_id, $key, self::maybe_decode_content( $value[0] ) );
636 - }
637 - }
638 - }
639 - }
640 - do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
641 - }
642 - wp_redirect( esc_url_raw( add_query_arg( 'chart', (int) $chart_id ) ) );
217 + $chart_id = wp_insert_post( array(
218 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
219 + 'post_title' => 'Visualization',
220 + 'post_author' => get_current_user_id(),
221 + 'post_status' => 'auto-draft',
222 + 'post_content' => $source->getData(),
223 + ) );
643 224
644 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
645 - wp_die();
225 + if ( $chart_id && ! is_wp_error( $chart_id ) ) {
226 + add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
227 + add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
228 + add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
229 + add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
230 + add_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, array( 'focusTarget' => 'datum' ) );
646 231 }
647 - exit();
648 - }
649 232
650 - $_POST['save_chart_image'] = isset( $_POST['save_chart_image'] ) && 'yes' === $_POST['save_chart_image'] ? true : false;
651 - $_POST['lazy_load_chart'] = isset( $_POST['lazy_load_chart'] ) && 'yes' === $_POST['lazy_load_chart'] ? true : false;
652 -
653 - if ( isset( $_POST['chart-img'] ) && ! empty( $_POST['chart-img'] ) ) {
654 - $attachment_id = $this->save_chart_image( $_POST['chart-img'], $chart_id, $_POST['save_chart_image'] );
655 - if ( $attachment_id ) {
656 - update_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, $attachment_id );
657 - }
233 + wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
234 + exit;
658 235 }
659 - $lib = $this->load_chart_type( $chart_id );
660 236
661 - // the alpha color picker (RGBA) is not supported by google.
662 - $color_picker_dep = 'wp-color-picker';
663 - if ( in_array( $lib, array( 'chartjs', 'datatables' ), true ) && ! wp_script_is( 'wp-color-picker-alpha', 'registered' ) ) {
664 - wp_register_script( 'wp-color-picker-alpha', VISUALIZER_ABSURL . 'js/lib/wp-color-picker-alpha.min.js', array( 'wp-color-picker' ), Visualizer_Plugin::VERSION );
665 - $color_picker_dep = 'wp-color-picker-alpha';
666 - }
667 -
668 237 // enqueue and register scripts and styles
669 - wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
670 - wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
238 + wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array(), Visualizer_Plugin::VERSION );
671 239
672 - wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
673 - wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion', 'jquery-ui-tabs' ), Visualizer_Plugin::VERSION, true );
674 - wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
675 - wp_register_script(
676 - 'visualizer-render',
677 - VISUALIZER_ABSURL . 'js/render-facade.js',
678 - apply_filters( 'visualizer_assets_render', array( 'visualizer-frame', 'visualizer-customization' ), false ),
679 - Visualizer_Plugin::VERSION,
680 - true
681 - );
682 - wp_register_script(
683 - 'visualizer-preview',
684 - VISUALIZER_ABSURL . 'js/preview.js',
685 - array(
686 - $color_picker_dep,
687 - 'visualizer-render',
688 - ),
689 - Visualizer_Plugin::VERSION,
690 - true
691 - );
692 - wp_register_script( 'visualizer-editor-simple', VISUALIZER_ABSURL . 'js/simple-editor.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
240 + wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
241 + wp_register_script( 'google-jsapi-new', '//www.gstatic.com/charts/loader.js', array(), null, true );
242 + wp_register_script( 'google-jsapi-old', '//www.google.com/jsapi', array( 'google-jsapi-new' ), null, true );
243 + wp_register_script( 'visualizer-render', VISUALIZER_ABSURL . 'js/render.js', array( 'google-jsapi-old', 'google-jsapi-new', 'visualizer-frame' ), Visualizer_Plugin::VERSION, true );
244 + wp_register_script( 'visualizer-preview', VISUALIZER_ABSURL . 'js/preview.js', array( 'wp-color-picker', 'visualizer-render' ), Visualizer_Plugin::VERSION, true );
693 245
694 - do_action( 'visualizer_add_scripts' );
695 -
696 - if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
246 + // added by Ash/Upwork
247 + if ( defined( 'Visualizer_Pro' ) ) {
697 248 global $Visualizer_Pro;
698 249 $Visualizer_Pro->_addScriptsAndStyles();
699 250 }
700 251
701 252 // dispatch pages
702 - $this->_chart = get_post( $chart_id );
703 - $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
704 -
705 - // skip chart type pages only for existing charts.
706 - if ( VISUALIZER_SKIP_CHART_TYPE_PAGE && 'auto-draft' !== $this->_chart->post_status && ( ! empty( $_GET['tab'] ) && 'visualizer' === $_GET['tab'] ) ) {
707 - $tab = 'settings';
708 - }
709 -
710 - if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
711 - // if the cancel button is clicked.
712 - $this->undoRevisions( $chart_id, true );
713 - } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
714 - $this->handlePermissions();
715 - // if the save button is clicked.
716 - $this->undoRevisions( $chart_id, false );
717 - } else {
718 - // if the edit button is clicked.
719 - $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
720 - }
721 -
722 - // Clear existing chart cache.
723 - if ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
724 - $cache_key = Visualizer_Plugin::CF_CHART_CACHE . '_' . $chart_id;
725 - if ( get_transient( $cache_key ) ) {
726 - delete_transient( $cache_key );
727 - }
728 - }
729 -
730 - switch ( $tab ) {
253 + $this->_chart = $chart;
254 + switch ( filter_input( INPUT_GET, 'tab' ) ) {
731 255 case 'settings':
256 + // changed by Ash/Upwork
732 257 $this->_handleDataAndSettingsPage();
733 258 break;
734 - case 'type': // fall through.
735 - case 'visualizer': // fall through.
259 + case 'type':
260 + default:
736 261 $this->_handleTypesPage();
737 262 break;
738 - default:
739 - // this should never happen.
740 - break;
741 263 }
742 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
264 +
265 + exit;
743 266 }
744 267
745 268 /**
746 - * Load code editor assets.
269 + * Handles chart type selection page.
270 + *
271 + * @since 1.0.0
272 + *
273 + * @access private
747 274 */
748 - private function loadCodeEditorAssets( $chart_id ) {
749 - global $wp_version;
275 + private function _handleTypesPage() {
276 + // process post request
277 + if ( $_SERVER['REQUEST_METHOD'] == 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
278 + $type = filter_input( INPUT_POST, 'type' );
279 + if ( in_array( $type, Visualizer_Plugin::getChartTypes() ) ) {
280 + // save new chart type
281 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
750 282
751 - $wp_scripts = wp_scripts();
283 + // if the chart has default data, update it with appropriate default data for new type
284 + if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
285 + $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
286 + $source->fetch();
752 287
753 - // data tables assets.
754 - wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
755 - wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
756 - wp_register_style( 'visualizer-jquery-ui', sprintf( '//code.jquery.com/ui/%s/themes/smoothness/jquery-ui.css', $wp_scripts->registered['jquery-ui-core']->ver ), array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
757 - wp_enqueue_script( 'visualizer-datatables' );
758 - wp_enqueue_style( 'visualizer-jquery-ui' );
288 + $this->_chart->post_content = $source->getData();
289 + wp_update_post( $this->_chart->to_array() );
759 290
760 - if ( ! Visualizer_Module::is_pro() ) {
761 - return;
291 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
292 + }
293 +
294 + // redirect to next tab
295 + // changed by Ash/Upwork
296 + wp_redirect( add_query_arg( 'tab', 'settings' ) );
297 + return;
298 + }
762 299 }
763 300
764 - $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping( $chart_id );
301 + $render = new Visualizer_Render_Page_Types();
302 + $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
303 + $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
304 + $render->chart = $this->_chart;
765 305
766 - if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
767 - // code mirror assets.
768 - wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
769 - wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
770 - wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
771 - wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
772 - wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
773 - wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
774 - wp_register_script( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.js', array( 'visualizer-codemirror-sql', 'visualizer-codemirror-sql-hint', 'visualizer-codemirror-placeholder', 'visualizer-codemirror-matchbrackets', 'visualizer-codemirror-closebrackets' ), Visualizer_Plugin::VERSION );
775 - wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
776 - wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
306 + wp_enqueue_style( 'visualizer-frame' );
307 + wp_enqueue_script( 'visualizer-frame' );
777 308
778 - wp_enqueue_script( 'visualizer-codemirror-hint' );
779 - wp_enqueue_style( 'visualizer-codemirror-hint' );
780 - } else {
781 - wp_enqueue_code_editor(
782 - array(
783 - 'type' => 'sql',
784 - 'codemirror' => array(
785 - 'autofocus' => true,
786 - 'lineWrapping' => true,
787 - 'dragDrop' => false,
788 - 'matchBrackets' => true,
789 - 'autoCloseBrackets' => true,
790 - 'extraKeys' => array( 'Shift-Space' => 'autocomplete' ),
791 - 'hintOptions' => array( 'tables' => $table_col_mapping ),
792 - ),
793 - )
794 - );
795 - }
796 -
797 - return $table_col_mapping;
309 + wp_iframe( array( $render, 'render' ) );
798 310 }
799 311
800 312 /**
801 - * Handle permissions from the new conslidated settings sidebar.
313 + * Handles chart data page.
314 + *
315 + * @since 1.0.0
316 + *
317 + * @access private
802 318 */
803 - private function handlePermissions() {
804 - if ( ! Visualizer_Module::is_pro() ) {
805 - return;
319 + private function _handleDataPage() {
320 + $data = $this->_getChartArray();
321 +
322 + $render = new Visualizer_Render_Page_Data();
323 + $render->chart = $this->_chart;
324 + $render->type = $data['type'];
325 +
326 + unset( $data['settings']['width'], $data['settings']['height'] );
327 +
328 + wp_enqueue_style( 'visualizer-frame' );
329 + wp_enqueue_script( 'visualizer-render' );
330 + wp_localize_script( 'visualizer-render', 'visualizer', array(
331 + 'l10n' => array(
332 + 'remotecsv_prompt' => esc_html__( 'Please, enter the URL of CSV file:', 'visualizer' ),
333 + 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
334 + ),
335 + 'charts' => array(
336 + 'canvas' => $data,
337 + ),
338 + ) );
339 +
340 + // Added by Ash/Upwork
341 + if ( defined( 'Visualizer_Pro' ) ) {
342 + global $Visualizer_Pro;
343 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
806 344 }
345 + // Added by Ash/Upwork
346 + $this->_addAction( 'admin_head', 'renderFlattrScript' );
807 347
808 - // we will not support old free and new pro.
809 - // handling new free and old pro.
810 - if ( has_action( 'visualizer_pro_handle_tab' ) ) {
811 - do_action( 'visualizer_pro_handle_tab', 'permissions', $this->_chart );
812 - } else {
813 - do_action( 'visualizer_handle_permissions', $this->_chart );
814 - }
348 + wp_iframe( array( $render, 'render' ) );
815 349 }
816 350
817 351 /**
818 352 * Handle data and settings page
@@ -817,252 +351,81 @@
817 351 /**
818 352 * Handle data and settings page
819 353 */
820 354 private function _handleDataAndSettingsPage() {
821 - if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
822 - $is_canceled = isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] );
823 - $is_newly_created = $this->_chart->post_status === 'auto-draft';
824 -
825 - if ( isset( $_POST['map_api_key'] ) && current_user_can( 'manage_options' ) ) {
826 - update_option( 'visualizer-map-api-key', sanitize_text_field( wp_unslash( $_POST['map_api_key'] ) ) );
827 - }
828 -
829 - if ( $is_newly_created && ! $is_canceled ) {
355 + if ( $_SERVER['REQUEST_METHOD'] == 'POST' && wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ) ) ) {
356 + if ( $this->_chart->post_status == 'auto-draft' ) {
830 357 $this->_chart->post_status = 'publish';
831 -
832 - // 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.
833 - // we do not want any difference in data so disable revisions temporarily.
834 - $this->disableRevisionsTemporarily();
835 -
836 358 wp_update_post( $this->_chart->to_array() );
837 359 }
838 - // save meta data only when it is NOT being canceled.
839 - if ( ! $is_canceled ) {
840 - $post_settings = $_POST;
841 - $existing = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
842 - if ( isset( $existing['colors'] ) && is_array( $existing['colors'] ) && ! isset( $post_settings['colors'] ) ) {
843 - $post_settings['colors'] = $existing['colors'];
844 - }
845 - $post_settings = $this->sanitizeSettings( $post_settings );
846 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $post_settings );
847 360
848 - // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
849 - // this will help in searching with the chart id.
850 - $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
851 - $title = null;
852 - if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
853 - $title = $settings['title'];
854 - if ( is_array( $title ) ) {
855 - $title = $settings['title']['text'];
856 - }
857 - }
858 - if ( empty( $title ) ) {
859 - $title = $this->_chart->ID;
860 - }
861 - $settings['internal_title'] = $title;
862 - $settings_label = isset( $settings['pieResidueSliceLabel'] ) ? $settings['pieResidueSliceLabel'] : '';
863 - if ( empty( $settings_label ) ) {
864 - $settings['pieResidueSliceLabel'] = esc_html__( 'Other', 'visualizer' );
865 - } else {
866 - $settings['pieResidueSliceLabel'] = $settings_label;
867 - }
868 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
869 - }
870 - $render = new Visualizer_Render_Page_Send();
361 + update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
362 +
363 + $render = new Visualizer_Render_Page_Send();
871 364 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
365 +
872 366 wp_iframe( array( $render, 'render' ) );
873 367 return;
874 368 }
875 - $data = $this->_getChartArray();
876 - $sidebar = '';
877 - $sidebar_class = $this->load_chart_class_name( $this->_chart->ID );
369 +
370 + $data = $this->_getChartArray();
371 +
372 + $sidebar = '';
373 + $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
878 374 if ( class_exists( $sidebar_class, true ) ) {
879 - $sidebar = new $sidebar_class( $data['settings'] );
375 + $sidebar = new $sidebar_class( $data['settings'] );
880 376 $sidebar->__series = $data['series'];
881 - $sidebar->__data = $data['data'];
377 + $sidebar->__data = $data['data'];
882 378 } else {
883 - $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
884 - if ( $sidebar !== '' ) {
379 + $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
380 + if ( $sidebar != '' ) {
885 381 $sidebar->__series = $data['series'];
886 - $sidebar->__data = $data['data'];
382 + $sidebar->__data = $data['data'];
887 383 }
888 384 }
889 - unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
385 +
386 + unset( $data['settings']['width'], $data['settings']['height'] );
387 +
388 + wp_enqueue_style( 'visualizer-frame' );
890 389 wp_enqueue_style( 'wp-color-picker' );
891 390 wp_enqueue_style( 'visualizer-frame' );
391 +
892 392 wp_enqueue_script( 'visualizer-preview' );
893 - wp_enqueue_script( 'visualizer-chosen' );
894 393 wp_enqueue_script( 'visualizer-render' );
895 - wp_enqueue_code_editor( array( 'type' => 'application/json' ) );
394 + wp_localize_script( 'visualizer-render', 'visualizer', array(
395 + 'l10n' => array(
396 + 'remotecsv_prompt' => esc_html__( 'Please, enter the URL of CSV file:', 'visualizer' ),
397 + 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
398 + ),
399 + 'charts' => array(
400 + 'canvas' => $data,
401 + ),
402 + ) );
896 403
897 - if ( Visualizer_Module::can_show_feature( 'simple-editor' ) ) {
898 - wp_enqueue_script( 'visualizer-editor-simple' );
899 - wp_localize_script(
900 - 'visualizer-editor-simple',
901 - 'visualizer1',
902 - array(
903 - 'ajax' => array(
904 - 'url' => admin_url( 'admin-ajax.php' ),
905 - 'nonces' => array(),
906 - 'actions' => array(),
907 - ),
908 - )
909 - );
910 - }
404 + $render = new Visualizer_Render_Page_Data();
405 + $render->chart = $this->_chart;
406 + $render->type = $data['type'];
911 407
912 - $table_col_mapping = $this->loadCodeEditorAssets( $this->_chart->ID );
913 -
914 - wp_localize_script(
915 - 'visualizer-render',
916 - 'visualizer',
917 - array(
918 - 'l10n' => array(
919 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
920 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
921 - 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
922 - 'select_columns' => esc_html__( 'Please select a few columns to include in the chart.', 'visualizer' ),
923 - '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' ),
924 - 'copied' => __( 'The data has been copied to your clipboard. Hit Ctrl-V/Cmd-V in your spreadsheet editor to paste the data.', 'visualizer' ),
925 - 'invalid_format' => esc_html__( 'This format pattern is not supported in the series settings field. Use the Manual Configuration option instead.', 'visualizer' ),
926 - ),
927 - 'charts' => array(
928 - 'canvas' => $data,
929 - 'id' => $this->_chart->ID,
930 - ),
931 - 'language' => $this->get_language(),
932 - 'map_api_key' => get_option( 'visualizer-map-api-key' ),
933 - 'ajax' => array(
934 - 'url' => admin_url( 'admin-ajax.php' ),
935 - 'nonces' => array(
936 - 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
937 - 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
938 - 'json_get_roots' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION ),
939 - 'json_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION ),
940 - 'json_set_schedule' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION ),
941 - ),
942 - 'actions' => array(
943 - 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
944 - 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
945 - 'json_get_roots' => Visualizer_Plugin::ACTION_JSON_GET_ROOTS,
946 - 'json_get_data' => Visualizer_Plugin::ACTION_JSON_GET_DATA,
947 - 'json_set_schedule' => Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE,
948 - ),
949 - ),
950 - 'db_query' => array(
951 - 'tables' => $table_col_mapping,
952 - ),
953 - 'is_pro' => Visualizer_Module::is_pro(),
954 - 'page_type' => 'chart',
955 - 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
956 - 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
957 - 'is_front' => false,
958 - 'rest_base' => get_rest_url( null, 'wc/v3/reports/' ),
959 - )
960 - );
961 -
962 - $render = new Visualizer_Render_Page_Data();
963 - $render->chart = $this->_chart;
964 - $render->type = $data['type'];
965 - $render->custom_css = $data['css'];
966 408 $render->sidebar = $sidebar;
967 409 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
968 - $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
410 + $render->button = filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART
969 411 ? esc_html__( 'Save Chart', 'visualizer' )
970 412 : esc_html__( 'Create Chart', 'visualizer' );
971 -
972 - $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
973 413 } else {
974 414 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
975 415 }
976 416
977 - do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
978 -
979 - if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
417 + if ( defined( 'Visualizer_Pro' ) ) {
980 418 global $Visualizer_Pro;
981 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
419 + $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
982 420 }
983 421
984 422 $this->_addAction( 'admin_head', 'renderFlattrScript' );
985 - wp_iframe( array( $render, 'render' ) );
986 - }
987 423
988 - /**
989 - * Handles chart type selection page.
990 - *
991 - * @since 1.0.0
992 - *
993 - * @access private
994 - */
995 - private function _handleTypesPage() {
996 - // process post request
997 - if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ), 'visualizer-upload-data' ) ) {
998 - $type = filter_input( INPUT_POST, 'type' );
999 - $library = filter_input( INPUT_POST, 'chart-library' );
1000 - if ( Visualizer_Module_Admin::checkChartStatus( $type ) ) {
1001 - if ( empty( $library ) ) {
1002 - // library cannot be empty.
1003 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
1004 - return;
1005 - }
1006 -
1007 - // save new chart type
1008 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
1009 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_LIBRARY, $library );
1010 - // if the chart has default data, update it with appropriate default data for new type
1011 - if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
1012 - $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
1013 - $source->fetch();
1014 - $this->_chart->post_content = $source->getData( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
1015 - wp_update_post( $this->_chart->to_array() );
1016 - update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1017 - }
1018 -
1019 - Visualizer_Module_Utility::set_defaults( $this->_chart );
1020 -
1021 - // redirect to next tab
1022 - // changed by Ash/Upwork
1023 - wp_redirect( esc_url_raw( add_query_arg( 'tab', 'settings' ) ) );
1024 -
1025 - return;
1026 - }
1027 - }
1028 - $render = new Visualizer_Render_Page_Types();
1029 - $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
1030 - $render->types = Visualizer_Module_Admin::_getChartTypesLocalized( false, false, false, 'types' );
1031 - $render->chart = $this->_chart;
1032 - wp_enqueue_style( 'visualizer-frame' );
1033 - wp_enqueue_script( 'visualizer-frame' );
1034 424 wp_iframe( array( $render, 'render' ) );
1035 425 }
1036 -
426 + // changed by Ash/Upwork
1037 427 /**
1038 - * Sanitize settings data from the request.
1039 - *
1040 - * @param array<string, mixed> $post_data The POST data to sanitize.
1041 - * @return array<string, mixed> The sanitized settings data.
1042 - */
1043 - private function sanitizeSettings( $post_data ): array {
1044 - $chart_img = '';
1045 - if ( isset( $post_data['chart-img'] ) ) {
1046 - $chart_img = wp_unslash( $post_data['chart-img'] );
1047 - unset( $post_data['chart-img'] );
1048 - }
1049 -
1050 - $post_data = map_deep(
1051 - $post_data,
1052 - 'sanitize_textarea_field'
1053 - );
1054 -
1055 - // The value is a client-side canvas export; keep it only when it is a
1056 - // base64 image data URI so nothing else is ever stored unsanitized.
1057 - if ( is_string( $chart_img ) && preg_match( '#^data:image/(png|jpeg|webp);base64,[A-Za-z0-9+/ ]+=*$#', $chart_img ) ) {
1058 - $post_data['chart-img'] = $chart_img;
1059 - }
1060 -
1061 - return $post_data;
1062 - }
1063 -
1064 - /**
1065 428 * Renders flattr script in the iframe <head>
1066 429 *
1067 430 * @since 1.4.2
1068 431 * @action admin_head
@@ -1073,202 +436,8 @@
1073 436 echo '';
1074 437 }
1075 438
1076 439 /**
1077 - * Processes the CSV that is sent in the request as a string.
1078 - *
1079 - * @since 3.2.0
1080 - */
1081 - /**
1082 - * Determines whether a remote URL serves an XLSX file.
1083 - *
1084 - * Used as a fallback when the URL path has no recognisable file extension
1085 - * (e.g. SharePoint, signed S3 URLs, or "download?id=…" endpoints).
1086 - *
1087 - * Uses the shared remote-fetch policy to block non-public destinations,
1088 - * and streams the response to a temp file so no body data is held in memory
1089 - * regardless of whether the server honours the Range header.
1090 - *
1091 - * The check relies on the ZIP magic number (PK\x03\x04) that every XLSX
1092 - * file begins with, making it immune to misleading Content-Type headers
1093 - * such as application/octet-stream. Content-Type is used as a last-resort
1094 - * fallback only when the temp file is empty (e.g. a HEAD-only server).
1095 - *
1096 - * @access private
1097 - * @param string $url The remote URL to probe.
1098 - * @return bool TRUE if the file appears to be XLSX, FALSE otherwise.
1099 - */
1100 - private static function _url_is_xlsx( $url ) {
1101 - $tmpfile = wp_tempnam( 'visualizer_xlsx_probe' );
1102 - if ( ! $tmpfile ) {
1103 - return false;
1104 - }
1105 -
1106 - $response = Visualizer_Remote_Fetch::request(
1107 - $url,
1108 - array(
1109 - 'timeout' => 10,
1110 - 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ),
1111 - 'headers' => array( 'Range' => 'bytes=0-3' ),
1112 - 'stream' => true,
1113 - 'filename' => $tmpfile,
1114 - 'limit_response_size' => 4,
1115 - )
1116 - );
1117 -
1118 - if ( is_wp_error( $response ) ) {
1119 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1120 - return false;
1121 - }
1122 -
1123 - $magic = '';
1124 - // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen
1125 - $fh = @fopen( $tmpfile, 'rb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1126 - if ( $fh ) {
1127 - $magic = fread( $fh, 4 ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fread
1128 - fclose( $fh ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose
1129 - }
1130 - @unlink( $tmpfile ); // phpcs:ignore WordPress.PHP.NoSilencedErrors
1131 -
1132 - if ( strlen( $magic ) >= 4 ) {
1133 - // XLSX (and all ZIP-based Office formats) start with PK\x03\x04.
1134 - return $magic === "PK\x03\x04";
1135 - }
1136 -
1137 - // Last resort: server returned an empty body (e.g. ignored Range and
1138 - // returned only headers). Check Content-Type from the same response.
1139 - // application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
1140 - return false !== strpos(
1141 - wp_remote_retrieve_header( $response, 'content-type' ),
1142 - 'spreadsheetml'
1143 - );
1144 - }
1145 -
1146 - /**
1147 - * Parses a raw CSV string or editor payload and returns a source object.
1148 - *
1149 - * @access private
1150 - * @param string $data The raw CSV data string.
1151 - * @param string $editor_type The editor type ('text' or 'tabular').
1152 - * @return Visualizer_Source|null The populated source object, or null on failure.
1153 - */
1154 - private function handleCSVasString( $data, $editor_type ) {
1155 - $source = null;
1156 -
1157 - switch ( $editor_type ) {
1158 - case 'text':
1159 - // data coming in from the text editor.
1160 - $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
1161 - $handle = fopen( $tmpfile, 'w' );
1162 - $values = preg_split( '/[\n\r]+/', stripslashes( trim( $data ) ) );
1163 - if ( $values ) {
1164 - foreach ( $values as $row ) {
1165 - if ( empty( $row ) ) {
1166 - continue;
1167 - }
1168 - $row = explode( ',', $row );
1169 - $row = array_map(
1170 - function ( $r ) {
1171 - return '' === $r ? ' ' : $r;
1172 - },
1173 - $row
1174 - );
1175 - $row = implode( ',', $row );
1176 - // don't use fpucsv here because we need to just dump the data
1177 - // minus the empty rows
1178 - // because fputcsv needs to tokenize
1179 - // we can standardize the CSV enclosure here and replace all ' with "
1180 - // we can assume that if there are an even number of ' they should be changed to "
1181 - // but that will screw up words like fo'c'sle
1182 - // so here let's just assume ' will NOT be used for enclosures
1183 - fwrite( $handle, $row );
1184 - fwrite( $handle, PHP_EOL );
1185 - }
1186 - }
1187 - $source = new Visualizer_Source_Csv( $tmpfile );
1188 - fclose( $handle );
1189 - break;
1190 - case 'table':
1191 - // Import from Chart
1192 - // fall-through.
1193 - case 'excel':
1194 - // data coming in from the excel editor.
1195 - $source = apply_filters( 'visualizer_pro_handle_chart_data', $data, '' );
1196 - break;
1197 - }
1198 - return $source;
1199 - }
1200 -
1201 - /**
1202 - * Parses the data uploaded as an HTML table.
1203 - *
1204 - * @since 3.2.0
1205 - *
1206 - * @access private
1207 - */
1208 - private function handleTabularData() {
1209 - $csv = array();
1210 - // the datatable mentions the headers twice, so lets remove the duplicates.
1211 - $headers = array_unique( array_filter( $_POST['header'] ) );
1212 - $types = $_POST['type'];
1213 -
1214 - // capture all the indexes that correspond to excluded columns.
1215 - $exclude = array();
1216 - $index = 0;
1217 - foreach ( $types as $type ) {
1218 - if ( empty( $type ) ) {
1219 - $exclude[] = $index;
1220 - }
1221 - ++$index;
1222 - }
1223 -
1224 - // when N headers are being renamed, the number of headers increases by N
1225 - // because of the way datatable duplicates header information
1226 - // so unset the headers that have been renamed.
1227 - if ( count( $headers ) !== count( $types ) ) {
1228 - $to = count( $headers );
1229 - for ( $i = count( $types ); $i < $to; $i++ ) {
1230 - unset( $headers[ $i + 1 ] );
1231 - }
1232 - }
1233 -
1234 - $columns = array();
1235 - for ( $i = 0; $i < count( $headers ); $i++ ) {
1236 - if ( ! isset( $_POST[ 'data' . $i ] ) ) {
1237 - continue;
1238 - }
1239 - $columns[ $i ] = $_POST[ 'data' . $i ];
1240 - }
1241 -
1242 - $csv[] = $headers;
1243 - $csv[] = $types;
1244 - for ( $j = 0; $j < count( $columns[0] ); $j++ ) {
1245 - $row = array();
1246 - for ( $i = 0; $i < count( $headers ); $i++ ) {
1247 - $row[] = sanitize_text_field( $columns[ $i ][ $j ] );
1248 - }
1249 - $csv[] = $row;
1250 - }
1251 -
1252 - $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
1253 - $handle = fopen( $tmpfile, 'w' );
1254 -
1255 - if ( $csv ) {
1256 - $index = 0;
1257 - foreach ( $csv as $row ) {
1258 - // remove all the cells corresponding to the excluded headers.
1259 - foreach ( $exclude as $j ) {
1260 - unset( $row[ $j ] );
1261 - }
1262 - fputcsv( $handle, $row );
1263 - }
1264 - }
1265 - $source = new Visualizer_Source_Csv( $tmpfile );
1266 - fclose( $handle );
1267 - return $source;
1268 - }
1269 -
1270 - /**
1271 440 * Parses uploaded CSV file and saves new data for the chart.
1272 441 *
1273 442 * @since 1.0.0
1274 443 *
@@ -1274,131 +443,40 @@
1274 443 *
1275 444 * @access public
1276 445 */
1277 446 public function uploadData() {
1278 - // if this is being called internally from pro and VISUALIZER_DO_NOT_DIE is set.
1279 - // otherwise, assume this is a normal web request.
1280 - $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
1281 - // $can_die also gates the capability checks below, so VISUALIZER_DO_NOT_DIE must stay internal-only (never set from request input or globally).
1282 -
1283 - // validate nonce; capability check applies to web requests only, not trusted internal calls.
1284 - if (
1285 - ! isset( $_GET['nonce'] ) ||
1286 - ! wp_verify_nonce( $_GET['nonce'], 'visualizer-upload-data' ) ||
1287 - ( $can_die && ! current_user_can( 'edit_posts' ) )
1288 - ) {
1289 - if ( ! $can_die ) {
1290 - return;
1291 - }
447 + // validate nonce
448 + if ( ! wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ) ) ) {
1292 449 status_header( 403 );
1293 450 exit;
1294 451 }
1295 452
1296 453 // check chart, if chart exists
1297 - // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
1298 - $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1299 - $chart = $chart_id ? get_post( $chart_id ) : null;
1300 - if (
1301 - ! $chart_id ||
1302 - ! $chart ||
1303 - $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ||
1304 - ( $can_die && ! current_user_can( 'edit_post', $chart_id ) )
1305 - ) {
1306 - if ( ! $can_die ) {
1307 - return;
1308 - }
454 + $chart_id = filter_input( INPUT_GET, 'chart', FILTER_VALIDATE_INT );
455 + if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
1309 456 status_header( 400 );
1310 457 exit;
1311 458 }
1312 459
1313 - 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__ );
1314 -
1315 - if ( ! isset( $_POST['vz-import-time'] ) ) {
1316 - apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
1317 - }
1318 -
1319 - if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
1320 - // delete the filters in case this chart is being uploaded from other data sources
1321 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
1322 - delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
1323 - delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
1324 -
1325 - // delete "import from db" specific parameters.
1326 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
1327 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
1328 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS );
1329 - }
1330 -
1331 - // delete json related data.
1332 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL );
1333 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT );
1334 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING );
1335 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_HEADERS );
1336 -
1337 - // delete last error
1338 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR );
1339 -
1340 - // delete editor related data.
1341 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR );
1342 -
1343 - // delete this so that a JSON import can be later edited manually without a problem.
1344 - delete_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE );
1345 -
1346 460 $source = null;
1347 461 $render = new Visualizer_Render_Page_Update();
462 + if ( filter_input( INPUT_POST, 'remote_data', FILTER_VALIDATE_URL ) ) {
463 + $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
464 + } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
465 + $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1348 466
1349 - $remote_data = false;
1350 - if ( isset( $_POST['remote_data'] ) && function_exists( 'wp_http_validate_url' ) ) {
1351 - $remote_data = wp_http_validate_url( $_POST['remote_data'] );
1352 - }
1353 - if ( false !== $remote_data ) {
1354 - $remote_ext = strtolower( pathinfo( parse_url( $remote_data, PHP_URL_PATH ), PATHINFO_EXTENSION ) );
1355 - if ( 'xlsx' === $remote_ext || ( 'csv' !== $remote_ext && self::_url_is_xlsx( $remote_data ) ) ) {
1356 - $source = new Visualizer_Source_Xlsx_Remote( $remote_data );
1357 - } else {
1358 - $source = new Visualizer_Source_Csv_Remote( $remote_data );
1359 - }
1360 - if ( isset( $_POST['vz-import-time'] ) ) {
1361 - apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $remote_data, $_POST['vz-import-time'] );
1362 - }
1363 - } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] === 0 ) {
1364 - $local_ext = strtolower( pathinfo( isset( $_FILES['local_data']['name'] ) ? $_FILES['local_data']['name'] : '', PATHINFO_EXTENSION ) );
1365 - if ( 'xlsx' === $local_ext ) {
1366 - $source = new Visualizer_Source_Xlsx( $_FILES['local_data']['tmp_name'] );
1367 - } else {
1368 - $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
1369 - }
1370 - } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
1371 - $source = $this->handleCSVasString( $_POST['chart_data'], $_POST['editor-type'] );
1372 - update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
1373 - } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
1374 - $source = $this->handleTabularData();
1375 - update_post_meta( $chart_id, Visualizer_Plugin::CF_EDITOR, $_POST['editor-type'] );
467 + // Added by Ash/Upwork
468 + } elseif ( defined( 'Visualizer_Pro' ) && isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
469 + global $Visualizer_Pro;
470 + $source = $Visualizer_Pro->_handleChartData( $_POST['chart_data'] );
471 + // Added by Ash/Upwork
1376 472 } else {
1377 - 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__ );
1378 - $render->message = esc_html__( 'No CSV file was received. Select a file and try uploading again.', 'visualizer' );
1379 - update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, esc_html__( 'No CSV file was received. Select a file and try uploading again.', 'visualizer' ) );
473 + $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
1380 474 }
1381 475
1382 - 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__ );
1383 -
1384 476 if ( $source ) {
1385 477 if ( $source->fetch() ) {
1386 - $content = $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) );
1387 - $populate = true;
1388 - $json = self::decode_content( $content );
1389 - if ( is_array( $json ) ) {
1390 - // if source exists, so should data. if source exists but data is blank, do not populate the chart.
1391 - // if we populate the data even if it is empty, the chart will show "Table has no columns".
1392 - if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
1393 - 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__ );
1394 - update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, sprintf( 'Not populating chart data as source exists (%s) but data is empty!', $json['source'] ) );
1395 - $populate = false;
1396 - }
1397 - }
1398 - if ( $populate ) {
1399 - $chart->post_content = $content;
1400 - }
478 + $chart->post_content = $source->getData();
1401 479 wp_update_post( $chart->to_array() );
1402 480
1403 481 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1404 482 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
@@ -1403,44 +481,17 @@
1403 481 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1404 482 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1405 483 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1406 484
1407 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Updated post for chart %d', $chart_id ), 'debug', __FILE__, __LINE__ );
1408 -
1409 - Visualizer_Module_Utility::set_defaults( $chart, null );
1410 -
1411 - $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
1412 - if ( isset( $settings['series'] ) && ! ( count( $settings['series'] ) - count( $source->getSeries() ) > 1 ) ) {
1413 - $diff_total_series = abs( count( $settings['series'] ) - count( $source->getSeries() ) );
1414 - if ( $diff_total_series ) {
1415 - foreach ( range( 1, $diff_total_series ) as $k => $diff_series ) {
1416 - $settings['series'][] = end( $settings['series'] );
1417 - }
1418 - update_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
1419 - }
1420 - }
1421 -
1422 - $render->id = $chart->ID;
1423 - $render->data = json_encode( $source->getRawData( get_post_meta( $chart->ID, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
485 + $render->data = json_encode( $source->getRawData() );
1424 486 $render->series = json_encode( $source->getSeries() );
1425 - $render->settings = json_encode( $settings );
1426 487 } else {
1427 - $error = $source->get_error();
1428 - if ( empty( $error ) ) {
1429 - $error = esc_html__( 'The CSV file couldn\'t be read. Check that it\'s properly formatted and try again.', 'visualizer' );
1430 - }
1431 - $render->message = $error;
1432 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( '%s for chart %d.', $error, $chart_id ), 'error', __FILE__, __LINE__ );
1433 - update_post_meta( $chart_id, Visualizer_Plugin::CF_ERROR, $error );
488 + $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
1434 489 }
1435 - } else {
1436 - do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unknown internal error for chart %d.', $chart_id ), 'error', __FILE__, __LINE__ );
1437 490 }
491 +
1438 492 $render->render();
1439 - if ( ! $can_die ) {
1440 - return;
1441 - }
1442 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
493 + exit;
1443 494 }
1444 495
1445 496 /**
1446 497 * Clones the chart.
@@ -1450,54 +501,42 @@
1450 501 * @access public
1451 502 */
1452 503 public function cloneChart() {
1453 504 $chart_id = $success = false;
1454 - $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
1455 - if ( $nonce ) {
1456 - $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1457 - if ( $chart_id && self::can_edit_chart( $chart_id ) ) {
1458 - $chart = get_post( $chart_id );
1459 - $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
505 + $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
506 + $capable = current_user_can( 'edit_posts' );
507 + if ( $nonce && $capable ) {
508 + $chart_id = filter_input( INPUT_GET, 'chart', FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1 ) ) );
509 + if ( $chart_id ) {
510 + $chart = get_post( $chart_id );
511 + $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1460 512 }
1461 513 }
1462 - $redirect = remove_query_arg( 'vaction', wp_get_referer() );
514 +
515 + $redirect = wp_get_referer();
1463 516 if ( $success ) {
1464 - $new_chart_id = wp_insert_post(
1465 - array(
1466 - 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
1467 - 'post_title' => 'Visualization',
1468 - 'post_author' => get_current_user_id(),
1469 - 'post_status' => $chart->post_status,
1470 - 'post_content' => $chart->post_content,
1471 - )
1472 - );
1473 - if ( is_wp_error( $new_chart_id ) ) {
1474 - 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__ );
1475 - } else {
1476 - $post_meta = get_post_meta( $chart_id );
1477 - foreach ( $post_meta as $key => $value ) {
1478 - if ( strpos( $key, 'visualizer-' ) !== false ) {
1479 - add_post_meta( $new_chart_id, $key, self::maybe_decode_content( $value[0] ) );
1480 - }
1481 - }
1482 - $redirect = esc_url(
1483 - add_query_arg(
1484 - array(
1485 - 'page' => 'visualizer',
1486 - 'type' => filter_input( INPUT_GET, 'type' ),
1487 - 'vaction' => false,
1488 - ),
1489 - admin_url( 'admin.php' )
1490 - ),
1491 - null,
1492 - 'db'
1493 - );
517 + $new_chart_id = wp_insert_post( array(
518 + 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
519 + 'post_title' => 'Visualization',
520 + 'post_author' => get_current_user_id(),
521 + 'post_status' => $chart->post_status,
522 + 'post_content' => $chart->post_content,
523 + ) );
524 +
525 + if ( $new_chart_id && ! is_wp_error( $new_chart_id ) ) {
526 + add_post_meta( $new_chart_id, Visualizer_Plugin::CF_CHART_TYPE, get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true ) );
527 + add_post_meta( $new_chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, get_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, true ) );
528 + add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SOURCE, get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true ) );
529 + add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SERIES, get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true ) );
530 + add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SETTINGS, get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) );
531 +
532 + $redirect = add_query_arg( array(
533 + 'page' => 'visualizer',
534 + 'type' => filter_input( INPUT_GET, 'type' ),
535 + ), admin_url( 'upload.php' ) );
1494 536 }
1495 537 }
1496 538
1497 - if ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) {
1498 - wp_die();
1499 - }
1500 539 wp_redirect( $redirect );
1501 540 exit;
1502 541 }
1503 542
@@ -1509,292 +548,79 @@
1509 548 * @access public
1510 549 */
1511 550 public function exportData() {
1512 551 check_ajax_referer( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION, 'security' );
1513 - $chart_id = isset( $_GET['chart'] ) ? filter_var(
1514 - $_GET['chart'],
1515 - FILTER_VALIDATE_INT,
1516 - array(
1517 - 'options' => array(
1518 - 'min_range' => 1,
1519 - ),
1520 - )
1521 - ) : '';
1522 - if ( $chart_id && self::can_edit_chart( $chart_id ) ) {
1523 - $data = $this->_getDataAs( $chart_id, 'csv' );
1524 - if ( $data ) {
1525 - echo wp_send_json_success( $data );
552 +
553 + $chart_id = $success = false;
554 + $capable = current_user_can( 'edit_posts' );
555 + if ( $capable ) {
556 + $chart_id = filter_input( INPUT_GET, 'chart', FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 1 ) ) );
557 + if ( $chart_id ) {
558 + $chart = get_post( $chart_id );
559 + $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
1526 560 }
1527 561 }
1528 562
1529 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1530 - }
563 + if ( $success ) {
564 + $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
565 + $filename = $settings['title'];
566 + if ( empty( $filename ) ) {
567 + $filename = 'export.csv';
568 + } else {
569 + $filename .= '.csv';
570 + }
571 + $rows = array();
572 + $series = get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true );
573 + $data = unserialize( $chart->post_content );
574 + if ( ! empty( $series ) ) {
575 + $row = array();
576 + foreach ( $series as $array ) {
577 + $row[] = $array['label'];
578 + }
579 + $rows[] = $row;
1531 580
1532 - /**
1533 - * Handles chart data page.
1534 - *
1535 - * @since 1.0.0
1536 - *
1537 - * @access private
1538 - */
1539 - private function _handleDataPage() {
1540 - $data = $this->_getChartArray();
1541 - $render = new Visualizer_Render_Page_Data();
1542 - $render->chart = $this->_chart;
1543 - $render->type = $data['type'];
581 + $row = array();
582 + foreach ( $series as $array ) {
583 + $row[] = $array['type'];
584 + }
585 + $rows[] = $row;
586 + }
1544 587
1545 - if ( $data && $data['settings'] ) {
1546 - unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1547 - }
1548 - wp_enqueue_style( 'visualizer-frame' );
1549 - wp_enqueue_script( 'visualizer-render' );
1550 - wp_localize_script(
1551 - 'visualizer-render',
1552 - 'visualizer',
1553 - array(
1554 - 'l10n' => array(
1555 - 'invalid_source' => esc_html__( 'The URL you entered is invalid. Please enter a valid URL.', 'visualizer' ),
1556 - 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1557 - 'invalid_format' => esc_html__( 'This format pattern is not supported in the series settings field. To display percentages, use the Manual Configuration option instead.', 'visualizer' ),
1558 - ),
1559 - 'charts' => array(
1560 - 'canvas' => $data,
1561 - ),
1562 - )
1563 - );
588 + if ( ! empty( $data ) ) {
589 + foreach ( $data as $array ) {
590 + // ignore strings
591 + if ( ! is_array( $array ) ) { continue; }
1564 592
1565 - do_action( 'visualizer_enqueue_scripts_and_styles', $data, $this->_chart->ID );
1566 -
1567 - if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
1568 - global $Visualizer_Pro;
1569 - $Visualizer_Pro->_enqueueScriptsAndStyles( $data, $this->_chart->ID );
1570 - }
1571 -
1572 - // Added by Ash/Upwork
1573 - $this->_addAction( 'admin_head', 'renderFlattrScript' );
1574 - wp_iframe( array( $render, 'render' ) );
1575 - }
1576 -
1577 - /**
1578 - * Returns the data for the query.
1579 - *
1580 - * @access public
1581 - */
1582 - public function getQueryData() {
1583 - check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1584 -
1585 - if ( ! current_user_can( 'administrator' ) ) {
1586 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1587 - }
1588 - if ( ! is_super_admin() ) {
1589 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1590 - }
1591 -
1592 - if ( ! Visualizer_Module::is_pro() ) {
1593 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1594 - }
1595 -
1596 - $params = wp_parse_args( $_POST['params'] );
1597 - $chart_id = filter_var( $params['chart_id'], FILTER_VALIDATE_INT );
1598 - $query = trim( $params['query'], ';' );
1599 -
1600 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1601 - $html = $source->fetch( true );
1602 - $error = $source->get_error();
1603 - if ( ! empty( $error ) ) {
1604 - wp_send_json_error( array( 'msg' => $error ) );
1605 - }
1606 - wp_send_json_success( array( 'table' => $html ) );
1607 - }
1608 -
1609 - /**
1610 - * Saves the query and the schedule.
1611 - *
1612 - * @access public
1613 - */
1614 - public function saveQuery() {
1615 - check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1616 -
1617 - if ( ! current_user_can( 'administrator' ) ) {
1618 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1619 - }
1620 - if ( ! is_super_admin() ) {
1621 - wp_send_json_error( array( 'msg' => __( 'Action not allowed for this user.', 'visualizer' ) ) );
1622 - }
1623 -
1624 - if ( ! Visualizer_Module::is_pro() ) {
1625 - wp_send_json_error( array( 'msg' => __( 'Feature is not available.', 'visualizer' ) ) );
1626 - }
1627 -
1628 - $chart_id = filter_input(
1629 - INPUT_GET,
1630 - 'chart',
1631 - FILTER_VALIDATE_INT,
1632 - array(
1633 - 'options' => array(
1634 - 'min_range' => 1,
1635 - ),
1636 - )
1637 - );
1638 -
1639 - $hours = filter_input(
1640 - INPUT_POST,
1641 - 'refresh',
1642 - FILTER_VALIDATE_FLOAT,
1643 - array(
1644 - 'options' => array(
1645 - 'min_range' => -1,
1646 - 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1647 - ),
1648 - )
1649 - );
1650 -
1651 - if ( ! is_numeric( $hours ) ) {
1652 - $hours = -1;
1653 - }
1654 -
1655 - $render = new Visualizer_Render_Page_Update();
1656 - if ( $chart_id ) {
1657 - $params = wp_parse_args( $_POST['params'] );
1658 - $query = trim( $params['query'], ';' );
1659 - $source = new Visualizer_Source_Query( stripslashes( $query ), $chart_id, $params );
1660 - $source->fetch( false );
1661 - $error = $source->get_error();
1662 - if ( empty( $error ) ) {
1663 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $query ) );
1664 - update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1665 - update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1666 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1667 - update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1668 - if ( isset( $params['db_type'] ) && $params['db_type'] !== Visualizer_Plugin::WP_DB_NAME ) {
1669 - $remote_db_params = $params;
1670 - unset( $remote_db_params['query'] );
1671 - unset( $remote_db_params['chart_id'] );
1672 - update_post_meta( $chart_id, Visualizer_Plugin::CF_REMOTE_DB_PARAMS, $remote_db_params );
593 + // if this is an array of arrays...
594 + if ( is_array( $array[0] ) ) {
595 + foreach ( $array as $arr ) {
596 + $rows[] = $arr;
597 + }
598 + } else {
599 + // just an array
600 + $rows[] = $array;
601 + }
1673 602 }
603 + }
1674 604
1675 - $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
1676 - $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
1677 - update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
605 + $fp = tmpfile();
606 + foreach ( $rows as $row ) {
607 + fputcsv( $fp, $row );
608 + }
609 + rewind( $fp );
1678 610
1679 - wp_update_post(
1680 - array(
1681 - 'ID' => $chart_id,
1682 - 'post_content' => $source->getData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ),
1683 - )
1684 - );
1685 - $render->data = json_encode( $source->getRawData( get_post_meta( $chart_id, Visualizer_Plugin::CF_EDITABLE_TABLE, true ) ) );
1686 - $render->series = json_encode( $source->getSeries() );
1687 - $render->id = $chart_id;
1688 - } else {
1689 - $render->message = $error;
611 + $csv = '';
612 + while ( ($array = fgetcsv( $fp )) !== false ) {
613 + if ( strlen( $csv ) > 0 ) { $csv .= PHP_EOL; }
614 + $csv .= implode( ',', $array );
1690 615 }
1691 - }
1692 - $render->render();
1693 - if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1694 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1695 - }
1696 - }
616 + fclose( $fp );
1697 617
618 + echo wp_send_json_success(array(
619 + 'csv' => $csv,
620 + 'name' => $filename,
621 + ));
622 + }// End if().
1698 623
1699 - /**
1700 - * Saves the filter query and the schedule.
1701 - *
1702 - * @access public
1703 - */
1704 - public function saveFilter() {
1705 - check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1706 -
1707 - $chart_id = isset( $_GET['chart'] ) ? filter_var(
1708 - $_GET['chart'],
1709 - FILTER_VALIDATE_INT,
1710 - array(
1711 - 'options' => array(
1712 - 'min_range' => 1,
1713 - ),
1714 - )
1715 - ) : false;
1716 -
1717 - if ( ! self::can_edit_chart( $chart_id ) ) {
1718 - wp_send_json_error( array( 'msg' => esc_html__( 'You do not have permission to perform this action.', 'visualizer' ) ), 403 );
1719 - }
1720 -
1721 - $hours = filter_input(
1722 - INPUT_POST,
1723 - 'refresh',
1724 - FILTER_VALIDATE_FLOAT,
1725 - array(
1726 - 'options' => array(
1727 - 'min_range' => -1,
1728 - 'max_range' => apply_filters( 'visualizer_is_business', false ) ? PHP_INT_MAX : -1,
1729 - ),
1730 - )
1731 - );
1732 -
1733 - if ( ! is_numeric( $hours ) ) {
1734 - $hours = -1;
1735 - }
1736 -
1737 - do_action( 'visualizer_save_filter', $chart_id, $hours );
1738 -
1739 - if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1740 - ( defined( 'WP_TESTS_DOMAIN' ) && function_exists( 'tests_add_filter' ) ) ? wp_die() : exit();
1741 - }
1742 - }
1743 -
1744 - /**
1745 - * Save chart image.
1746 - *
1747 - * @param string $base64_img Chart image.
1748 - * @param int $chart_id Chart ID.
1749 - * @param bool $save_attachment Save attachment.
1750 - * @return int Attachment ID, or 0 when no attachment was saved.
1751 - */
1752 - public function save_chart_image( $base64_img, $chart_id, $save_attachment = true ) {
1753 - // Delete old chart image.
1754 - $old_attachment_id = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_IMAGE, true );
1755 - if ( $old_attachment_id ) {
1756 - wp_delete_attachment( $old_attachment_id, true );
1757 - }
1758 -
1759 - if ( ! $save_attachment ) {
1760 - return 0;
1761 - }
1762 -
1763 - // Upload dir.
1764 - $upload_dir = wp_upload_dir();
1765 - $upload_path = str_replace( '/', DIRECTORY_SEPARATOR, $upload_dir['path'] ) . DIRECTORY_SEPARATOR;
1766 -
1767 - $img = str_replace( 'data:image/png;base64,', '', (string) $base64_img );
1768 - $img = str_replace( ' ', '+', $img );
1769 - $decoded = base64_decode( $img, true );
1770 - // The value comes from an untrusted request; only write real PNG bytes to uploads.
1771 - if ( false === $decoded || 0 !== strncmp( $decoded, "\x89PNG\r\n\x1a\n", 8 ) ) {
1772 - return 0;
1773 - }
1774 - $filename = 'visualization-' . $chart_id . '.png';
1775 - $file_type = 'image/png';
1776 - $hashed_filename = $filename;
1777 -
1778 - // Save the image in the uploads directory.
1779 - require_once ABSPATH . '/wp-admin/includes/file.php';
1780 - \WP_Filesystem();
1781 - global $wp_filesystem;
1782 - if ( ! is_a( $wp_filesystem, 'WP_Filesystem_Base' ) ) {
1783 - $creds = request_filesystem_credentials( site_url() );
1784 - wp_filesystem( $creds );
1785 - }
1786 - $upload_file = $wp_filesystem->put_contents( $upload_path . $hashed_filename, $decoded );
1787 -
1788 - // Insert new chart image.
1789 - $attachment = array(
1790 - 'post_mime_type' => $file_type,
1791 - 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $hashed_filename ) ),
1792 - 'post_content' => '',
1793 - 'post_status' => 'inherit',
1794 - 'guid' => $upload_dir['url'] . '/' . basename( $hashed_filename ),
1795 - );
1796 -
1797 - $attach_id = wp_insert_attachment( $attachment, $upload_dir['path'] . '/' . $hashed_filename );
1798 - return $attach_id;
624 + exit;
1799 625 }
1800 626 }