PluginProbe
Visualizer – Tables & Charts Manager with Built-in AI Generator / 3.6.0
Visualizer – Tables & Charts Manager with Built-in AI Generator v3.6.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.php

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

784 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 // +----------------------------------------------------------------------+
4 // | Copyright 2013 Madpixels (email : visualizer@madpixels.net) |
5 // +----------------------------------------------------------------------+
6 // | This program is free software; you can redistribute it and/or modify |
7 // | it under the terms of the GNU General Public License, version 2, as |
8 // | published by the Free Software Foundation. |
9 // | |
10 // | This program is distributed in the hope that it will be useful, |
11 // | but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 // | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 // | GNU General Public License for more details. |
14 // | |
15 // | You should have received a copy of the GNU General Public License |
16 // | along with this program; if not, write to the Free Software |
17 // | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, |
18 // | MA 02110-1301 USA |
19 // +----------------------------------------------------------------------+
20 // | Author: Eugene Manuilov <eugene@manuilov.org> |
21 // +----------------------------------------------------------------------+
22 /**
23 * Base class for all modules. Implements routine methods required by all modules.
24 *
25 * @category Visualizer
26 * @package Module
27 *
28 * @since 1.0.0
29 */
30 class Visualizer_Module {
31
32 /**
33 * The instance of wpdb class.
34 *
35 * @since 1.0.0
36 *
37 * @access protected
38 * @var wpdb
39 */
40 protected $_wpdb = null;
41
42 /**
43 * The plugin instance.
44 *
45 * @since 1.0.0
46 *
47 * @access protected
48 * @var Visualizer_Plugin
49 */
50 protected $_plugin = null;
51
52 /**
53 * Constructor.
54 *
55 * @since 1.0.0
56 * @global wpdb $wpdb Current database connection.
57 *
58 * @access public
59 * @param Visualizer_Plugin $plugin The instance of the plugin.
60 */
61 public function __construct( Visualizer_Plugin $plugin ) {
62 global $wpdb;
63
64 $this->_wpdb = $wpdb;
65 $this->_plugin = $plugin;
66
67 $this->_addFilter( Visualizer_Plugin::FILTER_UNDO_REVISIONS, 'undoRevisions', 10, 2 );
68 $this->_addFilter( Visualizer_Plugin::FILTER_HANDLE_REVISIONS, 'handleExistingRevisions', 10, 2 );
69 $this->_addFilter( Visualizer_Plugin::FILTER_GET_CHART_DATA_AS, 'getDataAs', 10, 3 );
70 register_shutdown_function( array($this, 'onShutdown') );
71
72 }
73
74 /**
75 * Register a shutdown hook to catch fatal errors.
76 *
77 * @since ?
78 *
79 * @access public
80 */
81 public function onShutdown() {
82 $error = error_get_last();
83 if ( $error && $error['type'] === E_ERROR && false !== strpos( $error['file'], 'Visualizer/' ) ) {
84 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Critical error %s', print_r( $error, true ) ), 'error', __FILE__, __LINE__ );
85 }
86 }
87
88 /**
89 * Registers an action hook.
90 *
91 * @since 1.0.0
92 * @uses add_action() To register action hook.
93 *
94 * @access protected
95 * @param string $tag The name of the action to which the $method is hooked.
96 * @param string $method The name of the method to be called.
97 * @param bool $methodClass The root of the method.
98 * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
99 * @param int $accepted_args optional. The number of arguments the function accept (default 1).
100 * @return Visualizer_Module
101 */
102 protected function _addAction( $tag, $method, $methodClass = null, $priority = 10, $accepted_args = 1 ) {
103 add_action( $tag, array( $methodClass ? $methodClass : $this, $method ), $priority, $accepted_args );
104 return $this;
105 }
106
107 /**
108 * Registers AJAX action hook.
109 *
110 * @since 1.0.0
111 *
112 * @access public
113 * @param string $tag The name of the AJAX action to which the $method is hooked.
114 * @param string $method Optional. The name of the method to be called. If the name of the method is not provided, tag name will be used as method name.
115 * @param bool $methodClass The root of the method.
116 * @param boolean $private Optional. Determines if we should register hook for logged in users.
117 * @param boolean $public Optional. Determines if we should register hook for not logged in users.
118 * @return Visualizer_Module
119 */
120 protected function _addAjaxAction( $tag, $method = '', $methodClass = null, $private = true, $public = false ) {
121 if ( $private ) {
122 $this->_addAction( 'wp_ajax_' . $tag, $method, $methodClass );
123 }
124
125 if ( $public ) {
126 $this->_addAction( 'wp_ajax_nopriv_' . $tag, $method, $methodClass );
127 }
128
129 return $this;
130 }
131
132 /**
133 * Registers a filter hook.
134 *
135 * @since 1.0.0
136 * @uses add_filter() To register filter hook.
137 *
138 * @access protected
139 * @param string $tag The name of the filter to hook the $method to.
140 * @param type $method The name of the method to be called when the filter is applied.
141 * @param int $priority optional. Used to specify the order in which the functions associated with a particular action are executed (default: 10). Lower numbers correspond with earlier execution, and functions with the same priority are executed in the order in which they were added to the action.
142 * @param int $accepted_args optional. The number of arguments the function accept (default 1).
143 * @return Visualizer_Module
144 */
145 protected function _addFilter( $tag, $method, $priority = 10, $accepted_args = 1 ) {
146 add_filter( $tag, array( $this, $method ), $priority, $accepted_args );
147 return $this;
148 }
149
150 /**
151 * Registers a hook for shortcode tag.
152 *
153 * @since 1.0.0
154 * @uses add_shortcode() To register shortcode hook.
155 *
156 * @access protected
157 * @param string $tag Shortcode tag to be searched in post content.
158 * @param string $method Hook to run when shortcode is found.
159 * @return Visualizer_Module
160 */
161 protected function _addShortcode( $tag, $method ) {
162 add_shortcode( $tag, array( $this, $method ) );
163 return $this;
164 }
165
166 /**
167 * A wrapper around the actual function _getDataAs. This function is invoked as a filter.
168 *
169 * @since 3.2.0
170 */
171 public function getDataAs( $final, $chart_id, $type ) {
172 return $this->_getDataAs( $chart_id, $type );
173 }
174
175 /**
176 * Extracts the data for a chart and prepares it for the given type.
177 *
178 * @access public
179 * @param int $chart_id The chart id.
180 * @param string $type The exported type.
181 */
182 public function _getDataAs( $chart_id, $type ) {
183 $final = null;
184 $success = false;
185 if ( $chart_id ) {
186 $chart = get_post( $chart_id );
187 $success = $chart && $chart->post_type === Visualizer_Plugin::CPT_VISUALIZER;
188 }
189 if ( $success ) {
190 $settings = get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true );
191 $rows = array();
192 $series = get_post_meta( $chart_id, Visualizer_Plugin::CF_SERIES, true );
193 $data = self::get_chart_data( $chart, $type, false );
194 if ( ! empty( $series ) ) {
195 $row = array();
196 foreach ( $series as $array ) {
197 $row[] = $array['label'];
198 }
199 $rows[] = $row;
200 $row = array();
201 foreach ( $series as $array ) {
202 $row[] = $array['type'];
203 }
204 $rows[] = $row;
205 }
206 if ( ! empty( $data ) ) {
207 foreach ( $data as $array ) {
208 // ignore strings
209 if ( ! is_array( $array ) ) {
210 continue;
211 }
212 // if this is an array of arrays...
213 if ( is_array( $array[0] ) ) {
214 foreach ( $array as $arr ) {
215 $rows[] = $arr;
216 }
217 } else {
218 // just an array
219 $rows[] = $array;
220 }
221 }
222 }
223
224 $title = 'visualizer#' . $chart_id;
225 if ( ! empty( $settings['title'] ) ) {
226 $title = $settings['title'];
227 }
228 // for ChartJS, title is an array.
229 if ( is_array( $title ) && isset( $title['text'] ) ) {
230 $title = $title['text'];
231 }
232 if ( empty( $title ) ) {
233 $title = 'visualizer#' . $chart_id;
234 }
235
236 $filename = $title;
237
238 switch ( $type ) {
239 case 'csv':
240 $final = $this->_getCSV( $rows, $filename, false );
241 break;
242 case 'csv-display':
243 $final = $this->_getCSV( $rows, $filename, true );
244 break;
245 case 'xls':
246 $final = $this->_getExcel( $rows, $filename );
247 break;
248 case 'print':
249 $final = $this->_getHTML( $rows );
250 break;
251 case 'image':
252 $final = $this->_getImage( $chart );
253 break;
254 }
255 }
256 return $final;
257 }
258
259 /**
260 * Prepares a CSV.
261 *
262 * @access private
263 * @param array $rows The array of data.
264 * @param string $filename The name of the file to use.
265 * @param bool $enclose Enclose strings that have commas in them in double quotes.
266 */
267 private function _getCSV( $rows, $filename, $enclose ) {
268 $filename .= '.csv';
269
270 $bom = chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF );
271 $fp = tmpfile();
272 if ( ! apply_filters( 'vizualizer_export_include_series_type', true ) ) {
273 unset( $rows[1] );
274 $rows = array_values( $rows );
275 }
276 // support for MS Excel
277 fprintf( $fp, $bom );
278 foreach ( $rows as $row ) {
279 fputcsv( $fp, $row );
280 }
281 rewind( $fp );
282 $csv = '';
283 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition
284 while ( ( $array = fgetcsv( $fp ) ) !== false ) {
285 if ( strlen( $csv ) > 0 ) {
286 $csv .= PHP_EOL;
287 }
288 // if enclosure is required, check every item of this line
289 // if a comma exists in the item, add enclosure.
290 if ( $enclose ) {
291 $temp_array = array();
292 foreach ( $array as $item ) {
293 if ( strpos( $item, ',' ) !== false ) {
294 $item = VISUALIZER_CSV_ENCLOSURE . $item . VISUALIZER_CSV_ENCLOSURE;
295 }
296 $temp_array[] = $item;
297 }
298 $array = $temp_array;
299 }
300 $csv .= implode( ',', $array );
301 }
302 fclose( $fp );
303
304 return array(
305 'csv' => $csv,
306 'name' => $filename,
307 'string' => str_replace( $bom, '', $csv ),
308 );
309 }
310
311 /**
312 * Prepares an Excel file.
313 *
314 * @access private
315 * @param array $rows The array of data.
316 * @param string $filename The name of the file to use.
317 */
318 private function _getExcel( $rows, $filename ) {
319 // PHPExcel did not like sheet names longer than 31 characters and we will assume the same with PhpSpreadsheet
320 $chart = substr( $filename, 0, 30 );
321 $filename .= '.xlsx';
322 if ( ! apply_filters( 'vizualizer_export_include_series_type', true ) ) {
323 unset( $rows[1] );
324 $rows = array_values( $rows );
325 $rows = array_map(
326 function( $r ) {
327 return array_map( 'strval', $r );
328 },
329 $rows
330 );
331 }
332 $vendor_file = VISUALIZER_ABSPATH . '/vendor/autoload.php';
333 if ( is_readable( $vendor_file ) ) {
334 include_once( $vendor_file );
335 }
336 $xlsData = '';
337 if ( class_exists( 'PhpOffice\PhpSpreadsheet\Spreadsheet' ) ) {
338 $doc = new PhpOffice\PhpSpreadsheet\Spreadsheet();
339 $doc->getActiveSheet()->fromArray( $rows, null, 'A1' );
340 $doc->getActiveSheet()->setTitle( sanitize_title( $chart ) );
341 $doc = apply_filters( 'visualizer_excel_doc', $doc );
342 $writer = PhpOffice\PhpSpreadsheet\IOFactory::createWriter( $doc, 'Xlsx' );
343 ob_start();
344 $writer->save( 'php://output' );
345 $xlsData = ob_get_contents();
346 ob_end_clean();
347 } else {
348 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, 'Class PhpOffice\PhpSpreadsheet\Spreadsheet does not exist!', 'error', __FILE__, __LINE__ );
349 error_log( 'Class PhpOffice\PhpSpreadsheet\Spreadsheet does not exist!' );
350 }
351 return array(
352 'csv' => 'data:application/vnd.ms-excel;base64,' . base64_encode( $xlsData ),
353 'name' => $filename,
354 'raw' => base64_encode( $xlsData ),
355 );
356 }
357
358 /**
359 * Prepares an HTML table.
360 *
361 * @access private
362 * @param array $rows The array of data.
363 */
364 private function _getHTML( $rows ) {
365 $css = '
366 table.visualizer-print {
367 border-collapse: collapse;
368 }
369 table.visualizer-print, table.visualizer-print th, table.visualizer-print td {
370 border: 1px solid #000;
371 }
372 ';
373 $html = '';
374 $html .= '
375 <html>
376 <head>
377 <style>
378 ' . apply_filters( 'visualizer_print_css', $css ) . '
379 </style>
380 </head>
381 <body>';
382
383 $table = '<table class="visualizer-print">';
384 $index = 0;
385 foreach ( $rows as $row ) {
386 // skip the data type row.
387 if ( 1 === $index ) {
388 $index++;
389 continue;
390 }
391
392 $table .= '<tr>';
393 foreach ( $row as $col ) {
394 if ( $index === 0 ) {
395 $table .= '<th>' . $col . '</th>';
396 } else {
397 $table .= '<td>' . $col . '</td>';
398 }
399 }
400 $table .= '</tr>';
401 $index++;
402 }
403 $table .= '</table>';
404
405 $html .= apply_filters( 'visualizer_print_table', $table ) . '
406 </body>
407 </html>';
408 return array(
409 'csv' => $html,
410 );
411 }
412
413 /**
414 * Disable revisions temporarily for visualizer post type.
415 */
416 protected final function disableRevisionsTemporarily() {
417 add_filter(
418 'wp_revisions_to_keep', function( $num, $post ) {
419 if ( $post->post_type === Visualizer_Plugin::CPT_VISUALIZER ) {
420 return 0;
421 }
422 return $num;
423 }, 10, 2
424 );
425 }
426
427 /**
428 * Undo revisions for the chart, and if necessary, restore the earliest version.
429 *
430 * @return bool If any revisions were found.
431 */
432 public final function undoRevisions( $chart_id, $restore = false ) {
433 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'undoRevisions for %d with%s restore', $chart_id, ( $restore ? '' : 'out' ) ), 'debug', __FILE__, __LINE__ );
434 if ( get_post_type( $chart_id ) !== Visualizer_Plugin::CPT_VISUALIZER ) {
435 return false;
436 }
437 $revisions = wp_get_post_revisions( $chart_id, array( 'order' => 'ASC' ) );
438 if ( count( $revisions ) > 1 ) {
439 $revision_ids = array_keys( $revisions );
440
441 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'found %d revisions = %s', count( $revisions ), print_r( $revision_ids, true ) ), 'debug', __FILE__, __LINE__ );
442
443 // when we restore, a new revision is likely to be created. so, let's disable revisions for the time being.
444 $this->disableRevisionsTemporarily();
445
446 if ( $restore ) {
447 // restore to the oldest one i.e. the first one.
448 wp_restore_post_revision( array_shift( $revision_ids ) );
449 }
450
451 // delete all revisions.
452 foreach ( $revision_ids as $id ) {
453 wp_delete_post_revision( $id );
454 }
455
456 return true;
457 }
458 return false;
459 }
460
461 /**
462 * If existing revisions exist for the chart, restore the earliest version and then create a new revision to initiate editing.
463 */
464 public final function handleExistingRevisions( $chart_id, $chart ) {
465
466 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'handleExistingRevisions for %d', $chart_id ), 'debug', __FILE__, __LINE__ );
467 if ( get_post_type( $chart_id ) !== Visualizer_Plugin::CPT_VISUALIZER ) {
468 return $chart_id;
469 }
470 // undo revisions.
471 $revisions_found = $this->undoRevisions( $chart_id, true );
472
473 // create revision for the edit action.
474 wp_save_post_revision( $chart_id );
475
476 if ( $revisions_found ) {
477 // fetch chart data again in case it was updated by an earlier revision.
478 $chart = get_post( $chart_id );
479 }
480 return $chart;
481 }
482
483 /**
484 * Returns the language of the locale.
485 *
486 * @access protected
487 */
488 protected function get_language() {
489 $locale = get_locale();
490 if ( empty( $locale ) ) {
491 return '';
492 }
493 $array = explode( '_', $locale );
494 if ( count( $array ) < 2 ) {
495 return '';
496 }
497 return reset( $array );
498 }
499
500 /**
501 * Gets/creates the JS where user-specific customizations can be/have been added.
502 */
503 protected function get_user_customization_js() {
504 // use this as the JS file in case we are not able to create the file in uploads.
505 $default = VISUALIZER_ABSURL . 'js/customization.js';
506
507 $uploads = wp_get_upload_dir();
508 $specific = $uploads['baseurl'] . '/visualizer/customization.js';
509
510 // for testing on user sites (before we send them the correctly customized file).
511 if ( VISUALIZER_TEST_JS_CUSTOMIZATION ) {
512 return $default;
513 }
514
515 require_once( ABSPATH . 'wp-admin/includes/file.php' );
516 WP_Filesystem();
517 global $wp_filesystem;
518
519 $multisite_arg = '/';
520 if ( is_multisite() && ! is_main_site() ) {
521 $multisite_arg = '/sites/' . get_current_blog_id() . '/';
522 }
523
524 $dir = $wp_filesystem->wp_content_dir() . 'uploads' . $multisite_arg . 'visualizer';
525 $file = $wp_filesystem->wp_content_dir() . 'uploads' . $multisite_arg . 'visualizer/customization.js';
526
527 if ( $wp_filesystem->is_readable( $file ) ) {
528 return $specific;
529 }
530
531 if ( $wp_filesystem->exists( $file ) && ! $wp_filesystem->is_readable( $file ) ) {
532 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unable to read file %s', $file ), 'error', __FILE__, __LINE__ );
533 return $default;
534 }
535
536 if ( ! $wp_filesystem->exists( $dir ) ) {
537 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found
538 if ( ( $done = $wp_filesystem->mkdir( $dir ) ) === false ) {
539 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unable to create directory %s', $dir ), 'error', __FILE__, __LINE__ );
540 return $default;
541 }
542 }
543
544 // if file does not exist, copy.
545 if ( ! $wp_filesystem->exists( $file ) ) {
546 $src = str_replace( ABSPATH, $wp_filesystem->abspath(), VISUALIZER_ABSPATH . '/js/customization.js' );
547 // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.Found
548 if ( ( $done = $wp_filesystem->copy( $src, $file ) ) === false ) {
549 do_action( 'themeisle_log_event', Visualizer_Plugin::NAME, sprintf( 'Unable to copy file %s to %s', $src, $file ), 'error', __FILE__, __LINE__ );
550 return $default;
551 }
552 }
553
554 return $specific;
555 }
556
557 /**
558 * Load the class for the given chart's chart type so that its assets can be loaded.
559 */
560 protected function load_chart_type( $chart_id ) {
561 $name = $this->load_chart_class_name( $chart_id );
562 $class = null;
563 if ( class_exists( $name ) || true === apply_filters( 'visualizer_load_chart', false, $name ) ) {
564 if ( 'Visualizer_Render_Sidebar_Type_DataTable_DataTable' === $name ) {
565 $name = 'Visualizer_Render_Sidebar_Type_DataTable_Tabular';
566 }
567 $class = new $name;
568 }
569
570 if ( is_null( $class ) && Visualizer_Module::is_pro() ) {
571 // lets see if this type exists in pro. New Lite(3.1.0+) & old Pro(1.8.0-).
572 $type = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true );
573 $class = apply_filters( 'visualizer_pro_chart_type_sidebar', null, array( 'id' => $chart_id, 'type' => $type, 'settings' => get_post_meta( $chart_id, Visualizer_Plugin::CF_SETTINGS, true ) ) );
574 }
575
576 return is_null( $class ) ? null : $class->getLibrary();
577 }
578
579 /**
580 * Returns the class name for the given chart's chart type.
581 */
582 protected function load_chart_class_name( $chart_id ) {
583 $type = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_TYPE, true );
584 $lib = get_post_meta( $chart_id, Visualizer_Plugin::CF_CHART_LIBRARY, true );
585
586 // backward compatibility.
587 if ( empty( $lib ) ) {
588 $lib = 'GoogleCharts';
589 if ( 'dataTable' === $type ) {
590 $lib = 'DataTable';
591 }
592 }
593 $name = 'Visualizer_Render_Sidebar_Type_' . $lib . '_' . ucwords( $type );
594 return $name;
595 }
596
597 /**
598 * Generates the inline CSS to apply to the chart and adds these classes to the settings.
599 *
600 * @access public
601 * @param int $id The id of the chart.
602 * @param array $settings The settings of the chart.
603 */
604 protected function get_inline_custom_css( $id, $settings ) {
605 $css = '';
606
607 $arguments = array( '', $settings );
608 if ( ! isset( $settings['customcss'] ) ) {
609 return $arguments;
610 }
611
612 $classes = array();
613 $css = '<style type="text/css" name="visualizer-custom-css" id="customcss-' . $id . '">';
614 foreach ( $settings['customcss'] as $name => $element ) {
615 $attributes = array();
616 foreach ( $element as $property => $value ) {
617 $attributes[] = $this->handle_css_property( $property, $value );
618 }
619 $class_name = $id . $name;
620 $properties = implode( ' !important; ', array_filter( $attributes ) );
621 if ( ! empty( $properties ) ) {
622 $css .= '.' . $class_name . ' {' . $properties . ' !important;}';
623 $classes[ $name ] = $class_name;
624 }
625 }
626 $css .= '</style>';
627
628 $settings['cssClassNames'] = $classes;
629
630 $arguments = array( $css, $settings );
631 apply_filters_ref_array( 'visualizer_inline_css', array( &$arguments ) );
632
633 return $arguments;
634 }
635
636 /**
637 * Handles CSS properties that might need special syntax.
638 *
639 * @access private
640 * @param string $property The name of the css property.
641 * @param string $value The value of the css property.
642 */
643 private function handle_css_property( $property, $value ) {
644 if ( empty( $property ) || empty( $value ) ) {
645 return '';
646 }
647
648 switch ( $property ) {
649 case 'transform':
650 $value = 'rotate(' . $value . 'deg)';
651 break;
652 }
653 return $property . ': ' . $value;
654 }
655
656 /**
657 * Determines if charts have been created of the particular chart type.
658 */
659 protected static function hasChartType( $type ) {
660 $args = array(
661 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
662 'fields' => 'ids',
663 'post_status' => 'publish',
664 'meta_query' => array(
665 array(
666 'key' => Visualizer_Plugin::CF_CHART_TYPE,
667 'value' => $type,
668 ),
669 ),
670 );
671
672 $q = new WP_Query( $args );
673 return $q->found_posts > 0;
674 }
675
676 /**
677 * Determines how many charts have been created.
678 */
679 protected static function numberOfCharts() {
680 $args = array(
681 'post_type' => Visualizer_Plugin::CPT_VISUALIZER,
682 'fields' => 'ids',
683 'post_status' => 'publish',
684 'posts_per_page' => 300,
685 );
686
687 $q = new WP_Query( $args );
688 return $q->found_posts;
689 }
690
691 /**
692 * Checks if the PRO version is active.
693 *
694 * @since 3.3.0
695 */
696 public static function is_pro() {
697 // versions of pro before 1.9.0 will use the constant VISUALIZER_PRO
698 // versions of pro 1.9.0 onwards will use the filter
699 return apply_filters( 'visualizer_is_pro', VISUALIZER_PRO );
700 }
701
702 /**
703 * Checks if the PRO version is older than a particular version.
704 *
705 * @since 3.3.0
706 */
707 public static function is_pro_older_than( $version ) {
708 return version_compare( VISUALIZER_PRO_VERSION, $version, '<' );
709 }
710
711 /**
712 * Should we show some specific feature on the basis of the version?
713 *
714 * @since 3.4.0
715 */
716 public static function can_show_feature( $feature ) {
717 switch ( $feature ) {
718 case 'simple-editor':
719 // if user has pro but an older version, then don't load the simple editor functionality
720 // as the select box will not behave as expected because the pro editor's functionality will supercede.
721 return ! Visualizer_Module::is_pro() || ! Visualizer_Module::is_pro_older_than( '1.9.2' );
722 }
723 return false;
724 }
725
726 /**
727 * Gets the features for the provided license type.
728 */
729 public static final function get_features_for_license( $plan ) {
730 switch ( $plan ) {
731 case 1:
732 return array( 'import-wp', 'db-query' );
733 case 2:
734 return array( 'schedule-chart', 'chart-permissions' );
735 }
736 }
737
738 /**
739 * Gets the chart content after common manipulations.
740 */
741 public static function get_chart_data( $chart, $type, $run_filter = true ) {
742 // change HTML entities
743 $data = unserialize( html_entity_decode( $chart->post_content ) );
744 $altered = array();
745 foreach ( $data as $index => $array ) {
746 if ( ! is_array( $index ) && is_array( $array ) ) {
747 foreach ( $array as &$datum ) {
748 if ( is_string( $datum ) ) {
749 $datum = stripslashes( $datum );
750 }
751 }
752 $altered[ $index ] = $array;
753 }
754 }
755 // if something goes wrong and the end result is empty, be safe and use the original data
756 if ( empty( $altered ) ) {
757 $altered = $data;
758 }
759 if ( $run_filter ) {
760 return apply_filters( Visualizer_Plugin::FILTER_GET_CHART_DATA, $altered, $chart->ID, $type );
761 }
762 return $altered;
763 }
764
765 /**
766 * Get chart image.
767 *
768 * @param object $chart Chart data.
769 * @return string
770 */
771 public function _getImage( $chart = null ) {
772 $image = '';
773 if ( $chart ) {
774 $chart_image = get_post_meta( $chart->ID, Visualizer_Plugin::CF_CHART_IMAGE, true );
775 if ( ! empty( $chart_image ) ) {
776 $image = wp_get_attachment_image( $chart_image, 'full' );
777 }
778 }
779 return array(
780 'csv' => $image,
781 );
782 }
783 }
784