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

1,249 lines 42.2 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 $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 }
73
74 /**
75 * Sets the schedule for how JSON-endpoint charts should be updated.
76 *
77 * @since ?
78 *
79 * @access public
80 */
81 public function setJsonSchedule() {
82 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION, 'security' );
83
84 $chart_id = filter_input(
85 INPUT_POST,
86 'chart',
87 FILTER_VALIDATE_INT,
88 array(
89 'options' => array(
90 'min_range' => 1,
91 ),
92 )
93 );
94
95 if ( ! $chart_id ) {
96 wp_send_json_error();
97 }
98
99 $time = filter_input(
100 INPUT_POST,
101 'time',
102 FILTER_VALIDATE_INT,
103 array(
104 'options' => array(
105 'min_range' => -1,
106 ),
107 )
108 );
109
110 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE );
111
112 if ( -1 < $time ) {
113 add_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_SCHEDULE, $time );
114 }
115 wp_send_json_success();
116 }
117
118 /**
119 * Get the root elements for JSON-endpoint.
120 *
121 * @since ?
122 *
123 * @access public
124 */
125 public function getJsonRoots() {
126 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION, 'security' );
127
128 $params = wp_parse_args( $_POST['params'] );
129
130 $source = new Visualizer_Source_Json( $params );
131
132 $roots = $source->fetchRoots();
133 if ( empty( $roots ) ) {
134 wp_send_json_error( array( 'msg' => $source->get_error() ) );
135 }
136
137 wp_send_json_success( array( 'url' => $params['url'], 'roots' => $roots ) );
138 }
139
140 /**
141 * Get the data for the JSON-endpoint corresponding to the chosen root.
142 *
143 * @since ?
144 *
145 * @access public
146 */
147 public function getJsonData() {
148 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION, 'security' );
149
150 $params = wp_parse_args( $_POST['params'] );
151
152 $chart_id = $params['chart'];
153
154 if ( empty( $chart_id ) ) {
155 wp_die();
156 }
157
158 $source = new Visualizer_Source_Json( $params );
159
160 $data = $source->parse();
161 if ( empty( $data ) ) {
162 wp_send_json_error( array( 'msg' => esc_html__( 'Unable to fetch data from the endpoint. Please try again.', 'visualizer' ) ) );
163 }
164
165 $data = Visualizer_Render_Layout::show( 'editor-table', $data, $chart_id, 'viz-json-table', false, false );
166 wp_send_json_success( array( 'table' => $data, 'root' => $params['root'], 'url' => $params['url'], 'paging' => $source->getPaginationElements() ) );
167 }
168
169 /**
170 * Updates the database with the correct post parameters for JSON-endpoint charts.
171 *
172 * @since ?
173 *
174 * @access public
175 */
176 public function setJsonData() {
177 check_ajax_referer( Visualizer_Plugin::ACTION_JSON_SET_DATA . Visualizer_Plugin::VERSION, 'security' );
178
179 $params = $_POST;
180 $chart_id = $_GET['chart'];
181
182 if ( empty( $chart_id ) ) {
183 wp_die();
184 }
185
186 $chart = get_post( $chart_id );
187
188 $source = new Visualizer_Source_Json( $params );
189 $source->fetch();
190
191 $content = $source->getData();
192 $chart->post_content = $content;
193 wp_update_post( $chart->to_array() );
194 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
195 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
196 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
197 update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_URL, $params['url'] );
198 update_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_ROOT, $params['root'] );
199 delete_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING );
200 if ( ! empty( $params['paging'] ) ) {
201 add_post_meta( $chart->ID, Visualizer_Plugin::CF_JSON_PAGING, $params['paging'] );
202 }
203
204 $render = new Visualizer_Render_Page_Update();
205 $render->id = $chart->ID;
206 $render->data = json_encode( $source->getRawData() );
207 $render->series = json_encode( $source->getSeries() );
208 $render->render();
209
210 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
211 }
212
213
214 /**
215 * Fetches charts from database.
216 *
217 * This method is also called from the media pop-up (classic editor: create a post and add chart from insert content).
218 *
219 * @since 1.0.0
220 *
221 * @access public
222 */
223 public function getCharts() {
224 $query_args = array(
225 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
226 'posts_per_page' => 9,
227 'paged' => filter_input(
228 INPUT_GET,
229 'page',
230 FILTER_VALIDATE_INT,
231 array(
232 'options' => array(
233 'min_range' => 1,
234 'default' => 1,
235 ),
236 )
237 ),
238 );
239 $filter = filter_input( INPUT_GET, 's', FILTER_SANITIZE_STRING );
240 if ( empty( $filter ) ) {
241 // 'filter' is from the modal from the add media button.
242 $filter = filter_input( INPUT_GET, 'filter', FILTER_SANITIZE_STRING );
243 }
244
245 if ( $filter && in_array( $filter, Visualizer_Plugin::getChartTypes(), true ) ) {
246 $query_args['meta_query'] = array(
247 array(
248 'key' => Visualizer_Plugin::CF_CHART_TYPE,
249 'value' => $filter,
250 'compare' => '=',
251 ),
252 );
253 }
254 $query = new WP_Query( $query_args );
255 $charts = array();
256 while ( $query->have_posts() ) {
257 $chart = $query->next_post();
258 $chart_data = $this->_getChartArray( $chart );
259 $chart_data['id'] = $chart->ID;
260 $chart_data['library'] = $this->load_chart_type( $chart->ID );
261 $css = '';
262 $settings = $chart_data['settings'];
263 $arguments = $this->get_inline_custom_css( 'visualizer-chart-' . $chart->ID, $settings );
264 if ( ! empty( $arguments ) ) {
265 $css = $arguments[0];
266 $settings = $arguments[1];
267 }
268 $chart_data['settings'] = $settings;
269 $chart_data['css'] = $css;
270 $charts[] = $chart_data;
271 }
272 self::_sendResponse(
273 array(
274 'success' => true,
275 'data' => $charts,
276 'total' => $query->max_num_pages,
277 )
278 );
279 }
280
281 /**
282 * Returns chart data required for rendering.
283 *
284 * @since 1.0.0
285 *
286 * @access private
287 *
288 * @param WP_Post $chart The chart object.
289 *
290 * @return array The array of chart data.
291 */
292 private function _getChartArray( WP_Post $chart = null ) {
293 if ( is_null( $chart ) ) {
294 $chart = $this->_chart;
295 }
296 $type = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
297 $series = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SERIES, get_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, true ), $chart->ID, $type );
298 $data = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, unserialize( $chart->post_content ), $chart->ID, $type );
299 $library = $this->load_chart_type( $chart->ID );
300
301 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
302 $settings = apply_filters( Visualizer_Plugin::FILTER_GET_CHART_SETTINGS, $settings, $chart->ID, $type );
303 if ( ! empty( $atts['settings'] ) ) {
304 $settings = apply_filters( $atts['settings'], $settings, $chart->ID, $type );
305 }
306
307 $css = '';
308 $arguments = $this->get_inline_custom_css( 'visualizer-' . $chart->ID, $settings );
309 if ( ! empty( $arguments ) ) {
310 $css = $arguments[0];
311 $settings = $arguments[1];
312 }
313
314 $date_formats = Visualizer_Source::get_date_formats_if_exists( $series, $data );
315
316 return array(
317 'type' => $type,
318 'series' => $series,
319 'settings' => $settings,
320 'data' => $data,
321 'library' => $library,
322 'css' => $css,
323 'date_formats' => $date_formats,
324 );
325 }
326
327 /**
328 * Sends json response.
329 *
330 * @since 1.0.0
331 *
332 * @access private
333 *
334 * @param array $results The response array.
335 */
336 public static function _sendResponse( $results ) {
337 header( 'Content-type: application/json' );
338 nocache_headers();
339 echo json_encode( $results );
340 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
341 }
342
343 /**
344 * Deletes a chart from database.
345 *
346 * @since 1.0.0
347 * @uses wp_delete_post() To delete a chart.
348 *
349 * @access public
350 */
351 public function deleteChart() {
352 $is_post = $_SERVER['REQUEST_METHOD'] === 'POST';
353 $input_method = $is_post ? INPUT_POST : INPUT_GET;
354 $chart_id = $success = false;
355 $nonce = wp_verify_nonce( filter_input( $input_method, 'nonce' ) );
356 $capable = current_user_can( 'delete_posts' );
357 if ( $nonce && $capable ) {
358 $chart_id = filter_input(
359 $input_method,
360 'chart',
361 FILTER_VALIDATE_INT,
362 array(
363 'options' => array(
364 'min_range' => 1,
365 ),
366 )
367 );
368 if ( $chart_id ) {
369 $chart = get_post( $chart_id );
370 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
371 }
372 }
373 if ( $success ) {
374 wp_delete_post( $chart_id, true );
375 }
376 if ( $is_post ) {
377 self::_sendResponse(
378 array(
379 'success' => $success,
380 )
381 );
382 }
383 wp_redirect( remove_query_arg( 'vaction', wp_get_referer() ) );
384 exit;
385 }
386
387 /**
388 * Delete charts that are still in auto-draft mode.
389 */
390 private function deleteOldCharts() {
391 $query = new WP_Query(
392 array(
393 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
394 'post_status' => 'auto-draft',
395 'fields' => 'ids',
396 'update_post_meta_cache' => false,
397 'update_post_term_cache' => false,
398 'posts_per_page' => 50,
399 'date_query' => array(
400 array(
401 'before' => 'today',
402 ),
403 ),
404 )
405 );
406
407 if ( $query->have_posts() ) {
408 $ids = array();
409 while ( $query->have_posts() ) {
410 wp_delete_post( $query->next_post(), true );
411 }
412 }
413 }
414
415 /**
416 * Renders appropriate page for chart builder. Creates new auto draft chart
417 * if no chart has been specified.
418 *
419 * @since 1.0.0
420 *
421 * @access public
422 */
423 public function renderChartPages() {
424 defined( 'IFRAME_REQUEST' ) || define( 'IFRAME_REQUEST', 1 );
425 // check chart, if chart not exists, will create new one and redirects to the same page with proper chart id
426 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
427 if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
428 $this->deleteOldCharts();
429 $default_type = isset( $_GET['type'] ) && ! empty( $_GET['type'] ) ? $_GET['type'] : 'line';
430 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $default_type . '.csv' );
431 $source->fetch();
432 $chart_id = wp_insert_post(
433 array(
434 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
435 'post_title' => 'Visualization',
436 'post_author' => get_current_user_id(),
437 'post_status' => 'auto-draft',
438 'post_content' => $source->getData(),
439 )
440 );
441 if ( $chart_id && ! is_wp_error( $chart_id ) ) {
442 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, $default_type );
443 add_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 1 );
444 add_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
445 add_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
446 add_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, '' );
447 add_post_meta(
448 $chart_id,
449 Visualizer_Plugin::CF_SETTINGS,
450 array(
451 'focusTarget' => 'datum',
452 )
453 );
454 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
455 }
456 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
457 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
458 }
459
460 $lib = $this->load_chart_type( $chart_id );
461
462 // the alpha color picker (RGBA) is not supported by google.
463 $color_picker_dep = 'wp-color-picker';
464 if ( in_array( $lib, array( 'chartjs', 'datatables' ), true ) && ! wp_script_is( 'wp-color-picker-alpha', 'registered' ) ) {
465 wp_register_script( 'wp-color-picker-alpha', VISUALIZER_ABSURL . 'js/lib/wp-color-picker-alpha.min.js', array( 'wp-color-picker' ), Visualizer_Plugin::VERSION );
466 $color_picker_dep = 'wp-color-picker-alpha';
467 }
468
469 // enqueue and register scripts and styles
470 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
471 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
472
473 wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
474 wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion' ), Visualizer_Plugin::VERSION, true );
475 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
476 wp_register_script(
477 'visualizer-render',
478 VISUALIZER_ABSURL . 'js/render-facade.js',
479 apply_filters( 'visualizer_assets_render', array( 'visualizer-frame', 'visualizer-customization' ), false ),
480 Visualizer_Plugin::VERSION,
481 true
482 );
483 wp_register_script(
484 'visualizer-preview',
485 VISUALIZER_ABSURL . 'js/preview.js',
486 array(
487 $color_picker_dep,
488 'visualizer-render',
489 ),
490 Visualizer_Plugin::VERSION,
491 true
492 );
493 wp_register_script( 'visualizer-editor-simple', VISUALIZER_ABSURL . 'js/simple-editor.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
494
495 do_action( 'visualizer_add_scripts' );
496
497 if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
498 global $Visualizer_Pro;
499 $Visualizer_Pro->_addScriptsAndStyles();
500 }
501
502 // dispatch pages
503 $this->_chart = get_post( $chart_id );
504 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
505
506 // skip chart type pages only for existing charts.
507 if ( VISUALIZER_SKIP_CHART_TYPE_PAGE && 'auto-draft' !== $this->_chart->post_status && ( ! empty( $_GET['tab'] ) && 'visualizer' === $_GET['tab'] ) ) {
508 $tab = 'settings';
509 }
510
511 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
512 // if the cancel button is clicked.
513 $this->undoRevisions( $chart_id, true );
514 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
515 // if the save button is clicked.
516 $this->undoRevisions( $chart_id, false );
517 } else {
518 // if the edit button is clicked.
519 $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
520 }
521
522 switch ( $tab ) {
523 case 'settings':
524 $this->_handleDataAndSettingsPage();
525 break;
526 case 'type': // fall through.
527 case 'visualizer': // fall through.
528 $this->_handleTypesPage();
529 break;
530 default:
531 do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
532 break;
533 }
534 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
535 }
536
537 /**
538 * Load code editor assets.
539 */
540 private function loadCodeEditorAssets() {
541 global $wp_version;
542
543 $wp_scripts = wp_scripts();
544
545 // data tables assets.
546 wp_register_script( 'visualizer-datatables', VISUALIZER_ABSURL . 'js/lib/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
547 wp_register_style( 'visualizer-datatables', VISUALIZER_ABSURL . 'css/lib/datatables.min.css', array(), Visualizer_Plugin::VERSION );
548 wp_register_style( 'visualizer-jquery-ui', sprintf( '//ajax.googleapis.com/ajax/libs/jqueryui/%s/themes/smoothness/jquery-ui.css', $wp_scripts->registered['jquery-ui-core']->ver ), array( 'visualizer-datatables' ), Visualizer_Plugin::VERSION );
549 wp_enqueue_script( 'visualizer-datatables' );
550 wp_enqueue_style( 'visualizer-jquery-ui' );
551
552 if ( ! Visualizer_Module::is_pro() ) {
553 return;
554 }
555
556 $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping();
557
558 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
559 // code mirror assets.
560 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
561 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
562 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
563 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
564 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
565 wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
566 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 );
567 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
568 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
569
570 wp_enqueue_script( 'visualizer-codemirror-hint' );
571 wp_enqueue_style( 'visualizer-codemirror-hint' );
572 } else {
573 wp_enqueue_code_editor(
574 array(
575 'type' => 'sql',
576 'codemirror' => array(
577 'autofocus' => true,
578 'lineWrapping' => true,
579 'dragDrop' => false,
580 'matchBrackets' => true,
581 'autoCloseBrackets' => true,
582 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
583 'hintOptions' => array( 'tables' => $table_col_mapping ),
584 ),
585 )
586 );
587 }
588
589 return $table_col_mapping;
590 }
591
592 /**
593 * Handle data and settings page
594 */
595 private function _handleDataAndSettingsPage() {
596 if ( isset( $_POST['map_api_key'] ) ) {
597 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
598 }
599 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
600 if ( $this->_chart->post_status === 'auto-draft' ) {
601 $this->_chart->post_status = 'publish';
602
603 // 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.
604 // we do not want any difference in data so disable revisions temporarily.
605 add_filter( 'wp_revisions_to_keep', '__return_false' );
606 wp_update_post( $this->_chart->to_array() );
607 }
608 // save meta data only when it is NOT being canceled.
609 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
610 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
611
612 // we will keep a parameter called 'internal_title' that will be set to the given title or, if empty, the chart ID
613 // this will help in searching with the chart id.
614 $settings = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
615 $title = null;
616 if ( isset( $settings['title'] ) && ! empty( $settings['title'] ) ) {
617 $title = $settings['title'];
618 if ( is_array( $title ) ) {
619 $title = $settings['title']['text'];
620 }
621 }
622 if ( empty( $title ) ) {
623 $title = $this->_chart->ID;
624 }
625 $settings['internal_title'] = $title;
626 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $settings );
627 }
628 $render = new Visualizer_Render_Page_Send();
629 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
630 wp_iframe( array( $render, 'render' ) );
631
632 return;
633 }
634 $data = $this->_getChartArray();
635 $sidebar = '';
636 $sidebar_class = $this->load_chart_class_name( $this->_chart->ID );
637 if ( class_exists( $sidebar_class, true ) ) {
638 $sidebar = new $sidebar_class( $data['settings'] );
639 $sidebar->__series = $data['series'];
640 $sidebar->__data = $data['data'];
641 } else {
642 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
643 if ( $sidebar !== '' ) {
644 $sidebar->__series = $data['series'];
645 $sidebar->__data = $data['data'];
646 }
647 }
648 unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
649 wp_enqueue_style( 'wp-color-picker' );
650 wp_enqueue_style( 'visualizer-frame' );
651 wp_enqueue_script( 'visualizer-preview' );
652 wp_enqueue_script( 'visualizer-chosen' );
653 wp_enqueue_script( 'visualizer-render' );
654
655 if ( ! Visualizer_Module::is_pro() ) {
656 wp_enqueue_script( 'visualizer-editor-simple' );
657 wp_localize_script(
658 'visualizer-editor-simple',
659 'visualizer1',
660 array(
661 'ajax' => array(
662 'url' => admin_url( 'admin-ajax.php' ),
663 'nonces' => array(
664 ),
665 'actions' => array(
666 ),
667 ),
668 )
669 );
670 }
671
672 $table_col_mapping = $this->loadCodeEditorAssets();
673
674 wp_localize_script(
675 'visualizer-render',
676 'visualizer',
677 array(
678 'l10n' => array(
679 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
680 'loading' => esc_html__( 'Loading...', 'visualizer' ),
681 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
682 ),
683 'charts' => array(
684 'canvas' => $data,
685 'id' => $this->_chart->ID,
686 ),
687 'language' => $this->get_language(),
688 'map_api_key' => get_option( 'visualizer-map-api-key' ),
689 'ajax' => array(
690 'url' => admin_url( 'admin-ajax.php' ),
691 'nonces' => array(
692 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
693 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
694 'json_get_roots' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION ),
695 'json_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION ),
696 'json_set_schedule' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION ),
697 ),
698 'actions' => array(
699 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
700 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
701 'json_get_roots' => Visualizer_Plugin::ACTION_JSON_GET_ROOTS,
702 'json_get_data' => Visualizer_Plugin::ACTION_JSON_GET_DATA,
703 'json_set_schedule' => Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE,
704 ),
705 ),
706 'db_query' => array(
707 'tables' => $table_col_mapping,
708 ),
709 'is_pro' => Visualizer_Module::is_pro(),
710 'page_type' => 'chart',
711 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
712 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
713 'is_front' => false,
714 )
715 );
716
717 $render = new Visualizer_Render_Page_Data();
718 $render->chart = $this->_chart;
719 $render->type = $data['type'];
720 $render->custom_css = $data['css'];
721 $render->sidebar = $sidebar;
722 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
723 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
724 ? esc_html__( 'Save Chart', 'visualizer' )
725 : esc_html__( 'Create Chart', 'visualizer' );
726 if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
727 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
728 }
729 } else {
730 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
731 }
732
733 do_action( 'visualizer_enqueue_scripts_and_styles', $data );
734
735 if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
736 global $Visualizer_Pro;
737 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
738 }
739
740 $this->_addAction( 'admin_head', 'renderFlattrScript' );
741 wp_iframe( array( $render, 'render' ) );
742 }
743
744 /**
745 * Handles chart type selection page.
746 *
747 * @since 1.0.0
748 *
749 * @access private
750 */
751 private function _handleTypesPage() {
752 // process post request
753 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
754 $type = filter_input( INPUT_POST, 'type' );
755 $library = filter_input( INPUT_POST, 'chart-library' );
756 if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
757 if ( empty( $library ) ) {
758 // library cannot be empty.
759 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Chart library empty while creating the chart! Aborting...', 'error', __FILE__, __LINE__ );
760 return;
761 }
762
763 // save new chart type
764 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
765 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_LIBRARY, $library );
766 // if the chart has default data, update it with appropriate default data for new type
767 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
768 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
769 $source->fetch();
770 $this->_chart->post_content = $source->getData();
771 wp_update_post( $this->_chart->to_array() );
772 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
773 }
774
775 Visualizer_Module_Utility::set_defaults( $this->_chart );
776
777 // redirect to next tab
778 // changed by Ash/Upwork
779 wp_redirect( add_query_arg( 'tab', 'settings' ) );
780
781 return;
782 }
783 }
784 $render = new Visualizer_Render_Page_Types();
785 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
786 $render->types = Visualizer_Module_Admin::_getChartTypesLocalized( false, false, false, 'types' );
787 $render->chart = $this->_chart;
788 wp_enqueue_style( 'visualizer-frame' );
789 wp_enqueue_script( 'visualizer-frame' );
790 wp_iframe( array( $render, 'render' ) );
791 }
792
793 /**
794 * Renders flattr script in the iframe <head>
795 *
796 * @since 1.4.2
797 * @action admin_head
798 *
799 * @access public
800 */
801 public function renderFlattrScript() {
802 echo '';
803 }
804
805 /**
806 * Processes the CSV that is sent in the request as a string.
807 *
808 * @since 3.2.0
809 */
810 private function handleCSVasString( $data ) {
811 $source = null;
812
813 // @issue https://github.com/Codeinwp/visualizer/issues/412
814 if ( has_filter( 'visualizer_pro_handle_chart_data' ) ) {
815 $source = apply_filters( 'visualizer_pro_handle_chart_data', $data, '' );
816 } else {
817 // data coming in from the text editor.
818 $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
819 $handle = fopen( $tmpfile, 'w' );
820 $values = preg_split( '/[\n\r]+/', stripslashes( trim( $data ) ) );
821 if ( $values ) {
822 foreach ( $values as $row ) {
823 if ( empty( $row ) ) {
824 continue;
825 }
826 $columns = explode( ',', $row );
827 fputcsv( $handle, $columns );
828 }
829 }
830 $source = new Visualizer_Source_Csv( $tmpfile );
831 fclose( $handle );
832 }
833 return $source;
834 }
835
836 /**
837 * Parses the data uploaded as an HTML table.
838 *
839 * @since 3.2.0
840 *
841 * @access private
842 */
843 private function handleTabularData() {
844 $csv = array();
845 // the datatable mentions the headers twice, so lets remove the duplicates.
846 $headers = array_unique( array_filter( $_POST['header'] ) );
847 $types = $_POST['type'];
848
849 // capture all the indexes that correspond to excluded columns.
850 $exclude = array();
851 $index = 0;
852 foreach ( $types as $type ) {
853 if ( empty( $type ) ) {
854 $exclude[] = $index;
855 }
856 $index++;
857 }
858
859 // when N headers are being renamed, the number of headers increases by N
860 // because of the way datatable duplicates header information
861 // so unset the headers that have been renamed.
862 if ( count( $headers ) !== count( $types ) ) {
863 $to = count( $headers );
864 for ( $i = count( $types ); $i < $to; $i++ ) {
865 unset( $headers[ $i + 1 ] );
866 }
867 }
868
869 $columns = array();
870 for ( $i = 0; $i < count( $headers ); $i++ ) {
871 if ( ! isset( $_POST[ 'data' . $i ] ) ) {
872 continue;
873 }
874 $columns[ $i ] = $_POST[ 'data' . $i ];
875 }
876
877 $csv[] = $headers;
878 $csv[] = $types;
879 for ( $j = 0; $j < count( $columns[0] ); $j++ ) {
880 $row = array();
881 for ( $i = 0; $i < count( $headers ); $i++ ) {
882 $row[] = $columns[ $i ][ $j ];
883 }
884 $csv[] = $row;
885 }
886
887 $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
888 $handle = fopen( $tmpfile, 'w' );
889
890 if ( $csv ) {
891 $index = 0;
892 foreach ( $csv as $row ) {
893 // remove all the cells corresponding to the excluded headers.
894 foreach ( $exclude as $j ) {
895 unset( $row[ $j ] );
896 }
897 fputcsv( $handle, $row );
898 }
899 }
900 $source = new Visualizer_Source_Csv( $tmpfile );
901 fclose( $handle );
902 return $source;
903 }
904
905 /**
906 * Parses uploaded CSV file and saves new data for the chart.
907 *
908 * @since 1.0.0
909 *
910 * @access public
911 */
912 public function uploadData() {
913 // if this is being called internally from pro and VISUALIZER_DO_NOT_DIE is set.
914 // otherwise, assume this is a normal web request.
915 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
916
917 // validate nonce
918 if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
919 if ( ! $can_die ) {
920 return;
921 }
922 status_header( 403 );
923 exit;
924 }
925
926 // check chart, if chart exists
927 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
928 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
929 if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
930 if ( ! $can_die ) {
931 return;
932 }
933 status_header( 400 );
934 exit;
935 }
936
937 if ( ! isset( $_POST['vz-import-time'] ) ) {
938 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
939 }
940
941 if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
942 // delete the filters in case this chart is being uploaded from other data sources
943 delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
944 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
945 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
946
947 // delete "import from db" specific parameters.
948 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
949 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
950 }
951
952 // delete json related data.
953 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL );
954 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT );
955 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING );
956
957 $source = null;
958 $render = new Visualizer_Render_Page_Update();
959 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
960 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
961 if ( isset( $_POST['vz-import-time'] ) ) {
962 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
963 }
964 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
965 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
966 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
967 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
968 $source = $this->handleCSVasString( $_POST['chart_data'] );
969 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
970 $source = $this->handleTabularData();
971 } else {
972 $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please try again.', 'visualizer' );
973 }
974 if ( $source ) {
975 if ( $source->fetch() ) {
976 $content = $source->getData();
977 $populate = true;
978 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
979 $json = unserialize( $content );
980 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
981 // if we populate the data even if it is empty, the chart will show "Table has no columns".
982 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
983 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__ );
984 $populate = false;
985 }
986 }
987 if ( $populate ) {
988 $chart->post_content = $content;
989 }
990 wp_update_post( $chart->to_array() );
991 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
992 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
993 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
994
995 Visualizer_Module_Utility::set_defaults( $chart, null );
996
997 $settings = get_post_meta( $chart->ID, Visualizer_Plugin::CF_SETTINGS, true );
998
999 $render->id = $chart->ID;
1000 $render->data = json_encode( $source->getRawData() );
1001 $render->series = json_encode( $source->getSeries() );
1002 $render->settings = json_encode( $settings );
1003 } else {
1004 $render->message = $source->get_error();
1005 if ( empty( $render->message ) ) {
1006 $render->message = esc_html__( 'CSV file is broken or invalid. Please try again.', 'visualizer' );
1007 }
1008 }
1009 }
1010 $render->render();
1011 if ( ! $can_die ) {
1012 return;
1013 }
1014 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1015 }
1016
1017 /**
1018 * Clones the chart.
1019 *
1020 * @since 1.0.0
1021 *
1022 * @access public
1023 */
1024 public function cloneChart() {
1025 $chart_id = $success = false;
1026 $nonce = isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'], Visualizer_Plugin::ACTION_CLONE_CHART );
1027 $capable = current_user_can( 'edit_posts' );
1028 if ( $nonce && $capable ) {
1029 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
1030 if ( $chart_id ) {
1031 $chart = get_post( $chart_id );
1032 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
1033 }
1034 }
1035 $redirect = remove_query_arg( 'vaction', wp_get_referer() );
1036 if ( $success ) {
1037 $new_chart_id = wp_insert_post(
1038 array(
1039 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
1040 'post_title' => 'Visualization',
1041 'post_author' => get_current_user_id(),
1042 'post_status' => $chart->post_status,
1043 'post_content' => $chart->post_content,
1044 )
1045 );
1046 if ( is_wp_error( $new_chart_id ) ) {
1047 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__ );
1048 } else {
1049 $post_meta = get_post_meta( $chart_id );
1050 foreach ( $post_meta as $key => $value ) {
1051 if ( strpos( $key, 'visualizer-' ) !== false ) {
1052 add_post_meta( $new_chart_id, $key, maybe_unserialize( $value[0] ) );
1053 }
1054 }
1055 $redirect = add_query_arg(
1056 array(
1057 'page' => 'visualizer',
1058 'type' => filter_input( INPUT_GET, 'type' ),
1059 'vaction' => false,
1060 ),
1061 admin_url( 'admin.php' )
1062 );
1063 }
1064 }
1065
1066 if ( defined( 'WP_TESTS_DOMAIN' ) ) {
1067 wp_die();
1068 }
1069
1070 wp_redirect( $redirect );
1071 exit;
1072 }
1073
1074 /**
1075 * Exports the chart data
1076 *
1077 * @since 1.0.0
1078 *
1079 * @access public
1080 */
1081 public function exportData() {
1082 check_ajax_referer( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION, 'security' );
1083 $capable = current_user_can( 'edit_posts' );
1084 if ( $capable ) {
1085 $chart_id = isset( $_GET['chart'] ) ? filter_var(
1086 $_GET['chart'],
1087 FILTER_VALIDATE_INT,
1088 array(
1089 'options' => array(
1090 'min_range' => 1,
1091 ),
1092 )
1093 ) : '';
1094 if ( $chart_id ) {
1095 $data = $this->_getDataAs( $chart_id, 'csv' );
1096 if ( $data ) {
1097 echo wp_send_json_success( $data );
1098 }
1099 }
1100 }
1101
1102 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1103 }
1104
1105 /**
1106 * Handles chart data page.
1107 *
1108 * @since 1.0.0
1109 *
1110 * @access private
1111 */
1112 private function _handleDataPage() {
1113 $data = $this->_getChartArray();
1114 $render = new Visualizer_Render_Page_Data();
1115 $render->chart = $this->_chart;
1116 $render->type = $data['type'];
1117 unset( $data['settings']['width'], $data['settings']['height'], $data['settings']['chartArea'] );
1118 wp_enqueue_style( 'visualizer-frame' );
1119 wp_enqueue_script( 'visualizer-render' );
1120 wp_localize_script(
1121 'visualizer-render',
1122 'visualizer',
1123 array(
1124 'l10n' => array(
1125 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1126 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1127 ),
1128 'charts' => array(
1129 'canvas' => $data,
1130 ),
1131 )
1132 );
1133
1134 do_action( 'visualizer_enqueue_scripts_and_styles', $data );
1135
1136 if ( Visualizer_Module::is_pro() && Visualizer_Module::is_pro_older_than( '1.9.0' ) ) {
1137 global $Visualizer_Pro;
1138 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1139 }
1140
1141 // Added by Ash/Upwork
1142 $this->_addAction( 'admin_head', 'renderFlattrScript' );
1143 wp_iframe( array( $render, 'render' ) );
1144 }
1145
1146 /**
1147 * Returns the data for the query.
1148 *
1149 * @access public
1150 */
1151 public function getQueryData() {
1152 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1153
1154 $params = wp_parse_args( $_POST['params'] );
1155 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1156 $html = $source->fetch( true );
1157 $error = '';
1158 if ( empty( $html ) ) {
1159 $error = $source->get_error();
1160 wp_send_json_error( array( 'msg' => $error ) );
1161 }
1162 wp_send_json_success( array( 'table' => $html ) );
1163 }
1164
1165 /**
1166 * Saves the query and the schedule.
1167 *
1168 * @access public
1169 */
1170 public function saveQuery() {
1171 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1172
1173 $chart_id = filter_input(
1174 INPUT_GET,
1175 'chart',
1176 FILTER_VALIDATE_INT,
1177 array(
1178 'options' => array(
1179 'min_range' => 1,
1180 ),
1181 )
1182 );
1183
1184 $render = new Visualizer_Render_Page_Update();
1185 if ( $chart_id ) {
1186 $params = wp_parse_args( $_POST['params'] );
1187 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1188 $source->fetch( false );
1189 $error = $source->get_error();
1190 if ( empty( $error ) ) {
1191 $hours = $_POST['refresh'];
1192 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
1193 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1194 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1195 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1196 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1197
1198 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
1199 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
1200 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
1201
1202 wp_update_post(
1203 array(
1204 'ID' => $chart_id,
1205 'post_content' => $source->getData(),
1206 )
1207 );
1208 $render->data = json_encode( $source->getRawData() );
1209 $render->series = json_encode( $source->getSeries() );
1210 } else {
1211 $render->message = $error;
1212 }
1213 }
1214 $render->render();
1215 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1216 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1217 }
1218 }
1219
1220
1221 /**
1222 * Saves the filter query and the schedule.
1223 *
1224 * @access public
1225 */
1226 public function saveFilter() {
1227 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1228
1229 $chart_id = filter_input(
1230 INPUT_GET,
1231 'chart',
1232 FILTER_VALIDATE_INT,
1233 array(
1234 'options' => array(
1235 'min_range' => 1,
1236 ),
1237 )
1238 );
1239
1240 $hours = $_POST['refresh'];
1241
1242 do_action( 'visualizer_save_filter', $chart_id, $hours );
1243
1244 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1245 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1246 }
1247 }
1248 }
1249