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

1,195 lines 40.0 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();
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();
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( 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(
447 $chart_id,
448 Visualizer_Plugin::CF_SETTINGS,
449 array(
450 'focusTarget' => 'datum',
451 )
452 );
453 do_action( 'visualizer_pro_new_chart_defaults', $chart_id );
454 }
455 wp_redirect( add_query_arg( 'chart', (int) $chart_id ) );
456 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
457 }
458
459 $this->load_chart_type( $chart_id );
460
461 // enqueue and register scripts and styles
462 wp_register_script( 'visualizer-chosen', VISUALIZER_ABSURL . 'js/lib/chosen.jquery.min.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
463 wp_register_style( 'visualizer-chosen', VISUALIZER_ABSURL . 'css/lib/chosen.min.css', array(), Visualizer_Plugin::VERSION );
464
465 wp_register_style( 'visualizer-frame', VISUALIZER_ABSURL . 'css/frame.css', array( 'visualizer-chosen' ), Visualizer_Plugin::VERSION );
466 wp_register_script( 'visualizer-frame', VISUALIZER_ABSURL . 'js/frame.js', array( 'visualizer-chosen', 'jquery-ui-accordion' ), Visualizer_Plugin::VERSION, true );
467 wp_register_script( 'visualizer-customization', $this->get_user_customization_js(), array(), null, true );
468 wp_register_script(
469 'visualizer-render',
470 VISUALIZER_ABSURL . 'js/render-facade.js',
471 apply_filters( 'visualizer_assets_render', array( 'visualizer-frame', 'visualizer-customization' ), false ),
472 Visualizer_Plugin::VERSION,
473 true
474 );
475 wp_register_script(
476 'visualizer-preview',
477 VISUALIZER_ABSURL . 'js/preview.js',
478 array(
479 'wp-color-picker',
480 'visualizer-render',
481 ),
482 Visualizer_Plugin::VERSION,
483 true
484 );
485 wp_register_script( 'visualizer-editor-simple', VISUALIZER_ABSURL . 'js/simple-editor.js', array( 'jquery' ), Visualizer_Plugin::VERSION, true );
486
487 // added by Ash/Upwork
488 if ( VISUALIZER_PRO ) {
489 global $Visualizer_Pro;
490 $Visualizer_Pro->_addScriptsAndStyles();
491 }
492
493 // dispatch pages
494 $this->_chart = get_post( $chart_id );
495 $tab = isset( $_GET['tab'] ) && ! empty( $_GET['tab'] ) ? $_GET['tab'] : 'visualizer';
496
497 // skip chart type pages only for existing charts.
498 if ( VISUALIZER_SKIP_CHART_TYPE_PAGE && 'auto-draft' !== $this->_chart->post_status && ( ! empty( $_GET['tab'] ) && 'visualizer' === $_GET['tab'] ) ) {
499 $tab = 'settings';
500 }
501
502 if ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) {
503 // if the cancel button is clicked.
504 $this->undoRevisions( $chart_id, true );
505 } elseif ( isset( $_POST['save'] ) && 1 === intval( $_POST['save'] ) ) {
506 // if the save button is clicked.
507 $this->undoRevisions( $chart_id, false );
508 } else {
509 // if the edit button is clicked.
510 $this->_chart = $this->handleExistingRevisions( $chart_id, $this->_chart );
511 }
512
513 switch ( $tab ) {
514 case 'settings':
515 $this->_handleDataAndSettingsPage();
516 break;
517 case 'type': // fall through.
518 case 'visualizer': // fall through.
519 $this->_handleTypesPage();
520 break;
521 default:
522 do_action( 'visualizer_pro_handle_tab', $tab, $this->_chart );
523 break;
524 }
525 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
526 }
527
528 /**
529 * Load code editor assets.
530 */
531 private function loadCodeEditorAssets() {
532 global $wp_version;
533
534 $wp_scripts = wp_scripts();
535
536 // data tables assets.
537 wp_register_script( 'visualizer-datatables', '//cdn.datatables.net/v/dt/dt-1.10.18/b-1.5.6/b-colvis-1.5.6/cr-1.5.0/fc-3.2.5/fh-3.1.4/r-2.2.2/sc-2.0.0/sl-1.3.0/datatables.min.js', array( 'jquery-ui-core' ), Visualizer_Plugin::VERSION );
538 wp_register_style( 'visualizer-datatables', '//cdn.datatables.net/v/dt/dt-1.10.18/b-1.5.6/b-colvis-1.5.6/cr-1.5.0/fc-3.2.5/fh-3.1.4/r-2.2.2/sc-2.0.0/sl-1.3.0/datatables.min.css', array(), Visualizer_Plugin::VERSION );
539 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 );
540 wp_enqueue_script( 'visualizer-datatables' );
541 wp_enqueue_style( 'visualizer-jquery-ui' );
542
543 if ( ! VISUALIZER_PRO ) {
544 return;
545 }
546
547 $table_col_mapping = Visualizer_Source_Query_Params::get_all_db_tables_column_mapping();
548
549 if ( version_compare( $wp_version, '4.9.0', '<' ) ) {
550 // code mirror assets.
551 wp_register_script( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.js', array( 'jquery' ), Visualizer_Plugin::VERSION );
552 wp_register_script( 'visualizer-codemirror-placeholder', '//codemirror.net/addon/display/placeholder.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
553 wp_register_script( 'visualizer-codemirror-matchbrackets', '//codemirror.net/addon/edit/matchbrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
554 wp_register_script( 'visualizer-codemirror-closebrackets', '//codemirror.net/addon/edit/closebrackets.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
555 wp_register_script( 'visualizer-codemirror-sql', '//codemirror.net/mode/sql/sql.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
556 wp_register_script( 'visualizer-codemirror-sql-hint', '//codemirror.net/addon/hint/sql-hint.js', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
557 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 );
558 wp_register_style( 'visualizer-codemirror-core', '//codemirror.net/lib/codemirror.css', array(), Visualizer_Plugin::VERSION );
559 wp_register_style( 'visualizer-codemirror-hint', '//codemirror.net/addon/hint/show-hint.css', array( 'visualizer-codemirror-core' ), Visualizer_Plugin::VERSION );
560
561 wp_enqueue_script( 'visualizer-codemirror-hint' );
562 wp_enqueue_style( 'visualizer-codemirror-hint' );
563 } else {
564 wp_enqueue_code_editor(
565 array(
566 'type' => 'sql',
567 'codemirror' => array(
568 'autofocus' => true,
569 'lineWrapping' => true,
570 'dragDrop' => false,
571 'matchBrackets' => true,
572 'autoCloseBrackets' => true,
573 'extraKeys' => array( 'Ctrl-Space' => 'autocomplete' ),
574 'hintOptions' => array( 'tables' => $table_col_mapping ),
575 ),
576 )
577 );
578 }
579
580 return $table_col_mapping;
581 }
582
583 /**
584 * Handle data and settings page
585 */
586 private function _handleDataAndSettingsPage() {
587 if ( isset( $_POST['map_api_key'] ) ) {
588 update_option( 'visualizer-map-api-key', $_POST['map_api_key'] );
589 }
590 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_GET['nonce'] ) && wp_verify_nonce( $_GET['nonce'] ) ) {
591 if ( $this->_chart->post_status === 'auto-draft' ) {
592 $this->_chart->post_status = 'publish';
593
594 // 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.
595 // we do not want any difference in data so disable revisions temporarily.
596 add_filter( 'wp_revisions_to_keep', '__return_false' );
597 wp_update_post( $this->_chart->to_array() );
598 }
599 // save meta data only when it is NOT being canceled.
600 if ( ! ( isset( $_POST['cancel'] ) && 1 === intval( $_POST['cancel'] ) ) ) {
601 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SETTINGS, $_POST );
602 }
603 $render = new Visualizer_Render_Page_Send();
604 $render->text = sprintf( '[visualizer id="%d"]', $this->_chart->ID );
605 wp_iframe( array( $render, 'render' ) );
606
607 return;
608 }
609 $data = $this->_getChartArray();
610 $sidebar = '';
611 $sidebar_class = 'Visualizer_Render_Sidebar_Type_' . ucfirst( $data['type'] );
612 if ( class_exists( $sidebar_class, true ) ) {
613 $sidebar = new $sidebar_class( $data['settings'] );
614 $sidebar->__series = $data['series'];
615 $sidebar->__data = $data['data'];
616 } else {
617 $sidebar = apply_filters( 'visualizer_pro_chart_type_sidebar', '', $data );
618 if ( $sidebar !== '' ) {
619 $sidebar->__series = $data['series'];
620 $sidebar->__data = $data['data'];
621 }
622 }
623 unset( $data['settings']['width'], $data['settings']['height'] );
624 wp_enqueue_style( 'wp-color-picker' );
625 wp_enqueue_style( 'visualizer-frame' );
626 wp_enqueue_script( 'visualizer-preview' );
627 wp_enqueue_script( 'visualizer-chosen' );
628 wp_enqueue_script( 'visualizer-render' );
629
630 if ( ! VISUALIZER_PRO ) {
631 wp_enqueue_script( 'visualizer-editor-simple' );
632 wp_localize_script(
633 'visualizer-editor-simple',
634 'visualizer1',
635 array(
636 'ajax' => array(
637 'url' => admin_url( 'admin-ajax.php' ),
638 'nonces' => array(
639 ),
640 'actions' => array(
641 ),
642 ),
643 )
644 );
645 }
646
647 $table_col_mapping = $this->loadCodeEditorAssets();
648
649 wp_localize_script(
650 'visualizer-render',
651 'visualizer',
652 array(
653 'l10n' => array(
654 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
655 'loading' => esc_html__( 'Loading...', 'visualizer' ),
656 'json_error' => esc_html__( 'An error occured in fetching data.', 'visualizer' ),
657 ),
658 'charts' => array(
659 'canvas' => $data,
660 'id' => $this->_chart->ID,
661 ),
662 'language' => $this->get_language(),
663 'map_api_key' => get_option( 'visualizer-map-api-key' ),
664 'ajax' => array(
665 'url' => admin_url( 'admin-ajax.php' ),
666 'nonces' => array(
667 'permissions' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA ),
668 'db_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION ),
669 'json_get_roots' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_ROOTS . Visualizer_Plugin::VERSION ),
670 'json_get_data' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_GET_DATA . Visualizer_Plugin::VERSION ),
671 'json_set_schedule' => wp_create_nonce( Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE . Visualizer_Plugin::VERSION ),
672 ),
673 'actions' => array(
674 'permissions' => Visualizer_Plugin::ACTION_FETCH_PERMISSIONS_DATA,
675 'db_get_data' => Visualizer_Plugin::ACTION_FETCH_DB_DATA,
676 'json_get_roots' => Visualizer_Plugin::ACTION_JSON_GET_ROOTS,
677 'json_get_data' => Visualizer_Plugin::ACTION_JSON_GET_DATA,
678 'json_set_schedule' => Visualizer_Plugin::ACTION_JSON_SET_SCHEDULE,
679 ),
680 ),
681 'db_query' => array(
682 'tables' => $table_col_mapping,
683 ),
684 'is_pro' => VISUALIZER_PRO,
685 'page_type' => 'chart',
686 'json_tag_separator' => Visualizer_Source_Json::TAG_SEPARATOR,
687 'json_tag_separator_view' => Visualizer_Source_Json::TAG_SEPARATOR_VIEW,
688 'is_front' => false,
689 )
690 );
691
692 $render = new Visualizer_Render_Page_Data();
693 $render->chart = $this->_chart;
694 $render->type = $data['type'];
695 $render->custom_css = $data['css'];
696 $render->sidebar = $sidebar;
697 if ( filter_input( INPUT_GET, 'library', FILTER_VALIDATE_BOOLEAN ) ) {
698 $render->button = filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART
699 ? esc_html__( 'Save Chart', 'visualizer' )
700 : esc_html__( 'Create Chart', 'visualizer' );
701 if ( filter_input( INPUT_GET, 'action' ) === Visualizer_Plugin::ACTION_EDIT_CHART ) {
702 $render->cancel_button = esc_html__( 'Cancel', 'visualizer' );
703 }
704 } else {
705 $render->button = esc_attr__( 'Insert Chart', 'visualizer' );
706 }
707 if ( VISUALIZER_PRO ) {
708 global $Visualizer_Pro;
709 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
710 }
711 $this->_addAction( 'admin_head', 'renderFlattrScript' );
712 wp_iframe( array( $render, 'render' ) );
713 }
714
715 /**
716 * Handles chart type selection page.
717 *
718 * @since 1.0.0
719 *
720 * @access private
721 */
722 private function _handleTypesPage() {
723 // process post request
724 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && wp_verify_nonce( filter_input( INPUT_POST, 'nonce' ) ) ) {
725 $type = filter_input( INPUT_POST, 'type' );
726 if ( in_array( $type, Visualizer_Plugin::getChartTypes(), true ) ) {
727 // save new chart type
728 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, $type );
729 // if the chart has default data, update it with appropriate default data for new type
730 if ( filter_var( get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, true ), FILTER_VALIDATE_BOOLEAN ) ) {
731 $source = new Visualizer_Source_Csv( VISUALIZER_ABSPATH . DIRECTORY_SEPARATOR . 'samples' . DIRECTORY_SEPARATOR . $type . '.csv' );
732 $source->fetch();
733 $this->_chart->post_content = $source->getData();
734 wp_update_post( $this->_chart->to_array() );
735 update_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
736 }
737 // redirect to next tab
738 // changed by Ash/Upwork
739 wp_redirect( add_query_arg( 'tab', 'settings' ) );
740
741 return;
742 }
743 }
744 $render = new Visualizer_Render_Page_Types();
745 $render->type = get_post_meta( $this->_chart->ID, Visualizer_Plugin::CF_CHART_TYPE, true );
746 $render->types = Visualizer_Module_Admin::_getChartTypesLocalized();
747 $render->chart = $this->_chart;
748 wp_enqueue_style( 'visualizer-frame' );
749 wp_enqueue_script( 'visualizer-frame' );
750 wp_iframe( array( $render, 'render' ) );
751 }
752
753 /**
754 * Renders flattr script in the iframe <head>
755 *
756 * @since 1.4.2
757 * @action admin_head
758 *
759 * @access public
760 */
761 public function renderFlattrScript() {
762 echo '';
763 }
764
765 /**
766 * Processes the CSV that is sent in the request as a string.
767 *
768 * @since 3.2.0
769 */
770 private function handleCSVasString( $data ) {
771 $source = null;
772 if ( VISUALIZER_PRO ) {
773 $source = apply_filters( 'visualizer_pro_handle_chart_data', $data, '' );
774 } else {
775 // data coming in from the text editor.
776 $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
777 $handle = fopen( $tmpfile, 'w' );
778 $values = preg_split( '/[\n\r]+/', stripslashes( trim( $data ) ) );
779 if ( $values ) {
780 foreach ( $values as $row ) {
781 if ( empty( $row ) ) {
782 continue;
783 }
784 $columns = explode( ',', $row );
785 fputcsv( $handle, $columns );
786 }
787 }
788 $source = new Visualizer_Source_Csv( $tmpfile );
789 fclose( $handle );
790 }
791 return $source;
792 }
793
794 /**
795 * Parses the data uploaded as an HTML table.
796 *
797 * @since 3.2.0
798 *
799 * @access private
800 */
801 private function handleTabularData() {
802 $csv = array();
803 // the datatable mentions the headers twice, so lets remove the duplicates.
804 $headers = array_unique( array_filter( $_POST['header'] ) );
805 $types = $_POST['type'];
806
807 // capture all the indexes that correspond to excluded columns.
808 $exclude = array();
809 $index = 0;
810 foreach ( $types as $type ) {
811 if ( empty( $type ) ) {
812 $exclude[] = $index;
813 }
814 $index++;
815 }
816
817 // when N headers are being renamed, the number of headers increases by N
818 // because of the way datatable duplicates header information
819 // so unset the headers that have been renamed.
820 if ( count( $headers ) !== count( $types ) ) {
821 $to = count( $headers );
822 for ( $i = count( $types ); $i < $to; $i++ ) {
823 unset( $headers[ $i + 1 ] );
824 }
825 }
826
827 $columns = array();
828 for ( $i = 0; $i < count( $headers ); $i++ ) {
829 if ( ! isset( $_POST[ 'data' . $i ] ) ) {
830 continue;
831 }
832 $columns[ $i ] = $_POST[ 'data' . $i ];
833 }
834
835 $csv[] = $headers;
836 $csv[] = $types;
837 for ( $j = 0; $j < count( $columns[0] ); $j++ ) {
838 $row = array();
839 for ( $i = 0; $i < count( $headers ); $i++ ) {
840 $row[] = $columns[ $i ][ $j ];
841 }
842 $csv[] = $row;
843 }
844
845 $tmpfile = tempnam( get_temp_dir(), Visualizer_Plugin::NAME );
846 $handle = fopen( $tmpfile, 'w' );
847
848 if ( $csv ) {
849 $index = 0;
850 foreach ( $csv as $row ) {
851 // remove all the cells corresponding to the excluded headers.
852 foreach ( $exclude as $j ) {
853 unset( $row[ $j ] );
854 }
855 fputcsv( $handle, $row );
856 }
857 }
858 $source = new Visualizer_Source_Csv( $tmpfile );
859 fclose( $handle );
860 return $source;
861 }
862
863 /**
864 * Parses uploaded CSV file and saves new data for the chart.
865 *
866 * @since 1.0.0
867 *
868 * @access public
869 */
870 public function uploadData() {
871 // if this is being called internally from pro and VISUALIZER_DO_NOT_DIE is set.
872 // otherwise, assume this is a normal web request.
873 $can_die = ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE );
874
875 // validate nonce
876 if ( ! isset( $_GET['nonce'] ) || ! wp_verify_nonce( $_GET['nonce'] ) ) {
877 if ( ! $can_die ) {
878 return;
879 }
880 status_header( 403 );
881 exit;
882 }
883
884 // check chart, if chart exists
885 // do not use filter_input as it does not work for phpunit test cases, use filter_var instead
886 $chart_id = isset( $_GET['chart'] ) ? filter_var( $_GET['chart'], FILTER_VALIDATE_INT ) : '';
887 if ( ! $chart_id || ! ( $chart = get_post( $chart_id ) ) || $chart->post_type !== Visualizer_Plugin::CPT_VISUALIZER ) {
888 if ( ! $can_die ) {
889 return;
890 }
891 status_header( 400 );
892 exit;
893 }
894
895 if ( ! isset( $_POST['vz-import-time'] ) ) {
896 apply_filters( 'visualizer_pro_remove_schedule', $chart_id );
897 }
898
899 if ( ! isset( $_POST['chart_data_src'] ) || Visualizer_Plugin::CF_SOURCE_FILTER !== $_POST['chart_data_src'] ) {
900 // delete the filters in case this chart is being uploaded from other data sources
901 delete_post_meta( $chart_id, Visualizer_Plugin::CF_FILTER_CONFIG );
902 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_FILTER_CONFIG );
903 delete_post_meta( $chart_id, '__transient-' . Visualizer_Plugin::CF_DB_QUERY );
904
905 // delete "import from db" specific parameters.
906 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY );
907 delete_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE );
908 }
909
910 // delete json related data.
911 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_URL );
912 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_ROOT );
913 delete_post_meta( $chart_id, Visualizer_Plugin::CF_JSON_PAGING );
914
915 $source = null;
916 $render = new Visualizer_Render_Page_Update();
917 if ( isset( $_POST['remote_data'] ) && filter_var( $_POST['remote_data'], FILTER_VALIDATE_URL ) ) {
918 $source = new Visualizer_Source_Csv_Remote( $_POST['remote_data'] );
919 if ( isset( $_POST['vz-import-time'] ) ) {
920 apply_filters( 'visualizer_pro_chart_schedule', $chart_id, $_POST['remote_data'], $_POST['vz-import-time'] );
921 }
922 // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
923 } elseif ( isset( $_FILES['local_data'] ) && $_FILES['local_data']['error'] == 0 ) {
924 $source = new Visualizer_Source_Csv( $_FILES['local_data']['tmp_name'] );
925 } elseif ( isset( $_POST['chart_data'] ) && strlen( $_POST['chart_data'] ) > 0 ) {
926 $source = $this->handleCSVasString( $_POST['chart_data'] );
927 } elseif ( isset( $_POST['table_data'] ) && 'yes' === $_POST['table_data'] ) {
928 $source = $this->handleTabularData();
929 } else {
930 $render->message = esc_html__( 'CSV file with chart data was not uploaded. Please, try again.', 'visualizer' );
931 }
932 if ( $source ) {
933 if ( $source->fetch() ) {
934 $content = $source->getData();
935 $populate = true;
936 if ( is_string( $content ) && is_array( unserialize( $content ) ) ) {
937 $json = unserialize( $content );
938 // if source exists, so should data. if source exists but data is blank, do not populate the chart.
939 // if we populate the data even if it is empty, the chart will show "Table has no columns".
940 if ( array_key_exists( 'source', $json ) && ! empty( $json['source'] ) && ( ! array_key_exists( 'data', $json ) || empty( $json['data'] ) ) ) {
941 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__ );
942 $populate = false;
943 }
944 }
945 if ( $populate ) {
946 $chart->post_content = $content;
947 }
948 wp_update_post( $chart->to_array() );
949 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
950 update_post_meta( $chart->ID, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
951 update_post_meta( $chart->ID, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
952 $render->id = $chart->ID;
953 $render->data = json_encode( $source->getRawData() );
954 $render->series = json_encode( $source->getSeries() );
955 } else {
956 $render->message = esc_html__( 'CSV file is broken or invalid. Please, try again.', 'visualizer' );
957 }
958 }
959 $render->render();
960 if ( ! $can_die ) {
961 return;
962 }
963 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
964 }
965
966 /**
967 * Clones the chart.
968 *
969 * @since 1.0.0
970 *
971 * @access public
972 */
973 public function cloneChart() {
974 $chart_id = $success = false;
975 $nonce = wp_verify_nonce( filter_input( INPUT_GET, 'nonce' ), Visualizer_Plugin::ACTION_CLONE_CHART );
976 $capable = current_user_can( 'edit_posts' );
977 if ( $nonce && $capable ) {
978 $chart_id = filter_input(
979 INPUT_GET,
980 'chart',
981 FILTER_VALIDATE_INT,
982 array(
983 'options' => array(
984 'min_range' => 1,
985 ),
986 )
987 );
988 if ( $chart_id ) {
989 $chart = get_post( $chart_id );
990 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
991 }
992 }
993 $redirect = wp_get_referer();
994 if ( $success ) {
995 $new_chart_id = wp_insert_post(
996 array(
997 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
998 'post_title' => 'Visualization',
999 'post_author' => get_current_user_id(),
1000 'post_status' => $chart->post_status,
1001 'post_content' => $chart->post_content,
1002 )
1003 );
1004 if ( $new_chart_id && ! is_wp_error( $new_chart_id ) ) {
1005 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_CHART_TYPE, get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true ) );
1006 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, get_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, true ) );
1007 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SOURCE, get_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, true ) );
1008 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SERIES, get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true ) );
1009 add_post_meta( $new_chart_id, Visualizer_Plugin::CF_SETTINGS, get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) );
1010 $redirect = add_query_arg(
1011 array(
1012 'page' => 'visualizer',
1013 'type' => filter_input( INPUT_GET, 'type' ),
1014 ),
1015 admin_url( 'upload.php' )
1016 );
1017 }
1018 }
1019 wp_redirect( $redirect );
1020 exit;
1021 }
1022
1023 /**
1024 * Exports the chart data
1025 *
1026 * @since 1.0.0
1027 *
1028 * @access public
1029 */
1030 public function exportData() {
1031 check_ajax_referer( Visualizer_Plugin::ACTION_EXPORT_DATA . Visualizer_Plugin::VERSION, 'security' );
1032 $capable = current_user_can( 'edit_posts' );
1033 if ( $capable ) {
1034 $chart_id = isset( $_GET['chart'] ) ? filter_var(
1035 $_GET['chart'],
1036 FILTER_VALIDATE_INT,
1037 array(
1038 'options' => array(
1039 'min_range' => 1,
1040 ),
1041 )
1042 ) : '';
1043 if ( $chart_id ) {
1044 $data = $this->_getDataAs( $chart_id, 'csv' );
1045 if ( $data ) {
1046 echo wp_send_json_success( $data );
1047 }
1048 }
1049 }
1050
1051 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1052 }
1053
1054 /**
1055 * Handles chart data page.
1056 *
1057 * @since 1.0.0
1058 *
1059 * @access private
1060 */
1061 private function _handleDataPage() {
1062 $data = $this->_getChartArray();
1063 $render = new Visualizer_Render_Page_Data();
1064 $render->chart = $this->_chart;
1065 $render->type = $data['type'];
1066 unset( $data['settings']['width'], $data['settings']['height'] );
1067 wp_enqueue_style( 'visualizer-frame' );
1068 wp_enqueue_script( 'visualizer-render' );
1069 wp_localize_script(
1070 'visualizer-render',
1071 'visualizer',
1072 array(
1073 'l10n' => array(
1074 'invalid_source' => esc_html__( 'You have entered invalid URL. Please, insert proper URL.', 'visualizer' ),
1075 'loading' => esc_html__( 'Loading...', 'visualizer' ),
1076 ),
1077 'charts' => array(
1078 'canvas' => $data,
1079 ),
1080 )
1081 );
1082 // Added by Ash/Upwork
1083 if ( VISUALIZER_PRO ) {
1084 global $Visualizer_Pro;
1085 $Visualizer_Pro->_enqueueScriptsAndStyles( $data );
1086 }
1087 // Added by Ash/Upwork
1088 $this->_addAction( 'admin_head', 'renderFlattrScript' );
1089 wp_iframe( array( $render, 'render' ) );
1090 }
1091
1092 /**
1093 * Returns the data for the query.
1094 *
1095 * @access public
1096 */
1097 public function getQueryData() {
1098 check_ajax_referer( Visualizer_Plugin::ACTION_FETCH_DB_DATA . Visualizer_Plugin::VERSION, 'security' );
1099
1100 $params = wp_parse_args( $_POST['params'] );
1101 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1102 $html = $source->fetch( true );
1103 $error = '';
1104 if ( empty( $html ) ) {
1105 $error = $source->get_error();
1106 wp_send_json_error( array( 'msg' => $error ) );
1107 }
1108 wp_send_json_success( array( 'table' => $html ) );
1109 }
1110
1111 /**
1112 * Saves the query and the schedule.
1113 *
1114 * @access public
1115 */
1116 public function saveQuery() {
1117 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_DB_QUERY . Visualizer_Plugin::VERSION, 'security' );
1118
1119 $chart_id = filter_input(
1120 INPUT_GET,
1121 'chart',
1122 FILTER_VALIDATE_INT,
1123 array(
1124 'options' => array(
1125 'min_range' => 1,
1126 ),
1127 )
1128 );
1129
1130 $render = new Visualizer_Render_Page_Update();
1131 if ( $chart_id ) {
1132 $params = wp_parse_args( $_POST['params'] );
1133 $source = new Visualizer_Source_Query( stripslashes( $params['query'] ) );
1134 $source->fetch( false );
1135 $error = $source->get_error();
1136 if ( empty( $error ) ) {
1137 $hours = $_POST['refresh'];
1138 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_QUERY, stripslashes( $params['query'] ) );
1139 update_post_meta( $chart_id, Visualizer_Plugin::CF_SOURCE, $source->getSourceName() );
1140 update_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, $source->getSeries() );
1141 update_post_meta( $chart_id, Visualizer_Plugin::CF_DB_SCHEDULE, $hours );
1142 update_post_meta( $chart_id, Visualizer_Plugin::CF_DEFAULT_DATA, 0 );
1143
1144 $schedules = get_option( Visualizer_Plugin::CF_DB_SCHEDULE, array() );
1145 $schedules[ $chart_id ] = time() + $hours * HOUR_IN_SECONDS;
1146 update_option( Visualizer_Plugin::CF_DB_SCHEDULE, $schedules );
1147
1148 wp_update_post(
1149 array(
1150 'ID' => $chart_id,
1151 'post_content' => $source->getData(),
1152 )
1153 );
1154 $render->data = json_encode( $source->getRawData() );
1155 $render->series = json_encode( $source->getSeries() );
1156 } else {
1157 $render->message = $error;
1158 }
1159 }
1160 $render->render();
1161 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1162 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1163 }
1164 }
1165
1166
1167 /**
1168 * Saves the filter query and the schedule.
1169 *
1170 * @access public
1171 */
1172 public function saveFilter() {
1173 check_ajax_referer( Visualizer_Plugin::ACTION_SAVE_FILTER_QUERY . Visualizer_Plugin::VERSION, 'security' );
1174
1175 $chart_id = filter_input(
1176 INPUT_GET,
1177 'chart',
1178 FILTER_VALIDATE_INT,
1179 array(
1180 'options' => array(
1181 'min_range' => 1,
1182 ),
1183 )
1184 );
1185
1186 $hours = $_POST['refresh'];
1187
1188 do_action( 'visualizer_save_filter', $chart_id, $hours );
1189
1190 if ( ! ( defined( 'VISUALIZER_DO_NOT_DIE' ) && VISUALIZER_DO_NOT_DIE ) ) {
1191 defined( 'WP_TESTS_DOMAIN' ) ? wp_die() : exit();
1192 }
1193 }
1194 }
1195