PluginProbe
SQL Chart Builder / 3.0.2
SQL Chart Builder v3.0.2
3.0.2 3.0.1 trunk 1.0.2 1.0.3 2.2.2 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.7.1 2.3.7.2 2.3.8 3.0.0
sql-chart-builder / functions.php

functions.php in SQL Chart Builder 3.0.2, at functions.php

1,275 lines 52.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 die;
4 }
5 //postinstall function
6 function guaven_sqlcharts_load_defaults()
7 {
8 if (get_option("guaven_sqlcharts_already_installed_2") === false) {
9 update_option("guaven_sqlcharts_already_installed_2", "1");
10 guaven_sqlcharts_install_first_data();
11
12 }
13 }
14
15 function guaven_sqlcharts_install_first_data()
16 {
17 require_once(dirname(__FILE__) . "/initial_data.php");
18 gvn_chart_sample_nonxml_data();
19 }
20
21
22 function guaven_sqlcharts_recommended(){
23 if(!class_exists('WooCommerce'))return;
24 $uid=(int)get_current_user_id();
25 if(isset($_GET["gvnsql_dismiss_recommendation"])){
26 update_option('gvnsql_dismiss_recommendation_'.$uid,1);
27 return;
28 }
29 if(get_option('gvnsql_dismiss_recommendation_'.$uid)!='')return;
30 return '<table class="gf-alert gf-alert-info" style="margin-top:20px">
31 <tbody><tr><td style="width: auto;vertical-align: top;padding: 20px;">
32 <h2>WooCommerce Search Engine – INSTANT, RELEVANT AND SMART Search Box</h2>
33 <h3>Turn your website search into Smart Search which find products by price, SKU, attributes, meta data, categorys, tags etc. </h3>
34 <p>“WooCommerce Search Engine” is a very powerful and easy to use WooCommerce Search Plugin which turns a simple search box of your WooCommerce Store to the powerful multifunctional magic box which helps you to sell more products. The plugin UI is compatible with ALL THEMES.</p>
35 <a target="_blank" style="border:0px solid #6200ee;border-radius:0px;color:white;font-weight:bold;background: #6200ee;" class="button button-secondary"
36 href="https://codecanyon.net/item/woocommerce-search-box/15685698">Get the Search Box </a>
37 </td><td style="position:relative">
38 <a href="'.admin_url().'/edit.php?post_type=gvn_schart&gvnsql_dismiss_recommendation=1'.'" style="position: absolute;right: 0;top: -15px;right: -10px;">{svg}
39 </a>
40 <img src="'.plugin_dir_url( __FILE__ ) . 'asset/img/recommended1.jpg" style="max-width: 430px;"></td></tr>
41 </tbody></table>';
42 }
43
44
45
46 function guaven_sqlcharts_my_admin_notice()
47 {
48 global $post;
49
50
51 if(
52 (!empty($_SERVER["REQUEST_URI"]) and strpos(sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])),'post_type=gvn_schart')!==false)
53 or
54 (!empty($post) and $post->post_type == 'gvn_schart')
55 ){
56 echo str_replace('{svg}','<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="11" height="14" viewBox="0 0 11 14">
57 <path d="M10.141 10.328q0 0.312-0.219 0.531l-1.062 1.062q-0.219 0.219-0.531 0.219t-0.531-0.219l-2.297-2.297-2.297 2.297q-0.219 0.219-0.531 0.219t-0.531-0.219l-1.062-1.062q-0.219-0.219-0.219-0.531t0.219-0.531l2.297-2.297-2.297-2.297q-0.219-0.219-0.219-0.531t0.219-0.531l1.062-1.062q0.219-0.219 0.531-0.219t0.531 0.219l2.297 2.297 2.297-2.297q0.219-0.219 0.531-0.219t0.531 0.219l1.062 1.062q0.219 0.219 0.219 0.531t-0.219 0.531l-2.297 2.297 2.297 2.297q0.219 0.219 0.219 0.531z"></path>
58 </svg>',wp_kses_post(guaven_sqlcharts_recommended(),[]));
59 }
60
61
62
63 if (!empty($post) and $post->post_type == 'gvn_schart'):
64 if (!current_user_can('manage_options')) {
65 echo '<br><br>
66 <div class="updated gf-alert gf-alert-danger">Only administrators can manage this page</div>';
67 die();
68 }
69 echo '<div class="updated gf-alert gf-alert-info">';
70 if (empty($_GET["post"]) && strpos(sanitize_text_field(wp_unslash($_SERVER["REQUEST_URI"])), "post-new") === false) {
71 $gf_message = __(
72 'Use <b>Add new</b> button above to create a new SQL report. And click on any existing rule names below to manage them.',
73 'guaven_sqlcharts'
74 );
75 } else {
76 $gf_message = __(
77 '1. Give any name to your report.<br>
78 2. Pick a chart type, build your SQL query with the visual builder (or type it — autocomplete will help), map the X/Y columns and press Publish/Update.<br>
79 3. After update, you will see the shortcode of this chart at the bottom of the page. You can use that shortcode anywhere in your website: in pages, posts, widgets, etc.',
80 'guaven_sqlcharts'
81 );
82 }
83
84 echo '<div style="float:left;max-width:calc(100% - 345px)">';
85 echo wp_kses_post( $gf_message );
86 echo '</div>';
87
88 echo '<div style="float: right;
89 margin-top: 0px;
90 padding-top: 0px;"><a target="_blank" style="text-align:center;border:0px solid #6200ee;border-radius:0px;color:white;font-weight:bold;background: #6200ee;"
91 class="button button-secondary" href="https://guaven.com/contact/solution-request/">Get Premium Support </a>
92 <span style="line-height: 30px;padding: 0 5px;">OR</span>
93 <a target="_blank" style="text-align:center;border:0px solid #26b286;border-radius:0px;color:white;font-weight:bold;background: #26b286;"
94 class="button button-secondary" href="https://guaven.com/service/small-thankyou-premium-support-service/">Make a Small Donation</a>
95 </div> </div>';
96 endif;
97 }
98 add_action('admin_notices', 'guaven_sqlcharts_my_admin_notice');
99
100 function guaven_sqlcharts_onboarding_notice(){
101 if((function_exists('wp_doing_ajax') and wp_doing_ajax()) or get_option('guaven_sqlcharts_onboarding_notice_dismissed') == 1)
102 return;
103
104 printf('
105 <div class="guaven-sqlcharts-notice notice notice-success is-dismissible" data-notice="onboarding_notice">
106 <p>Welcome aboard on MySQL Charts!</p>
107 </div>'
108 );
109 }
110 add_action('admin_notices', 'guaven_sqlcharts_onboarding_notice');
111
112 function guaven_sqlcharts_onboarding_notice_dismissed(){
113 check_ajax_referer('notice_dismissed', 'nonce');
114
115 if(empty($_POST['type']))return;
116 switch ($_POST['type']){
117 case 'onboarding_notice':
118 update_option('guaven_sqlcharts_onboarding_notice_dismissed', 1);
119 break;
120 }
121 }
122 add_action('wp_ajax_guaven_sqlcharts_onboarding_notice_dismissed', 'guaven_sqlcharts_onboarding_notice_dismissed');
123
124 function guaven_sqlcharts_enqueue_chart()
125 {
126 wp_enqueue_script('guaven_sqlcharts_chartjs', plugins_url('asset/chart.umd.min.js', __FILE__),array('jquery'),GVNSQLCHARTS_VERSION,false);
127 wp_enqueue_script('guaven_sqlcharts_datepicker', plugins_url('asset/datepicker.min.js', __FILE__),array('jquery'),GVNSQLCHARTS_VERSION,false);
128 wp_enqueue_script('guaven_sqlcharts_front', plugins_url('asset/front.js', __FILE__),array('jquery','guaven_sqlcharts_chartjs','guaven_sqlcharts_datepicker'),GVNSQLCHARTS_VERSION,false);
129 wp_localize_script('guaven_sqlcharts_front', 'guaven_sqlcharts_notice_dismissed', array(
130 'action' => 'guaven_sqlcharts_onboarding_notice_dismissed',
131 'nonce' => wp_create_nonce('notice_dismissed')
132 ));
133
134 }
135 add_action('wp_enqueue_scripts', 'guaven_sqlcharts_enqueue_chart');
136 add_action('admin_enqueue_scripts', 'guaven_sqlcharts_enqueue_chart');
137
138 function guaven_sqlcharts_enqueue_main_style()
139 {
140 wp_enqueue_style('guaven_sqlcharts_main_style', plugins_url('asset/guaven_sqlcharts.css', __FILE__),array(),GVNSQLCHARTS_VERSION);
141 }
142 add_action('wp_enqueue_scripts', 'guaven_sqlcharts_enqueue_main_style');
143 add_action('admin_enqueue_scripts', 'guaven_sqlcharts_enqueue_main_style');
144
145 // admin-only assets: SQL builder, autocomplete, new metabox UI
146 function guaven_sqlcharts_admin_assets($hook)
147 {
148 if (!in_array($hook, array('post.php', 'post-new.php'))) return;
149 $screen = function_exists('get_current_screen') ? get_current_screen() : null;
150 if (empty($screen->post_type) or $screen->post_type != 'gvn_schart') return;
151 if (!current_user_can('manage_options')) return;
152
153 wp_enqueue_style('guaven_sqlcharts_admin_style', plugins_url('asset/admin.css', __FILE__), array(), GVNSQLCHARTS_VERSION);
154 wp_enqueue_script('guaven_sqlcharts_admin', plugins_url('asset/admin.js', __FILE__), array('jquery'), GVNSQLCHARTS_VERSION, true);
155
156 global $wpdb;
157 $tables = $wpdb->get_col('SHOW TABLES');
158 if (!is_array($tables)) $tables = array();
159 wp_localize_script('guaven_sqlcharts_admin', 'gvnSqlBuilder', array(
160 'ajaxurl' => admin_url('admin-ajax.php'),
161 'nonce' => wp_create_nonce('gvnsql_schema'),
162 'tables' => array_values($tables),
163 'prefix' => $wpdb->prefix,
164 ));
165 }
166 add_action('admin_enqueue_scripts', 'guaven_sqlcharts_admin_assets');
167
168 // returns column names of one table for the live SQL builder/autocomplete
169 function guaven_sqlcharts_ajax_columns()
170 {
171 check_ajax_referer('gvnsql_schema', 'nonce');
172 if (!current_user_can('manage_options')) wp_send_json_error('forbidden', 403);
173 global $wpdb;
174 $table = isset($_POST['table']) ? sanitize_text_field(wp_unslash($_POST['table'])) : '';
175 $tables = $wpdb->get_col('SHOW TABLES');
176 if (!is_array($tables) or !in_array($table, $tables, true)) wp_send_json_error('unknown table', 400);
177 $cols = $wpdb->get_results('SHOW COLUMNS FROM `' . str_replace('`', '', $table) . '`');
178 $out = array();
179 if (is_array($cols)) {
180 foreach ($cols as $col) {
181 $out[] = array('name' => $col->Field, 'type' => $col->Type);
182 }
183 }
184 wp_send_json_success($out);
185 }
186 add_action('wp_ajax_gvnsql_get_columns', 'guaven_sqlcharts_ajax_columns');
187
188
189 function guaven_sqlcharts_isJson($string)
190 {
191 json_decode($string);
192 return (json_last_error() == JSON_ERROR_NONE);
193 }
194
195 add_action('init', 'guaven_sqlcharts_register_post');
196 function guaven_sqlcharts_register_post()
197 {
198 register_post_type('gvn_schart', array(
199 'labels' => array(
200 'name' => __('My SQL Charts','guaven_sqlcharts'),
201 'singular_name' => __('SQL Chart','guaven_sqlcharts'),
202 'menu_name' => __('My SQL Charts','guaven_sqlcharts'),
203 'add_new' => __('Add Chart','guaven_sqlcharts'),
204 'add_new_item' => __('Add New Chart','guaven_sqlcharts'),
205 'edit_item' => __('Edit Chart','guaven_sqlcharts'),
206 'new_item' => __('New Chart','guaven_sqlcharts'),
207 'view_item' => __('View Chart','guaven_sqlcharts'),
208 'view_items' => __('View Charts','guaven_sqlcharts'),
209 'search_items' => __('Search Charts','guaven_sqlcharts'),
210 'not_found' => __('No charts found','guaven_sqlcharts'),
211 'not_found_in_trash' => __('No charts found in Trash','guaven_sqlcharts'),
212 'all_items' => __('All Charts','guaven_sqlcharts'),
213 'archives' => __('Chart Archives','guaven_sqlcharts'),
214 'attributes' => __('Chart Attributes','guaven_sqlcharts'),
215 'insert_into_item' => __('Insert into chart','guaven_sqlcharts'),
216 'uploaded_to_this_item' => __('Uploaded to this chart','guaven_sqlcharts'),
217 'filter_items_list' => __('Filter charts list','guaven_sqlcharts'),
218 'items_list_navigation' => __('Charts list navigation','guaven_sqlcharts'),
219 'items_list' => __('Charts list','guaven_sqlcharts'),
220 'item_published' => __('Chart published.','guaven_sqlcharts'),
221 'item_published_privately' => __('Chart published privately.','guaven_sqlcharts'),
222 'item_reverted_to_draft' => __('Chart reverted to draft.','guaven_sqlcharts'),
223 'item_scheduled' => __('Chart scheduled.','guaven_sqlcharts'),
224 'item_updated' => __('Chart updated.','guaven_sqlcharts'),
225 ),
226
227 'public' => true,
228 'menu_icon' => 'dashicons-chart-pie',
229 'supports' => array(
230 'title',
231 'postmeta'
232 ),
233 'register_meta_box_cb' => 'guaven_sqlcharts_metabox_area'
234 ));
235
236 guaven_sqlcharts_load_defaults();
237 }
238
239 // "Add title" placeholder on the chart edit screen
240 add_filter('enter_title_here', function ($title, $post) {
241 if (!empty($post) and $post->post_type == 'gvn_schart') return __('Chart name', 'guaven_sqlcharts');
242 return $title;
243 }, 10, 2);
244
245 add_action('admin_footer', 'guaven_sqlcharts_admin_front');
246
247
248 function guaven_sqlcharts_admin_front()
249 {
250 global $post;
251 if (!empty($post) and $post->post_type == 'gvn_schart') {
252 ?>
253 <style type="text/css">#normal-sortables{display: none}</style>
254 <?php
255 }
256 }
257
258 // metabox for editor
259 function guaven_sqlcharts_metabox_area()
260 {
261 add_meta_box('guaven_sqlcharts_metabox', 'Chart Builder', 'guaven_sqlcharts_metabox', 'gvn_schart', 'advanced', 'default');
262 }
263
264 function guaven_sqlcharts_metabox()
265 {
266 require_once(dirname(__FILE__) . "/admin_metabox.php");
267 }
268
269 /**
270 * Catalog of all supported chart types: label, group, per-type usage guide and example query.
271 * Used by the admin UI to render the type cards and the contextual guides.
272 */
273 function guaven_sqlcharts_type_catalog()
274 {
275 global $wpdb;
276 $p = $wpdb->posts;
277 $u = $wpdb->users;
278 return array(
279 'pie_l' => array(
280 'label' => 'Pie',
281 'group' => 'Circular',
282 'guide' => 'Best for showing how a total splits into a few parts (shares/percentages). Use one query that returns a label column (X) and a numeric value column (Y). Keep it under ~8 slices for readability.',
283 'example_sql' => "select count(*) postcount, SUBSTR(post_date,1,4) yearnum from $p group by yearnum order by yearnum asc limit 10",
284 'example_x' => 'yearnum', 'example_y' => 'postcount',
285 ),
286 'donut_l' => array(
287 'label' => 'Doughnut',
288 'group' => 'Circular',
289 'guide' => 'Same as Pie but with a hole in the middle — slightly easier to compare slice sizes. One query: label column (X) + numeric column (Y).',
290 'example_sql' => "select count(*) postcount, post_type from $p group by post_type order by postcount desc limit 8",
291 'example_x' => 'post_type', 'example_y' => 'postcount',
292 ),
293 'polar_l' => array(
294 'label' => 'Polar Area',
295 'group' => 'Circular',
296 'guide' => 'Like a pie, but every slice has the same angle and the value controls the radius. Good for cyclic data (months, weekdays). One query: label (X) + numeric value (Y).',
297 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,6,2) monthnum from $p group by monthnum order by monthnum",
298 'example_x' => 'monthnum', 'example_y' => 'postcount',
299 ),
300 'radar_l' => array(
301 'label' => 'Radar',
302 'group' => 'Circular',
303 'guide' => 'Compares one or more series across several categories arranged in a circle. Great for profiles/ratings. Use one query per series, separated with ";".',
304 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,6,2) monthnum from $p where post_type=\"post\" group by monthnum order by monthnum",
305 'example_x' => 'monthnum', 'example_y' => 'postcount',
306 ),
307 'line_l' => array(
308 'label' => 'Line',
309 'group' => 'Line',
310 'guide' => 'The classic choice for trends over time (per day/month/year). X should be an ordered value like a date. Add more queries separated with ";" for comparison lines.',
311 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,1,7) monthandyear from $p group by monthandyear order by monthandyear",
312 'example_x' => 'monthandyear', 'example_y' => 'postcount',
313 ),
314 'area_l' => array(
315 'label' => 'Area',
316 'group' => 'Line',
317 'guide' => 'A line chart with the region under the line filled — emphasizes volume/magnitude of a trend. Works well with 2 queries (";" separated) to compare filled regions.',
318 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,1,7) monthandyear from $p where post_type=\"post\" group by monthandyear order by monthandyear;\nselect count(*) postcount, SUBSTRING(post_date,1,7) monthandyear from $p where post_type!=\"post\" group by monthandyear order by monthandyear",
319 'example_x' => 'monthandyear', 'example_y' => 'Posts;Other content',
320 ),
321 'steppedline_l' => array(
322 'label' => 'Stepped Line',
323 'group' => 'Line',
324 'guide' => 'Line chart that moves in steps instead of slopes — perfect for values that change at discrete moments (prices, stock level, settings history).',
325 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,1,4) yearnum from $p group by yearnum order by yearnum",
326 'example_x' => 'yearnum', 'example_y' => 'postcount',
327 ),
328 'bar_l' => array(
329 'label' => 'Bar',
330 'group' => 'Bar',
331 'guide' => 'Compares values across categories with vertical bars. One query: category (X) + numeric value (Y). Multiple ";" separated queries become grouped/stacked bars.',
332 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,1,7) monthandyear from $p group by monthandyear order by monthandyear",
333 'example_x' => 'monthandyear', 'example_y' => 'postcount',
334 ),
335 'horizontalbar_l' => array(
336 'label' => 'Horizontal Bar',
337 'group' => 'Bar',
338 'guide' => 'Bar chart rotated 90° — the best pick when category names are long (user names, product titles).',
339 'example_sql' => "select count(*) as postcount, b.display_name as dname from $p a inner join $u b ON a.post_author=b.ID where a.post_status=\"publish\" group by a.post_author order by postcount desc limit 10",
340 'example_x' => 'dname', 'example_y' => 'postcount',
341 ),
342 'stackedbar_l' => array(
343 'label' => 'Stacked Bar',
344 'group' => 'Bar',
345 'guide' => 'Shows how each category total is composed of parts. Use 2+ queries separated with ";" — each query becomes one segment color of the stack.',
346 'example_sql' => "select count(*) postcount, SUBSTRING(post_date,1,4) yearnum from $p where post_type=\"post\" group by yearnum order by yearnum;\nselect count(*) postcount, SUBSTRING(post_date,1,4) yearnum from $p where post_type!=\"post\" group by yearnum order by yearnum",
347 'example_x' => 'yearnum', 'example_y' => 'Posts;Other content',
348 ),
349 'scatter_l' => array(
350 'label' => 'Scatter',
351 'group' => 'Other',
352 'guide' => 'Plots points on numeric X/Y axes to reveal correlation between two numbers. Both X and Y columns must be numeric (e.g. comment_count vs menu_order).',
353 'example_sql' => "select comment_count ccount, ID from $p where post_status=\"publish\" order by ID limit 100",
354 'example_x' => 'ID', 'example_y' => 'ccount',
355 ),
356 );
357 }
358
359 /**
360 * Maps deprecated Google-Chart era type slugs to their Chart.js equivalents.
361 * Old charts keep working without any manual migration; when the post is re-saved
362 * from the new UI the normalized value is stored automatically.
363 */
364 function guaven_sqlcharts_normalize_type($type)
365 {
366 $map = array(
367 'pie' => 'pie_l',
368 '3dpie' => 'pie_l',
369 'column' => 'bar_l',
370 'bar' => 'horizontalbar_l',
371 'area' => 'area_l',
372 );
373 return isset($map[$type]) ? $map[$type] : $type;
374 }
375
376 function guaven_gutenberg_wrapper($atts){
377 if(isset($atts['sqlcharts_inserted_script'])){
378 global $sqlcharts_inserted_script;
379 $sqlcharts_inserted_script = $atts['sqlcharts_inserted_script'];
380 }
381
382 $post = get_post($atts['chart_id']);
383 if( ! isset($atts['chart_id']) or !isset($post) or $post->post_type != 'gvn_schart'){
384
385 return "Invalid id";
386 }
387
388 return guaven_sqlcharts_local_shortcode(array('id' => $atts['chart_id'])); // temporary explicit value
389 }
390 function guaven_register_gutenberg_blocks()
391 {
392 wp_register_script(
393 'gvn_gutenberg_charts',
394 plugins_url( 'asset/guaven_gutenberg_charts.js', __FILE__ ),
395 array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-server-side-render' ),
396 GVNSQLCHARTS_VERSION.'_'.filemtime( plugin_dir_path( __FILE__ ) . 'asset/guaven_gutenberg_charts.js'),
397 false
398 );
399 wp_localize_script('gvn_gutenberg_charts', 'guaven', array(
400 'description' => 'Add My SQL Chart to your post',
401 ));
402
403 register_block_type( 'guaven-sqlcharts/gvn-chart-gutenberg', array(
404 'editor_script' => 'gvn_gutenberg_charts',
405 'render_callback' => 'guaven_gutenberg_wrapper',
406 'attributes' => array(
407 'chart_id' => array(
408 'type' => 'string',
409 'default' => null
410 ),
411 'sqlcharts_inserted_script' => array(
412 'type' => 'number',
413 'default' => null
414 )
415 )
416 ));
417 }
418 add_action('init', 'guaven_register_gutenberg_blocks');
419
420
421
422 function guaven_sqlcharts_save_metabox_area($post_id, $post)
423 {
424 if (!isset($_POST['meta_box_nonce_field']) or !wp_verify_nonce($_POST['meta_box_nonce_field'], 'meta_box_nonce_action')) {
425 return $post->ID;
426 }
427 $fields = array(
428 "guaven_sqlcharts_chartheight",
429 "guaven_sqlcharts_chartwidth",
430 "guaven_sqlcharts_graphtype",
431 "guaven_sqlcharts_xarg_s",
432 "guaven_sqlcharts_xarg_l",
433 "guaven_sqlcharts_yarg_s",
434 "guaven_sqlcharts_yarg_l",
435 "guaven_sqlcharts_tablepart",
436 "guaven_sqlcharts_variables",
437 "guaven_sqlcharts_formpartrole",
438 "guaven_sqlcharts_formpartbutton",
439 "guaven_sqlcharts_dbhost",
440 "guaven_sqlcharts_dblogin",
441 "guaven_sqlcharts_dbname",
442 "guaven_sqlcharts_colors",
443 "guaven_sqlcharts_begin_with_0_x",
444 "guaven_sqlcharts_begin_with_0_y",
445 "guaven_sqlcharts_round_y_values",
446 "guaven_sqlcharts_legend_position",
447 "guaven_sqlcharts_nostacked",
448 "guaven_sqlcharts_forcetooltips"
449 );
450 foreach ($fields as $key => $value) {
451 if(isset($_POST[$value]))$newval=esc_attr($_POST[$value]);
452 else $newval='';
453
454 update_post_meta($post->ID, $value, $newval);
455 }
456 if(!empty($_POST["guaven_sqlcharts_dbpass"])){
457 $encpass=guaven_sqlcharts_encrypt_decrypt('encrypt',$_POST["guaven_sqlcharts_dbpass"]);
458 update_post_meta($post->ID, 'guaven_sqlcharts_dbpass', ['encrypted',$encpass]);
459 }
460 // Store the SQL as typed. Do not HTML-encode it and do not rewrite quotes:
461 // the editor escapes it on output and the front end decodes entities before running it.
462 $sql_code = isset($_POST['guaven_sqlcharts_code']) ? wp_check_invalid_utf8(wp_unslash($_POST['guaven_sqlcharts_code'])) : '';
463 update_post_meta($post->ID, 'guaven_sqlcharts_code', $sql_code);
464 // Flag that this chart stores raw SQL. Charts without the flag were saved by
465 // versions before 3.0.1, which HTML-encoded the query, and still need decoding.
466 update_post_meta($post->ID, 'guaven_sqlcharts_code_raw', 1);
467 }
468
469 // Returns the stored SQL query exactly as the user typed it.
470 function guaven_sqlcharts_get_code($post_id)
471 {
472 $sql = get_post_meta($post_id, 'guaven_sqlcharts_code', true);
473 if (get_post_meta($post_id, 'guaven_sqlcharts_code_raw', true) != 1) {
474 $sql = html_entity_decode($sql, ENT_QUOTES, 'UTF-8');
475 }
476 return $sql;
477 }
478 add_action('save_post', 'guaven_sqlcharts_save_metabox_area', 1, 2);
479 // save the custom fields
480
481
482
483 function gvn_chart_check_sql_query($sql)
484 {
485 // case-insensitive, word-boundary check: only read-only SELECT queries are allowed
486 $pattern = '/\b(delete|update|insert|replace|drop|truncate|alter|create|rename|grant|revoke|call|handler|load\s+data|load_file|outfile|dumpfile)\b/i';
487 return preg_match($pattern, $sql) ? 1 : 0;
488 }
489
490 function guaven_get_labels_and_values($id, $fvs)
491 {
492 $values = array();
493 $labels = array();
494 $xarg_s = get_post_meta($id, 'guaven_sqlcharts_xarg_s', true);
495 $yarg_s = get_post_meta($id, 'guaven_sqlcharts_yarg_s', true);
496 // labels are saved through esc_attr, so "&" is stored as "&amp;"; decode before splitting on ";"
497 // or the entity's own ";" would be taken as a series separator
498 $xarg_l = html_entity_decode((string) get_post_meta($id, 'guaven_sqlcharts_xarg_l', true), ENT_QUOTES, 'UTF-8');
499 $yarg_l = html_entity_decode((string) get_post_meta($id, 'guaven_sqlcharts_yarg_l', true), ENT_QUOTES, 'UTF-8');
500 foreach ($fvs as $key => $value) {
501 $values[$value->$xarg_s] = $value->$yarg_s;
502 $labels[$value->$xarg_s] = '"' . $value->$xarg_s . '"';
503 }
504 return array(
505 $labels,
506 $values,
507 explode(";", $yarg_l),
508 explode(";", $xarg_l)
509 );
510 }
511
512 function guaven_sqlcharts_print_chart_js($print_data)
513 {
514 extract($print_data);
515 $tip_g = guaven_sqlcharts_normalize_type($tip_g);
516
517 switch ($tip_g) {
518 case 'line_l':
519 guaven_sqlcharts_linedata($title, $labels, $values, $ylabel, 'false', $pid);
520 break;
521 case 'area_l':
522 guaven_sqlcharts_linedata($title, $labels, $values, $ylabel, 'true', $pid);
523 break;
524 case 'steppedline_l':
525 guaven_sqlcharts_linedata($title, $labels, $values, $ylabel, 'false', $pid, 'line', true);
526 break;
527 case 'radar_l':
528 guaven_sqlcharts_linedata($title, $labels, $values, $ylabel, 'radarfill', $pid, 'radar');
529 break;
530 case 'pie_l':
531 guaven_sqlcharts_piedata($title, $labels, $values, $ylabel, $pid);
532 break;
533 case 'donut_l':
534 guaven_sqlcharts_piedata($title, $labels, $values, $ylabel, $pid, 'doughnut');
535 break;
536 case 'polar_l':
537 guaven_sqlcharts_piedata($title, $labels, $values, $ylabel, $pid, 'polarArea');
538 break;
539 case 'bar_l':
540 guaven_sqlcharts_bardata($title, $labels, $values, $ylabel, 'bar', $pid);
541 break;
542 case 'horizontalbar_l':
543 guaven_sqlcharts_bardata($title, $labels, $values, $ylabel, 'horizontalBar', $pid);
544 break;
545 case 'stackedbar_l':
546 guaven_sqlcharts_bardata($title, $labels, $values, $ylabel, 'stackedBar', $pid);
547 break;
548 case 'scatter_l':
549 guaven_sqlcharts_scatterdata($title, $labels, $values, $ylabel, $pid);
550 break;
551 case 'custom':
552 guaven_sqlcharts_custom($title, $labels, $values, $ylabel, $pid);
553 break;
554 }
555 }
556
557 function guaven_sqlcharts_custom($title, $labels, $values, $ylabel, $pid){
558 do_action('guaven_sqlcharts_custom',$title, $labels, $values, $ylabel, $pid);
559 }
560
561 function gvn_chart_put_variables($sql,$pid){
562 $sql_initial=$sql;
563
564
565 $default_tag_keys=['{current_user_id}','{current_user_login}','{current_user_email}','{current_user_display_name}'];
566 if(is_user_logged_in( )){
567 $currentuser=wp_get_current_user();
568 $default_tag_values=[$currentuser->ID,$currentuser->user_login,$currentuser->user_email,$currentuser->user_display_name];
569 }
570 else {
571 $default_tag_values='';
572 }
573 $sql_initial=str_replace($default_tag_keys,$default_tag_values,$sql_initial);
574
575 $variables_raw=get_post_meta($pid,'guaven_sqlcharts_variables',true);
576 $variables_arr=explode("|",$variables_raw);
577 foreach($variables_arr as $varfield){
578 $varfield_arr=explode("~",$varfield);
579 if (count($varfield_arr)<3) continue;
580 $varfield_arr=array_map("trim",$varfield_arr);
581 if (!empty($_GET[$varfield_arr[0]])) {
582 // User-supplied input: no () bypass allowed — sanitize strictly
583 $varreplacement = sanitize_text_field(wp_unslash($_GET[$varfield_arr[0]]));
584 if (is_numeric($varreplacement)) {
585 $varreplacement = $varreplacement + 0;
586 } else {
587 $varreplacement = '"' . esc_sql($varreplacement) . '"';
588 }
589 } else {
590 // Admin-configured default value: allow () for SQL functions (e.g. NOW())
591 $varreplacement = $varfield_arr[1];
592 if (!is_numeric($varreplacement) && strpos($varreplacement,'()')===false) {
593 $varreplacement = '"' . esc_sql($varreplacement) . '"';
594 }
595 }
596
597 $sql_initial=str_replace('{'.$varfield_arr[0].'}',$varreplacement,$sql_initial);
598 }
599 return $sql_initial;
600 }
601
602 function gvn_chart_top_form($atts){
603 if (get_post_meta($atts["id"],'guaven_sqlcharts_formpartrole',true)!='' and !is_user_logged_in()) return;
604 $topform='';$dateexists=false;
605 $variables_raw=get_post_meta($atts['id'],'guaven_sqlcharts_variables',true);
606 $variables_raw=explode("|",$variables_raw);
607 foreach ($variables_raw as $vrow){
608 $vrow_arr=explode("~",$vrow);
609 $vrow_arr=array_map("trim",$vrow_arr);
610 if (empty($vrow_arr[3])) continue;
611 $gvalue=!empty($_GET[$vrow_arr[0]])?esc_attr(urldecode($_GET[$vrow_arr[0]])):'';
612 $dvalue=(strpos($vrow_arr[1],'()')===false)?esc_attr($vrow_arr[1]):'';
613 if ($vrow_arr[3]=='date') {
614 $dateexists=true;
615 $topform.= '<span class="gvn-filter-field"><label>'.$vrow_arr[2].'</label> <input class="gws_datepicker" autocomplete="off" type="text"
616 value="'.$gvalue.'"
617 data-toggle="datepicker" name="'.$vrow_arr[0].'" placeholder="'.$dvalue.'"></span>
618 ';}
619 else {
620 $topform.= '<span class="gvn-filter-field"><label>'.$vrow_arr[2].'</label> <input autocomplete="off"
621 type="'.$vrow_arr[3].'"
622 value="'.$gvalue.'" name="'.$vrow_arr[0].'" placeholder="'.$dvalue.'"></span>
623 ';
624 }
625 }
626 if (!empty($topform)) {
627 $allowed_html = array(
628 'form' => array(
629 'method' => array(),
630 'action' => array(),
631 'class' => array()
632 ),
633 'input' => array(
634 'type' => array(),
635 'value' => array(),
636 'name' => array(),
637 'class' => array(),
638 'data-toggle'=>array(),
639 'placeholder'=>array(),
640 'autocomplete'=>array(),
641 'style'=>[]
642 ),
643 'span' => array('class' => array()),
644 'label' => array(),
645 );
646
647 $submit_button_value = get_post_meta($atts['id'], 'guaven_sqlcharts_formpartbutton', true) != ''
648 ? esc_attr(get_post_meta($atts['id'], 'guaven_sqlcharts_formpartbutton', true))
649 : 'OK';
650
651 $topform = '<form method="get" action="" class="guaven_sqlcharts_form">' . $topform . '
652 <input type="submit" value="' . $submit_button_value . '"></form>';
653
654 echo wp_kses($topform, $allowed_html);
655 }
656 }
657
658
659 function guaven_sqlcharts_encrypt_decrypt($action, $string)
660 {
661 $output = false;
662 $encrypt_method = "AES-256-CBC";
663 $secret_key = 'GWSCHARTPL2022.2016.';
664 $secret_iv = 'GWSCHARTPL2016.2022';
665 $key = hash('sha256', $secret_key);
666 $iv = substr(hash('sha256', $secret_iv), 0, 16);
667 if ( $action == 'encrypt' ) {
668 $output = openssl_encrypt($string, $encrypt_method, $key, 0, $iv);
669 $output = base64_encode($output);
670 } else if( $action == 'decrypt' ) {
671 $output = openssl_decrypt(base64_decode($string), $encrypt_method, $key, 0, $iv);
672 }
673 return $output;
674 }
675
676 function guaven_sqlcharts_local_shortcode($atts) {
677 if(empty($atts['id']))return 'ID is missing.';
678 $atts['id']=intval($atts['id']);
679 $remote_host=get_post_meta($atts['id'], 'guaven_sqlcharts_dbhost', true);
680 if ($remote_host!=''){
681 $remote_db=get_post_meta($atts['id'], 'guaven_sqlcharts_dbname', true);
682 $remote_login=get_post_meta($atts['id'], 'guaven_sqlcharts_dblogin', true);
683 $remote_pass=get_post_meta($atts['id'], 'guaven_sqlcharts_dbpass', true);
684 if(is_array($remote_pass)){
685 $remote_pass=guaven_sqlcharts_encrypt_decrypt('decrypt',$remote_pass[1]);
686 }
687 $wpdb=new wpdb($remote_login,$remote_pass,$remote_db,$remote_host);
688 }
689 else {
690 global $wpdb;
691 }
692
693 $GLOBALS["guaven_sqlcharts_atts"]=$atts;
694
695 $sql = guaven_sqlcharts_get_code($atts['id']);
696 if(empty($sql))return 'SQL query is missing.';
697 $sql=gvn_chart_put_variables($sql,$atts['id']);
698
699
700 $sql=apply_filters('guaven_sqlcharts_rendered_sql',$sql,$atts);
701
702 $blacklister_f = gvn_chart_check_sql_query($sql);
703 if ($blacklister_f == 1)return 'You given SQL code contains forbidden commands. Remember that you should only use SELECT queries';
704 $tip_g = guaven_sqlcharts_normalize_type(get_post_meta($atts['id'], 'guaven_sqlcharts_graphtype', true));
705
706 for($i=1;$i<20;$i++){
707 if(strpos($sql,"{arg".$i."}")!==false){
708 $replacearg=!empty($atts["arg".$i])?$atts["arg".$i]:0;
709 $sql = str_replace("{arg".$i."}", "%s", $sql);
710 $sql=$wpdb->prepare($sql,$replacearg);
711 }
712
713 }
714
715 $sql_split = explode(';', $sql);
716 $labels_and_values = array();
717 $post_g = get_post($atts['id']);
718
719 global $sqlcharts_inserted_script;
720 ob_start();
721 for ($i = 0; $i < count($sql_split); $i++) {
722 if (!empty($sql_split[$i])) {
723
724 $fvs = $wpdb->get_results($sql_split[$i]);
725 if (strpos($_SERVER["REQUEST_URI"],'wp-admin')!==false){
726 $wpdb->show_errors();
727 ob_start();
728 $wpdb->print_error();
729 $printerror = ob_get_clean();
730 if ($printerror != '' and strpos($printerror, "[]") === false){
731 ob_end_clean();
732 return $printerror;
733 }
734 elseif (empty($fvs)){
735 ob_end_clean();
736 return 'Your SQL returnes empty data, please recheck your SQL query above';
737 }
738 }
739
740 if (empty($sqlcharts_inserted_script))
741 $sqlcharts_inserted_script = 1;
742 $labels_and_values[$i] = guaven_get_labels_and_values($atts['id'], $fvs);
743 $labels[$i] = $labels_and_values[$i][0];
744 $values[$i] = $labels_and_values[$i][1];
745 $ylabel[$i] = !empty($labels_and_values[$i][2][$i]) ? $labels_and_values[$i][2][$i] : '';
746 $xlabel[$i] = !empty($labels_and_values[$i][3][$i]) ? $labels_and_values[$i][3][$i] : '';
747 }
748 }
749
750 gvn_chart_top_form($atts);
751
752 // shortcode width/height attributes override the saved defaults
753 $chart_w = !empty($atts['width']) ? $atts['width'] : get_post_meta($atts['id'], 'guaven_sqlcharts_chartwidth', true);
754 $chart_h = !empty($atts['height']) ? $atts['height'] : get_post_meta($atts['id'], 'guaven_sqlcharts_chartheight', true);
755 $wrap_style = '';
756 if ($chart_w != '') $wrap_style .= 'max-width:' . (int) $chart_w . 'px;';
757 if ($chart_h != '') $wrap_style .= 'height:' . (int) $chart_h . 'px;';
758 ?>
759 <div class="gvn-chartwrap"<?php echo $wrap_style != '' ? ' style="' . esc_attr($wrap_style) . '"' : ''; ?>>
760 <canvas
761 id="ct-chart_<?php echo esc_attr($sqlcharts_inserted_script); ?>"
762 class="guaven_chart_canvas"
763 ></canvas>
764 </div>
765
766 <script type="text/javascript" class="gvn_charts_script" async>
767 var ctx = jQuery("#ct-chart_<?php
768 echo esc_attr($sqlcharts_inserted_script);
769 ?>");
770
771 <?php
772 $print_data=apply_filters('guaven_sqlcharts_pre_print_vars',['tip_g'=>$tip_g, 'title'=>$post_g->post_title,
773 'labels'=>$labels, 'values'=>$values, 'ylabel'=>$ylabel, 'pid'=>$atts['id']]);
774 guaven_sqlcharts_print_chart_js($print_data);
775 ?>
776 </script>
777
778 <?php
779 if (!empty($atts["table"])) guaven_sqlcharts_tablepart($post_g->post_title, $labels, $values, $ylabel,$xlabel);
780 $sqlcharts_inserted_script++;
781 $ret=ob_get_clean();
782 $ret=apply_filters( 'guaven_sqlcharts_final_output', $ret, $atts );
783 return $ret;
784 }
785
786 add_shortcode('gvn_schart_2', 'guaven_sqlcharts_local_shortcode');
787
788 // legacy alias: old Google-Chart era posts produced [gvn_schart id=".."] shortcodes
789 if (!shortcode_exists('gvn_schart')) {
790 add_shortcode('gvn_schart', 'guaven_sqlcharts_local_shortcode');
791 }
792
793 add_shortcode("gvn_schart_2_cached",function($atts){
794 if(empty($atts["id"]))return;
795 $atts["id"]=intval($atts["id"]);
796 $is_logged_in=is_user_logged_in()?'':'_guest';
797 $expire=!empty($atts["expire"])?intval($atts["expire"]):3600;
798 $cached=get_transient('cached_sql_charts_'.$atts["id"].$is_logged_in);
799 if(!empty($cached) and !isset($_GET["force_sql_cache_reload"]) )return $cached;
800 $tobecached=do_shortcode('[gvn_schart_2 id="'.$atts["id"].'"]');
801 set_transient('cached_sql_charts_'.$atts["id"].$is_logged_in, $tobecached,$expire);//you can change 3600 yourself
802 return $tobecached;
803 });
804
805 // fixed, colorblind-friendly default palette (Tableau 10) used when no custom colors are set
806 function guaven_sqlcharts_default_palette(){
807 return apply_filters('guaven_sqlcharts_default_palette', array(
808 '#4E79A7', '#F28E2B', '#E15759', '#76B7B2', '#59A14F',
809 '#EDC948', '#B07AA1', '#FF9DA7', '#9C755F', '#BAB0AC'
810 ));
811 }
812
813 function guaven_sqlcharts_colors($index, $pid = null){
814 if(!isset($pid)) {
815 global $post;
816 $pid = $post->ID;
817 }
818 $colors=get_post_meta($pid,'guaven_sqlcharts_colors',true);
819 $colors=explode(",",$colors);
820 if (!empty($colors[$index])) return $colors[$index];
821 $palette = guaven_sqlcharts_default_palette();
822 return $palette[$index % count($palette)];
823 }
824
825 // outputs 'maintainAspectRatio:false,' when an explicit height is set, so the
826 // chart fills its sized wrapper instead of keeping the default aspect ratio
827 function guaven_sqlcharts_mar($pid){
828 $atts = isset($GLOBALS["guaven_sqlcharts_atts"]) ? $GLOBALS["guaven_sqlcharts_atts"] : array();
829 $h = !empty($atts['height']) ? $atts['height'] : get_post_meta($pid, 'guaven_sqlcharts_chartheight', true);
830 return $h != '' ? 'maintainAspectRatio: false,' : '';
831 }
832
833 // outputs 'showAllTooltips: true,' when "Value labels" is checked; the values are drawn by the
834 // gvnShowAllValues plugin in asset/front.js (works for every chart type)
835 function guaven_sqlcharts_value_labels($pid){
836 return get_post_meta($pid, 'guaven_sqlcharts_forcetooltips', true) != '' ? 'showAllTooltips: true,' : '';
837 }
838
839 // Chart.js scale title block built from the "X axis label" / "Y axis label" fields.
840 // $which is 'x' or 'y' (the *field* to use, not the scale). The Y label is only used as an axis
841 // title for single-series charts; with several ";"-separated series the legend names them instead.
842 function guaven_sqlcharts_axis_title($pid, $which){
843 $key = $which == 'x' ? 'guaven_sqlcharts_xarg_l' : 'guaven_sqlcharts_yarg_l';
844 $text = trim(html_entity_decode((string) get_post_meta($pid, $key, true), ENT_QUOTES, 'UTF-8'));
845 if ($text === '' or ($which == 'y' and strpos($text, ';') !== false)) return '';
846 return 'title: {display: true, text: ' . wp_json_encode($text) . '},';
847 }
848
849 // dataset label as a safe JS string literal (labels saved before 3.0.1 may hold HTML entities)
850 function guaven_sqlcharts_js_label($label){
851 return wp_json_encode(html_entity_decode((string) $label, ENT_QUOTES, 'UTF-8'));
852 }
853
854 function guaven_sqlcharts_bardata($title, $labels, $values, $ylabel, $type = 'bar', $pid = null)
855 {
856 $horizontal = ($type == 'horizontalBar');
857 $forcestack = ($type == 'stackedBar');
858 $stacked = ($forcestack or get_post_meta($pid, 'guaven_sqlcharts_nostacked', true) != 1) ? 'true' : 'false';
859 ?>
860 var data = {
861 labels: [<?php guaven_sqlcharts_merge_labeldata($labels);?>],
862 datasets: [
863 <?php
864 $values_new=guaven_sqlcharts_key_normalizer($values,$labels,$ylabel)[0];
865 $i=-1;
866 foreach ($values_new as $key_ak=>$value_ak) {
867 $i++;
868 ?>
869 {
870 <?php
871 if(!empty($GLOBALS["guaven_sqlcharts_atts"]["params"])){
872 //passing chartJS params via the shortcode
873 echo wp_kses($GLOBALS["guaven_sqlcharts_atts"]["params"],[]);
874 }
875 ?>
876 label: <?php echo guaven_sqlcharts_js_label($ylabel[$key_ak]); ?>,
877 backgroundColor: [
878 <?php
879 echo wp_kses(guaven_sqlcharts_colorgenerator(count($values_new[$key_ak]), 0, 0, guaven_sqlcharts_colors($i, $pid)),[]);
880 ?>
881 ],
882 borderColor: [
883 <?php
884 echo wp_kses(guaven_sqlcharts_colorgenerator(count($values_new[$key_ak]), 0, 0.2, guaven_sqlcharts_colors($i, $pid)),[]);
885 ?>
886 ],
887 borderWidth: 1,
888 data: [<?php
889 echo wp_kses(implode(",", $values_new[$key_ak]),[]);
890 ?>],
891 },
892 <?php
893 }
894 ?>
895 ]
896 };
897 var options={
898 responsive: true,
899 <?php echo wp_kses(guaven_sqlcharts_mar($pid),[]); ?>
900 <?php echo wp_kses(guaven_sqlcharts_value_labels($pid),[]); ?>
901 <?php if ($horizontal) echo "indexAxis: 'y',"; ?>
902 scales: {
903 x: {
904 <?php echo guaven_sqlcharts_axis_title($pid, $horizontal ? 'y' : 'x'); ?>
905 stacked: <?php echo esc_js($stacked); ?>,
906 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_x', true) == 1) ? 'true':'false'; ?>
907 },
908 y: {
909 <?php echo guaven_sqlcharts_axis_title($pid, $horizontal ? 'x' : 'y'); ?>
910 stacked: <?php echo esc_js($stacked); ?>,
911 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_y', true) == 1) ? 'true':'false'; ?>,
912 ticks: {
913 <?php if(get_post_meta($pid, 'guaven_sqlcharts_round_y_values', true) == 1) echo 'precision: 0,'; ?>
914 }
915 }
916 }
917 <?php
918 guaven_sqlcharts_maybe_additional_parameters($pid);
919 ?>
920 };
921 var myBarChart = new Chart(ctx, {
922 type: 'bar',
923 data: data,
924 options: options
925 });
926 <?php
927 }
928
929 function guaven_sqlcharts_merge_labeldata($labels){
930 if(count($labels)==1){echo wp_kses(implode(",",$labels[0]),[]);return;}
931 $merged=[];
932 foreach($labels as $label){
933 $merged=array_merge($merged,$label);
934 }
935 echo wp_kses(implode(",",array_unique($merged)),[]);
936 }
937
938 function guaven_sqlcharts_linedata($title, $labels, $values, $ylabel, $type = 'false', $pid = null, $charttype = 'line', $stepped = false)
939 {
940 ?>
941 var data = {
942 labels: [<?php guaven_sqlcharts_merge_labeldata($labels);?>],
943 datasets: [
944 <?php
945 $values_new=guaven_sqlcharts_key_normalizer($values,$labels,$ylabel)[0];
946 $dataset_count=count($values_new);
947 $i=-1;
948 foreach ($values_new as $key_ak=>$value_ak) {
949 $i++;
950 if ($type == 'radarfill') $fill = "'origin'";
951 elseif ($type == 'false') $fill = 'false';
952 else $fill = ($i == 0 and $dataset_count > 1) ? '"+1"' : '"origin"';
953 ?>
954 {
955 <?php
956 if(!empty($GLOBALS["guaven_sqlcharts_atts"]["params"])){
957 //passing chartJS params via the shortcode
958 echo wp_kses($GLOBALS["guaven_sqlcharts_atts"]["params"],[]);
959 }
960 ?>
961 label: <?php echo guaven_sqlcharts_js_label($ylabel[$key_ak]); ?>,
962 fill: <?php echo wp_kses($fill,[]);
963 ?>,
964 tension: 0.1,
965 <?php if ($stepped) echo 'stepped: true,'; ?>
966 backgroundColor: <?php
967 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
968 ?>
969 borderColor: <?php
970 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
971 ?>
972 pointBorderColor: <?php
973 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
974 ?>
975 pointHoverBackgroundColor: <?php
976 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
977 ?>
978 pointHoverBorderColor: <?php
979 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
980 ?>
981 data: [<?php
982 echo wp_kses_post(implode(",", $values_new[$key_ak]));
983 ?>],
984 spanGaps: false,
985 },
986 <?php
987 }
988 ?>
989 ]
990 };
991 var myLineChart = new Chart(ctx, {
992 type: '<?php echo esc_attr($charttype); ?>',
993 data: data,
994 options: {
995 responsive: true,
996 <?php echo wp_kses(guaven_sqlcharts_mar($pid),[]); ?>
997 <?php echo wp_kses(guaven_sqlcharts_value_labels($pid),[]); ?>
998 <?php if ($charttype == 'radar') { ?>
999 scales: {
1000 r: {
1001 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_y', true) == 1) ? 'true':'false'; ?>
1002 }
1003 }
1004 <?php } else { ?>
1005 scales: {
1006 x: {
1007 display: true,
1008 <?php echo guaven_sqlcharts_axis_title($pid, 'x'); ?>
1009 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_x', true) == 1) ? 'true':'false'; ?>
1010 },
1011 y: {
1012 <?php echo guaven_sqlcharts_axis_title($pid, 'y'); ?>
1013 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_y', true) == 1) ? 'true':'false'; ?>,
1014 ticks: {
1015 <?php if(get_post_meta($pid, 'guaven_sqlcharts_round_y_values', true) == 1) echo 'precision: 0,'; ?>
1016 }
1017 }
1018 }
1019 <?php } ?>
1020 <?php
1021 guaven_sqlcharts_maybe_additional_parameters($pid);
1022 ?>
1023
1024 }
1025 });
1026 <?php
1027 }
1028
1029 function guaven_sqlcharts_scatterdata($title, $labels, $values, $ylabel, $pid = null)
1030 {
1031 ?>
1032 var data = {
1033 datasets: [
1034 <?php
1035 $i=-1;
1036 foreach ($values as $key_ak=>$value_ak) {
1037 $i++;
1038 $points=array();
1039 foreach ($value_ak as $xval=>$yval) {
1040 $x = is_numeric($xval) ? $xval : '"'.esc_js($xval).'"';
1041 $y = is_numeric($yval) ? $yval : '"'.esc_js($yval).'"';
1042 $points[] = '{x:'.$x.',y:'.$y.'}';
1043 }
1044 ?>
1045 {
1046 <?php
1047 if(!empty($GLOBALS["guaven_sqlcharts_atts"]["params"])){
1048 //passing chartJS params via the shortcode
1049 echo wp_kses($GLOBALS["guaven_sqlcharts_atts"]["params"],[]);
1050 }
1051 ?>
1052 label: <?php echo guaven_sqlcharts_js_label(isset($ylabel[$key_ak])?$ylabel[$key_ak]:''); ?>,
1053 backgroundColor: <?php
1054 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
1055 ?>
1056 borderColor: <?php
1057 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 1, 0.2, guaven_sqlcharts_colors($i, $pid)));
1058 ?>
1059 data: [<?php echo wp_kses(implode(",", $points),[]); ?>],
1060 },
1061 <?php
1062 }
1063 ?>
1064 ]
1065 };
1066 var myScatterChart = new Chart(ctx, {
1067 type: 'scatter',
1068 data: data,
1069 options: {
1070 responsive: true,
1071 <?php echo wp_kses(guaven_sqlcharts_mar($pid),[]); ?>
1072 <?php echo wp_kses(guaven_sqlcharts_value_labels($pid),[]); ?>
1073 scales: {
1074 x: {
1075 <?php echo guaven_sqlcharts_axis_title($pid, 'x'); ?>
1076 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_x', true) == 1) ? 'true':'false'; ?>
1077 },
1078 y: {
1079 <?php echo guaven_sqlcharts_axis_title($pid, 'y'); ?>
1080 beginAtZero: <?php echo (get_post_meta($pid, 'guaven_sqlcharts_begin_with_0_y', true) == 1) ? 'true':'false'; ?>,
1081 ticks: {
1082 <?php if(get_post_meta($pid, 'guaven_sqlcharts_round_y_values', true) == 1) echo 'precision: 0,'; ?>
1083 }
1084 }
1085 }
1086 <?php
1087 guaven_sqlcharts_maybe_additional_parameters($pid);
1088 ?>
1089 }
1090 });
1091 <?php
1092 }
1093
1094
1095 function guaven_sqlcharts_maybe_additional_parameters($pid){
1096 if(function_exists('guaven_sqlcharts_maybe_additional_parameters_custom')){
1097 wp_kses(guaven_sqlcharts_maybe_additional_parameters_custom($pid),[]);
1098 return;
1099 }
1100 $guaven_sqlcharts_legend_position=get_post_meta($pid, 'guaven_sqlcharts_legend_position', true);
1101 if(in_array($guaven_sqlcharts_legend_position,['top','bottom','left','right'])){
1102 $display='true';$position=$guaven_sqlcharts_legend_position;
1103 }
1104 else {
1105 $display='false';$position='top';
1106 }
1107 echo wp_kses( ",plugins: {legend: {display: ".$display.",position:'".$position."'}}",[]);
1108 }
1109
1110
1111
1112
1113 function guaven_sqlcharts_piedata($title, $labels, $values, $ylabel, $pid, $type = 'pie')
1114 {
1115 ?>
1116 var options={
1117 <?php echo wp_kses(guaven_sqlcharts_value_labels($pid),[]); ?>
1118 responsive: true
1119 <?php echo get_post_meta($pid,'guaven_sqlcharts_chartheight',true)!=''||!empty($GLOBALS["guaven_sqlcharts_atts"]['height'])?',maintainAspectRatio: false':''; ?>
1120 <?php
1121 guaven_sqlcharts_maybe_additional_parameters($pid);
1122 ?>
1123 };
1124 var data = {
1125 labels: [ <?php guaven_sqlcharts_merge_labeldata($labels);?>],
1126 datasets: [
1127 <?php
1128 for ($i = 0; $i < count($values); $i++) {
1129 ?>
1130 {
1131 <?php
1132 if(!empty($GLOBALS["guaven_sqlcharts_atts"]["params"])){
1133 //passing chartJS params via the shortcode
1134 echo wp_kses($GLOBALS["guaven_sqlcharts_atts"]["params"],[]);
1135 }
1136 ?>
1137 data: [<?php
1138 echo wp_kses(implode(",", $values[$i]),[]);
1139 ?>],
1140 backgroundColor: [
1141 <?php
1142 $ii=0;
1143 foreach($values[$i] as $vci=>$valuecolor){
1144 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 0, -0.1, guaven_sqlcharts_colors($ii, $pid)));
1145 $ii++;
1146 }
1147 ?>
1148 ],
1149 hoverBackgroundColor: [
1150 <?php
1151 $ii=0;
1152 foreach($values[$i] as $vci=>$valuecolor){
1153 echo wp_kses_post(guaven_sqlcharts_colorgenerator(1, 0, 0.2, guaven_sqlcharts_colors($ii, $pid)));
1154 $ii++;
1155 }
1156 ?>
1157 ]
1158 },
1159 <?php
1160 }
1161 ?>
1162 ]
1163 };
1164 var myPieChart = new Chart(ctx,{
1165 type: '<?php
1166 echo esc_attr($type);
1167 ?>',
1168 data: data,
1169 options: options
1170 });
1171 <?php
1172 }
1173
1174
1175
1176
1177 function guaven_sqlcharts_colorgenerator($count, $indic, $darkness = 0, $initcolor = '255,0,0')
1178 {
1179 if (strpos($initcolor,'#')===0) {
1180 $split = str_split(substr($initcolor,1), 2);
1181 $r = hexdec($split[0]);
1182 $g = hexdec($split[1]);
1183 $b = hexdec($split[2]);
1184 $ret='';
1185 for ($i = 0; $i < $count; $i++) {
1186 $ret .= "'rgba(" . $r . ", " . $g . ", " . $b . ",".($darkness + 0.8 - $indic * $i * 0.8 / ($count)).")',
1187 ";
1188 }
1189 return $ret;
1190 }
1191 $initial_colors = array(
1192 'linebg' => 'red',
1193 'linebr' => 'yellow',
1194 'linebc' => 'green',
1195 'linehbg' => 'white',
1196 'linehbc' => 'black'
1197 );
1198 if (!empty($initial_colors[$count]))
1199 return '"' . $initial_colors[$count] . '",
1200 ';
1201 $ret = '';
1202 for ($i = 0; $i < $count; $i++) {
1203 $ret .= "'rgba(" . $initcolor . "," . ($darkness + 0.8 - $indic * $i * 0.8 / ($count)) . ")',
1204 ";
1205 }
1206 return $ret;
1207 }
1208
1209 function guaven_sqlcharts_tablepart($title, $labels, $values, $ylabel,$xlabel){
1210 $tabledata='';
1211 $fcol=[];$scol=[];
1212 $empty_cell=apply_filters( 'guaven_sqlcharts_table_empty_cell','<td></td>');
1213 $tablein='';
1214 foreach($values as $row=>$valuerow){
1215 foreach ($valuerow as $key => $value) {
1216 $putval=$labels[$row][$key]??'';
1217 $fcol[$key]='<td>'.str_replace('"',"",$putval).'</td>';
1218 $scol[$key][$row]='<td>'.$value.'</td>';
1219 }
1220 foreach($scol as $scolkey=>$scolvalue){
1221 for($i=0;$i<count($values);$i++){
1222 //echo $i;
1223 if(!isset($scolvalue[$i]))$scol[$scolkey][$i]=$empty_cell;;
1224 }
1225 ksort($scol[$scolkey]);
1226 }
1227 }
1228
1229 foreach($fcol as $key=>$value){
1230 $tablein.='<tr>'.$value.implode(" ",$scol[$key]).'</tr>'.PHP_EOL;
1231 }
1232 $tabledata.='<div class="gvn-tablewrap"><table class="gvn-table"><tr><th>'.$xlabel[0].'</th><th>'.implode("</th><th>",$ylabel).'</th></tr>
1233 '.$tablein.'</table></div><br>';
1234
1235 echo wp_kses_post($tabledata);
1236
1237 }
1238
1239 function guaven_sqlcharts_graphtype($post){
1240 if (strpos(get_post_meta($post->ID, 'guaven_sqlcharts_graphtype', true), "_l") !== false)
1241 $postfix = '_2';
1242 else $postfix = '';
1243 return $postfix;
1244 }
1245
1246 add_filter('the_content',function($content){
1247 if(!is_singular('gvn_schart'))return $content;
1248 global $post;
1249 $postfix=guaven_sqlcharts_graphtype($post);
1250 return '[gvn_schart'.$postfix.' id="'.$post->ID.'"'.
1251 (get_post_meta($post->ID,'guaven_sqlcharts_tablepart',true)!=''?' table="1"':'')
1252 .']';
1253 });
1254
1255 function guaven_sqlcharts_key_normalizer($values,$labels,$ylabel){
1256 $normalize_keys=[];
1257 $empty_value=apply_filters( 'guaven_sqlcharts_table_empty_value','');
1258 foreach ($values as $key_ak=>$value_ak) {
1259 $normalize_keys=array_merge($normalize_keys,array_keys($values[$key_ak]));
1260 }
1261 $values_normalized=[];$labels_normalized=[];$ylabel_normalized=[];
1262 foreach($normalize_keys as $normalized_key){
1263 foreach ($values as $key_ak=>$value_ak) {
1264 $values_normalized[$key_ak][$normalized_key]=isset( $values[$key_ak][$normalized_key])? $values[$key_ak][$normalized_key]:"'".$empty_value."'";
1265 $labels_normalized[$key_ak][$normalized_key]=isset( $labels[$key_ak][$normalized_key])? $labels[$key_ak][$normalized_key]:"''";
1266 $ylabel_normalized[$key_ak][$normalized_key]=isset( $ylabel[$key_ak][$normalized_key])? $ylabel[$key_ak][$normalized_key]:"";
1267 }
1268 }
1269 return [$values_normalized,$labels_normalized,$ylabel_normalized];
1270 }
1271
1272
1273 add_filter('guaven_sqlcharts_table_empty_cell',function($str){return '<td>#</td>';});
1274 add_filter('guaven_sqlcharts_table_empty_value',function($str){return 'N/A';});
1275