PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.1.3
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.1.3
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
visualizer / classes / Visualizer / Module / Chart.php

Chart.php in Visualizer – Tables & Charts Manager with Built-in AI Generator 3.1.3, at classes/Visualizer/Module/Chart.php

911 lines 31.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
4 // +----------------------------------------------------------------------+
5 // | This program is free software; you can redistribute it and/or modify |
6 // | it under the terms of the GNU General Public License, version 2, as |
7 // | published by the Free Software Foundation. |
8 // | |
9 // | This program is distributed in the hope that it will be useful, |
10 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
12 // | GNU General Public License for more details. |
13 // | |
14 // | You should have received a copy of the GNU General Public License |
15 // | along with this program; if not, write to the Free Software |
16 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
17 // | MA 02110-1301 USA |
18 // +----------------------------------------------------------------------+
19 // | Author: Eugene Manuilov <eugene@manuilov.org> |
20 // +----------------------------------------------------------------------+
21 /**
22 * The module for all stuff related to getting, editing, creating and deleting charts.
23 *
24 * @category Visualizer
25 * @package Module
26 *
27 * @since 1.0.0
28 */
29 class Visualizer_Module_Chart extends Visualizer_Module {
30
31 const NAME = __CLASS__;
32
33 /**
34 * The chart object.
35 *
36 * @since 1.0.0
37 *
38 * @access private
39 * @var WP_Post
40 */
41 private $_chart;
42
43 /**
44 * Constructor.
45 *
46 * @since 1.0.0
47 *
48 * @access public
49 *
50 * @param Visualizer_Plugin $plugin The instance of the plugin.
51 */
52 public function __construct( Visualizer_Plugin $plugin ) {
53 parent::__construct( $plugin );
54 $this->_addAjaxAction( Visualizer_Plugin::ACTION_GET_CHARTS, 'getCharts' );
55 $this->_addAjaxAction( Visualizer_Plugin::ACTION_DELETE_CHART, 'deleteChart' );
56 $this->_addAjaxAction( Visualizer_Plugin::ACTION_CREATE_CHART, 'renderChartPages' );
57 $this->_addAjaxAction( Visualizer_Plugin::ACTION_EDIT_CHART, 'renderChartPages' );
58 $this->_addAjaxAction( Visualizer_Plugin::ACTION_UPLOAD_DATA, 'uploadData' );
59 $this->_addAjaxAction( Visualizer_Plugin::ACTION_CLONE_CHART, 'cloneChart' );
60 $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 $this->_addAjaxAction( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY, 'saveFilter' );
65 }
66
67 /**
68 * Fetches charts from database.
69 *
70 * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
71 *
72 * @since 1.0.0
73 *
74 * @access public
75 */
76 public function getCharts() {
77 $query_args = array(
78 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
79 'posts_per_page' => 9,
80 'paged' => filter_input(
81 INPUT_GET,
82 'page',
83 FILTER_VALIDATE_INT,
84 array(
85 'options' => array(
86 'min_range' => 1,
87 'default' => 1,
88 ),
89 )
90 ),
91 );
92 $filter = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
93 if ( empty( $filter ) ) {
94 // 'filter' is from the modal from the add media button.
95 $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
96 }
97
98 if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes() ) ) {
99 $query_args['meta_query'] = array(
100 array(
101 'key' => Visualizer_Plugin::CF_CHART_TYPE,
102 'value' => $filter,
103 'compare' => '=',
104 ),
105 );
106 }
107 $query = new WP_Query( $query_args );
108 $charts = array();
109 while ( $query->have_posts() ) {
110 $chart = $query->next_post();
111 $chart_data = $this->_getChartArray( $chart );
112 $chart_data['id'] = $chart->ID;
113 $chart_data['library'] = $this->load_chart_type( $chart->ID );
114 $css = '';
115 $settings = $chart_data['settings'];
116 $arguments = $this->get_inline_custom_css( 'visualizer-chart-' . $chart->ID, $settings );
117 if ( ! empty( $arguments ) ) {
118 $css = $arguments[0];
119 $settings = $arguments[1];
120 }
121 $chart_data['settings'] = $settings;
122 $chart_data['css'] = $css;
123 $charts[] = $chart_data;
124 }
125 self::_sendResponse(
126 array(
127 'success' => true,
128 'data' => $charts,
129 'total' => $query->max_num_pages,
130 )
131 );
132 }
133
134 /**
135 * Returns chart data required for rendering.
136 *
137 * @since 1.0.0
138 *
139 * @access private
140 *
141 * @param WP_Post $chart The chart object.
142 *
143 * @return array The array of chart data.
144 */
145 private function _getChartArray( WP_Post $chart = null ) {
146 if ( is_null( $chart ) ) {
147 $chart = $this->_chart;
148 }
149 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
150 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
151 $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( $chart->post_content ), $chart->ID, $type );
152 $library = $this->load_chart_type( $chart->ID );
153
154 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
155 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
156 if ( ! empty( $atts['settings'] ) ) {
157 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
158 }
159
160 $css = '';
161 $arguments = $this->get_inline_custom_css( 'visualizer-' . $chart->ID, $settings );
162 if ( ! empty( $arguments ) ) {
163 $css = $arguments[0];
164 $settings = $arguments[1];
165 }
166
167 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
168
169 return array(
170 'type' => $type,
171 'series' => $series,
172 'settings' => $settings,
173 'data' => $data,
174 'library' => $library,
175 'css' => $css,
176 'date_formats' => $date_formats,
177 );
178 }
179
180 /**
181 * Sends json response.
182 *
183 * @since 1.0.0
184 *
185 * @access private
186 *
187 * @param array $results The response array.
188 */
189 public static function _sendResponse( $results ) {
190 header( 'Content-type: application/json' );
191 nocache_headers();
192 echo json_encode( $results );
193 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
194 }
195
196 /**
197 * Deletes a chart from database.
198 *
199 * @since 1.0.0
200 * @uses wp_delete_post() To delete a chart.
201 *
202 * @access public
203 */
204 public function deleteChart() {
205 $is_post = $_SERVER['REQUEST_METHOD'] == 'POST';
206 $input_method = $is_post ? INPUT_POST : INPUT_GET;
207 $chart_id = $success = false;
208 $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
209 $capable = current_user_can( 'delete_posts' );
210 if ( $nonce && $capable ) {
211 $chart_id = filter_input(
212 $input_method,
213 'chart',
214 FILTER_VALIDATE_INT,
215 array(
216 'options' => array(
217 'min_range' => 1,
218 ),
219 )
220 );
221 if ( $chart_id ) {
222 $chart = get_post( $chart_id );
223 $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
224 }
225 }
226 if ( $success ) {
227 wp_delete_post( $chart_id, true );
228 }
229 if ( $is_post ) {
230 self::_sendResponse(
231 array(
232 'success' => $success,
233 )
234 );
235 }
236 wp_redirect( wp_get_referer() );
237 exit;
238 }
239
240 /**
241 * Delete charts that are still in auto-draft mode.
242 */
243 private function deleteOldCharts() {
244 $query = new WP_Query(
245 array(
246 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
247 'post_status' => 'auto-draft',
248 'fields' => 'ids',
249 'update_post_meta_cache' => false,
250 'update_post_term_cache' => false,
251 'posts_per_page' => 50,
252 'date_query' => array(
253 array(
254 'before' => 'today',
255 ),
256 ),
257 )
258 );
259
260 if ( $query->have_posts() ) {
261 $ids = array();
262 while ( $query->have_posts() ) {
263 wp_delete_post( $query->next_post(), true );
264 }
265 }
266 }
267
268 /**
269 * Renders appropriate page for chart builder. Creates new auto draft chart
270 * if no chart has been specified.
271 *
272 * @since 1.0.0
273 *
274 * @access public
275 */
276 public function renderChartPages() {
277 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
278 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
279 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
280 if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
281 $this->deleteOldCharts();
282 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
283 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
284 $source->fetch();
285 $chart_id = wp_insert_post(
286 array(
287 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
288 'post_title' => 'Visualization',
289 'post_author' => get_current_user_id(),
290 'post_status' => 'auto-draft',
291 'post_content' => $source->getData(),
292 )
293 );
294 if ( $chart_id && ! is_wp_error( $chart_id ) ) {
295 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
296 add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
297 add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
298 add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
299 add_post_meta(
300 $chart_id,
301 Visualizer_Plugin::CF_SETTINGS,
302 array(
303 'focusTarget' => 'datum',
304 )
305 );
306 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
307 }
308 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
309 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
310 }
311
312 $this->load_chart_type( $chart_id );
313
314 // enqueue and register scripts and styles
315 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
316 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
317
318 wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
319 wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION, true );
320 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
321 wp_register_script(
322 'visualizer-render',
323 VISUALIZER_ABSURL . 'js/render-facade.js',
324 apply_filters( 'visualizer_assets_render', array( 'visualizer-frame', 'visualizer-customization' ), false ),
325 Visualizer_Plugin::VERSION,
326 true
327 );
328 wp_register_script(
329 'visualizer-preview',
330 VISUALIZER_ABSURL . 'js/preview.js',
331 array(
332 'wp-color-picker',
333 'visualizer-render',
334 ),
335 Visualizer_Plugin::VERSION,
336 true
337 );
338 // added by Ash/Upwork
339 if ( VISUALIZER_PRO ) {
340 global $Visualizer_Pro;
341 $Visualizer_Pro->_addScriptsAndStyles();
342 }
343 // dispatch pages
344 $this->_chart = get_post( $chart_id );
345 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
346
347 // skip chart type pages only for existing charts.
348 if ( VISUALIZER_SKIP_CHART_TYPE_PAGE && 'auto-draft' !== $this->_chart->post_status && ( ! empty( $_GET['tab'] ) && 'visualizer' === $_GET['tab'] ) ) {
349 $tab = 'settings';
350 }
351
352 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
353 // if the cancel button is clicked.
354 $this->undoRevisions( $chart_id, true );
355 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
356 // if the save button is clicked.
357 $this->undoRevisions( $chart_id, false );
358 } else {
359 // if the edit button is clicked.
360 $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
361 }
362
363 switch ( $tab ) {
364 case 'settings':
365 $this->_handleDataAndSettingsPage();
366 break;
367 case 'type': // fall through.
368 case 'visualizer': // fall through.
369 $this->_handleTypesPage();
370 break;
371 default:
372 do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
373 break;
374 }
375 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
376 }
377
378 /**
379 * Load code editor assets.
380 */
381 private function loadCodeEditorAssets() {
382 global $wp_version;
383
384 if ( ! VISUALIZER_PRO ) {
385 return;
386 }
387
388 $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping();
389
390 // data tables assets.
391 wp_register_script( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
392 wp_register_style( 'visualizer-datatables', '//cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css', array(), Visualizer_Plugin::VERSION );
393 wp_register_style( 'visualizer-datatables-ui', '//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css', array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
394
395 wp_enqueue_script( 'visualizer-datatables' );
396 wp_enqueue_style( 'visualizer-datatables-ui' );
397
398 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
399 // code mirror assets.
400 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
401 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
402 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
403 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
404 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
405 wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
406 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 );
407 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
408 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
409
410 wp_enqueue_script( 'visualizer-codemirror-hint' );
411 wp_enqueue_style( 'visualizer-codemirror-hint' );
412 } else {
413 wp_enqueue_code_editor(
414 array(
415 'type' => 'sql',
416 'codemirror' => array(
417 'autofocus' => true,
418 'lineWrapping' => true,
419 'dragDrop' => false,
420 'matchBrackets' => true,
421 'autoCloseBrackets' => true,
422 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
423 'hintOptions' => array( 'tables' => $table_col_mapping ),
424 ),
425 )
426 );
427 }
428
429 return $table_col_mapping;
430 }
431
432 /**
433 * Handle data and settings page
434 */
435 private function _handleDataAndSettingsPage() {
436 if ( isset( $_POST['map_api_key'] ) ) {
437 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
438 }
439 if ( $_SERVER['REQUEST_METHOD'] == 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
440 if ( $this->_chart->post_status == 'auto-draft' ) {
441 $this->_chart->post_status = 'publish';
442
443 // ensure that a revision is not created. If a revision is created it will have the proper data and the parent of the revision will have default data.
444 // we do not want any difference in data so disable revisions temporarily.
445 add_filter( 'wp_revisions_to_keep', '__return_false' );
446 wp_update_post( $this->_chart->to_array() );
447 }
448 // save meta data only when it is NOT being canceled.
449 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
450 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
451 }
452 $render = new Visualizer_Render_Page_Send();
453 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
454 wp_iframe( array( $render, 'render' ) );
455
456 return;
457 }
458 $data = $this->_getChartArray();
459 $sidebar = '';
460 $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
461 if ( class_exists( $sidebar_class, true ) ) {
462 $sidebar = new $sidebar_class( $data['settings'] );
463 $sidebar->__series = $data['series'];
464 $sidebar->__data = $data['data'];
465 } else {
466 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
467 if ( $sidebar != '' ) {
468 $sidebar->__series = $data['series'];
469 $sidebar->__data = $data['data'];
470 }
471 }
472 unset( $data['settings']['width'], $data['settings']['height'] );
473 wp_enqueue_style( 'wp-color-picker' );
474 wp_enqueue_style( 'visualizer-frame' );
475 wp_enqueue_script( 'visualizer-preview' );
476 wp_enqueue_script( 'visualizer-chosen' );
477 wp_enqueue_script( 'visualizer-render' );
478
479 $table_col_mapping = $this->loadCodeEditorAssets();
480
481 wp_localize_script(
482 'visualizer-render',
483 'visualizer',
484 array(
485 'l10n' => array(
486 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
487 'loading' => esc_html__( 'Loading...', 'visualizer' ),
488 ),
489 'charts' => array(
490 'canvas' => $data,
491 'id' => $this->_chart->ID,
492 ),
493 'language' => $this->get_language(),
494 'map_api_key' => get_option( 'visualizer-map-api-key' ),
495 'ajax' => array(
496 'url' => admin_url( 'admin-ajax.php' ),
497 'nonces' => array(
498 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
499 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
500 ),
501 'actions' => array(
502 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
503 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
504 ),
505 ),
506 'db_query' => array(
507 'tables' => $table_col_mapping,
508 ),
509 'is_pro' => VISUALIZER_PRO,
510 'page_type' => 'chart',
511 )
512 );
513
514 $render = new Visualizer_Render_Page_Data();
515 $render->chart = $this->_chart;
516 $render->type = $data['type'];
517 $render->custom_css = $data['css'];
518 $render->sidebar = $sidebar;
519 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
520 $render->button = filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART
521 ? esc_html__( 'Save Chart', 'visualizer' )
522 : esc_html__( 'Create Chart', 'visualizer' );
523 if ( filter_input( INPUT_GET, 'action' ) == Visualizer_Plugin::ACTION_EDIT_CHART ) {
524 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
525 }
526 } else {
527 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
528 }
529 if ( VISUALIZER_PRO ) {
530 global $Visualizer_Pro;
531 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
532 }
533 $this->_addAction( 'admin_head', 'renderFlattrScript' );
534 wp_iframe( array( $render, 'render' ) );
535 }
536
537 /**
538 * Handles chart type selection page.
539 *
540 * @since 1.0.0
541 *
542 * @access private
543 */
544 private function _handleTypesPage() {
545 // process post request
546 if ( $_SERVER['REQUEST_METHOD'] == 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
547 $type = filter_input( INPUT_POST, 'type' );
548 if ( in_array( $type, Visualizer_Plugin::getChartTypes() ) ) {
549 // save new chart type
550 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
551 // if the chart has default data, update it with appropriate default data for new type
552 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
553 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
554 $source->fetch();
555 $this->_chart->post_content = $source->getData();
556 wp_update_post( $this->_chart->to_array() );
557 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
558 }
559 // redirect to next tab
560 // changed by Ash/Upwork
561 wp_redirect( add_query_arg( 'tab', 'settings' ) );
562
563 return;
564 }
565 }
566 $render = new Visualizer_Render_Page_Types();
567 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
568 $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
569 $render->chart = $this->_chart;
570 wp_enqueue_style( 'visualizer-frame' );
571 wp_enqueue_script( 'visualizer-frame' );
572 wp_iframe( array( $render, 'render' ) );
573 }
574
575 /**
576 * Renders flattr script in the iframe <head>
577 *
578 * @since 1.4.2
579 * @action admin_head
580 *
581 * @access public
582 */
583 public function renderFlattrScript() {
584 echo '';
585 }
586 // changed by Ash/Upwork
587 /**
588 * Parses uploaded CSV file and saves new data for the chart.
589 *
590 * @since 1.0.0
591 *
592 * @access public
593 */
594 public function uploadData() {
595 // if this is being called internally from pro and VISUALIZER_DO_NOT_DIE is set.
596 // otherwise, assume this is a normal web request.
597 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
598
599 // validate nonce
600 if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
601 if ( ! $can_die ) {
602 return;
603 }
604 status_header( 403 );
605 exit;
606 }
607
608 // check chart, if chart exists
609 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
610 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
611 if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type != Visualizer_Plugin::CPT_VISUALIZER ) {
612 if ( ! $can_die ) {
613 return;
614 }
615 status_header( 400 );
616 exit;
617 }
618
619 if ( ! isset( $_POST['vz-import-time'] ) ) {
620 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
621 }
622
623 if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
624 // delete the filters in case this chart is being uploaded from other data sources
625 delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
626 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
627 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
628
629 // delete "import from db" specific parameters.
630 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
631 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
632 }
633
634 $source = null;
635 $render = new Visualizer_Render_Page_Update();
636 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
637 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
638 if ( isset( $_POST['vz-import-time'] ) ) {
639 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
640 }
641 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
642 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
643 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
644 $source = apply_filters( 'visualizer_pro_handle_chart_data', $_POST['chart_data'], '', $chart_id, $_POST );
645 } else {
646 $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
647 }
648 if ( $source ) {
649 if ( $source->fetch() ) {
650 $content = $source->getData();
651 $populate = true;
652 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
653 $json = unserialize( $content );
654 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
655 // if we populate the data even if it is empty, the chart will show "Table has no columns".
656 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
657 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__ );
658 $populate = false;
659 }
660 }
661 if ( $populate ) {
662 $chart->post_content = $content;
663 }
664 wp_update_post( $chart->to_array() );
665 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
666 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
667 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
668 $render->id = $chart->ID;
669 $render->data = json_encode( $source->getRawData() );
670 $render->series = json_encode( $source->getSeries() );
671 } else {
672 $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
673 }
674 }
675 $render->render();
676 if ( ! $can_die ) {
677 return;
678 }
679 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
680 }
681
682 /**
683 * Clones the chart.
684 *
685 * @since 1.0.0
686 *
687 * @access public
688 */
689 public function cloneChart() {
690 $chart_id = $success = false;
691 $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
692 $capable = current_user_can( 'edit_posts' );
693 if ( $nonce && $capable ) {
694 $chart_id = filter_input(
695 INPUT_GET,
696 'chart',
697 FILTER_VALIDATE_INT,
698 array(
699 'options' => array(
700 'min_range' => 1,
701 ),
702 )
703 );
704 if ( $chart_id ) {
705 $chart = get_post( $chart_id );
706 $success = $chart && $chart->post_type == Visualizer_Plugin::CPT_VISUALIZER;
707 }
708 }
709 $redirect = wp_get_referer();
710 if ( $success ) {
711 $new_chart_id = wp_insert_post(
712 array(
713 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
714 'post_title' => 'Visualization',
715 'post_author' => get_current_user_id(),
716 'post_status' => $chart->post_status,
717 'post_content' => $chart->post_content,
718 )
719 );
720 if ( $new_chart_id && ! is_wp_error( $new_chart_id ) ) {
721 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_CHART_TYPE, get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true ) );
722 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, get_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, true ) );
723 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SOURCE, get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true ) );
724 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SERIES, get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true ) );
725 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SETTINGS, get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) );
726 $redirect = add_query_arg(
727 array(
728 'page' => 'visualizer',
729 'type' => filter_input( INPUT_GET, 'type' ),
730 ),
731 admin_url( 'upload.php' )
732 );
733 }
734 }
735 wp_redirect( $redirect );
736 exit;
737 }
738
739 /**
740 * Exports the chart data
741 *
742 * @since 1.0.0
743 *
744 * @access public
745 */
746 public function exportData() {
747 check_ajax_referer( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION, 'security' );
748 $capable = current_user_can( 'edit_posts' );
749 if ( $capable ) {
750 $chart_id = isset( $_GET['chart'] ) ? filter_var(
751 $_GET['chart'],
752 FILTER_VALIDATE_INT,
753 array(
754 'options' => array(
755 'min_range' => 1,
756 ),
757 )
758 ) : '';
759 if ( $chart_id ) {
760 $data = $this->_getDataAs( $chart_id, 'csv' );
761 if ( $data ) {
762 echo wp_send_json_success( $data );
763 }
764 }
765 }
766
767 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
768 }
769
770 /**
771 * Handles chart data page.
772 *
773 * @since 1.0.0
774 *
775 * @access private
776 */
777 private function _handleDataPage() {
778 $data = $this->_getChartArray();
779 $render = new Visualizer_Render_Page_Data();
780 $render->chart = $this->_chart;
781 $render->type = $data['type'];
782 unset( $data['settings']['width'], $data['settings']['height'] );
783 wp_enqueue_style( 'visualizer-frame' );
784 wp_enqueue_script( 'visualizer-render' );
785 wp_localize_script(
786 'visualizer-render',
787 'visualizer',
788 array(
789 'l10n' => array(
790 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
791 'loading' => esc_html__( 'Loading...', 'visualizer' ),
792 ),
793 'charts' => array(
794 'canvas' => $data,
795 ),
796 )
797 );
798 // Added by Ash/Upwork
799 if ( VISUALIZER_PRO ) {
800 global $Visualizer_Pro;
801 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
802 }
803 // Added by Ash/Upwork
804 $this->_addAction( 'admin_head', 'renderFlattrScript' );
805 wp_iframe( array( $render, 'render' ) );
806 }
807
808 /**
809 * Returns the data for the query.
810 *
811 * @access public
812 */
813 public function getQueryData() {
814 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
815
816 $params = wp_parse_args( $_POST['params'] );
817 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
818 $html = $source->fetch( true );
819 $error = '';
820 if ( empty( $html ) ) {
821 $error = $source->get_error();
822 wp_send_json_error( array( 'msg' => $error ) );
823 }
824 wp_send_json_success( array( 'table' => $html ) );
825 }
826
827 /**
828 * Saves the query and the schedule.
829 *
830 * @access public
831 */
832 public function saveQuery() {
833 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
834
835 $chart_id = filter_input(
836 INPUT_GET,
837 'chart',
838 FILTER_VALIDATE_INT,
839 array(
840 'options' => array(
841 'min_range' => 1,
842 ),
843 )
844 );
845
846 $render = new Visualizer_Render_Page_Update();
847 if ( $chart_id ) {
848 $params = wp_parse_args( $_POST['params'] );
849 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
850 $source->fetch( false );
851 $error = $source->get_error();
852 if ( empty( $error ) ) {
853 $hours = $_POST['refresh'];
854 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
855 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
856 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
857 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
858 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
859
860 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
861 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
862 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
863
864 wp_update_post(
865 array(
866 'ID' => $chart_id,
867 'post_content' => $source->getData(),
868 )
869 );
870 $render->data = json_encode( $source->getRawData() );
871 $render->series = json_encode( $source->getSeries() );
872 } else {
873 $render->message = $error;
874 }
875 }
876 $render->render();
877 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
878 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
879 }
880 }
881
882
883 /**
884 * Saves the filter query and the schedule.
885 *
886 * @access public
887 */
888 public function saveFilter() {
889 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
890
891 $chart_id = filter_input(
892 INPUT_GET,
893 'chart',
894 FILTER_VALIDATE_INT,
895 array(
896 'options' => array(
897 'min_range' => 1,
898 ),
899 )
900 );
901
902 $hours = $_POST['refresh'];
903
904 do_action( 'visualizer_save_filter', $chart_id, $hours );
905
906 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
907 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
908 }
909 }
910 }
911