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

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