PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.1.2
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.1.2
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.2, at classes/Visualizer/Module/Chart.php

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