PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.36
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.36
3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 2.44 All 141 releases
photonic / Admin / Options_Manager.php

Options_Manager.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.36, at Admin/Options_Manager.php

851 lines 30.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Photonic_Plugin\Admin;
4
5 if (!current_user_can('edit_theme_options')) {
6 wp_die(esc_html__('You are not authorized to use this capability.', 'photonic'));
7 }
8
9 use Photonic_Plugin\Core\Photonic;
10
11 use Photonic_Plugin\Options\Defaults;
12 use Photonic_Plugin\Options\DeviantArt;
13 use Photonic_Plugin\Options\Flickr;
14 use Photonic_Plugin\Options\Generic;
15 use Photonic_Plugin\Options\Google;
16 use Photonic_Plugin\Options\Instagram;
17 use Photonic_Plugin\Options\Lightbox;
18 use Photonic_Plugin\Options\SmugMug;
19 use Photonic_Plugin\Options\Zenfolio;
20
21 require_once 'Admin_Page.php';
22
23 class Options_Manager extends Admin_Page {
24 private string $tab;
25 private array $tab_options;
26 private array $reverse_options;
27 private array $option_defaults;
28 private array $allowed_values;
29 private $hidden_options;
30 private array $nested_options;
31 private int $displayed_sections;
32 private $option_structure;
33 private string $previous_displayed_section;
34 private string $file;
35 private $tab_name;
36 private $core;
37
38 /**
39 * Options_Manager constructor.
40 *
41 * @param $file
42 * @param Photonic $core
43 */
44 public function __construct($file, $core) {
45 global $photonic_setup_options;
46 $options_page_array = [
47 'Generic.php' => Generic::get_instance()->get_options(),
48 'Flickr.php' => Flickr::get_instance()->get_options(),
49 // 'Google.php' => Google::get_instance()->get_options(),
50 'SmugMug.php' => SmugMug::get_instance()->get_options(),
51 'Zenfolio.php' => Zenfolio::get_instance()->get_options(),
52 // 'Instagram.php' => Instagram::get_instance()->get_options(),
53 'DeviantArt.php' => DeviantArt::get_instance()->get_options(),
54 'Lightbox.php' => Lightbox::get_instance()->get_options(),
55 ];
56
57 $tab_name_array = [
58 'Generic.php' => 'Generic Options',
59 'Flickr.php' => 'Flickr Options',
60 // 'Google.php' => 'Google Photos Options',
61 'SmugMug.php' => 'SmugMug Options',
62 'Zenfolio.php' => 'Zenfolio Options',
63 // 'Instagram.php' => 'Instagram Options',
64 'DeviantArt.php' => 'DeviantArt Options',
65 'Lightbox.php' => 'Lightbox Options',
66 ];
67
68 $this->core = $core;
69 $this->file = $file;
70 $this->tab = 'Generic.php';
71 if (isset($_REQUEST['tab']) && array_key_exists($_REQUEST['tab'], $tab_name_array)) { // phpcs:ignore WordPress.Security.NonceVerification
72 $this->tab = sanitize_text_field($_REQUEST['tab']); // phpcs:ignore WordPress.Security.NonceVerification
73 }
74
75 $this->tab_options = $options_page_array[$this->tab];
76 $this->tab_name = $tab_name_array[$this->tab];
77 $this->reverse_options = [];
78 $this->nested_options = [];
79 $this->displayed_sections = 0;
80 $this->option_structure = $this->get_option_structure();
81 $this->option_defaults = [];
82 $this->allowed_values = [];
83
84 $all_options = get_option('photonic_options');
85 if (!isset($all_options)) {
86 $this->hidden_options = [];
87 }
88 else {
89 $this->hidden_options = $all_options;
90 }
91
92 foreach ($this->tab_options as $option) {
93 if (isset($option['id'])) {
94 if (isset($this->hidden_options[$option['id']])) {
95 unset($this->hidden_options[$option['id']]);
96 }
97 }
98 }
99
100 $defaults = Defaults::get_options();
101 foreach ($photonic_setup_options as $option) {
102 if (isset($option['category']) && !isset($this->nested_options[$option['category']])) {
103 $this->nested_options[$option['category']] = [];
104 }
105
106 if (isset($option['id'])) {
107 $this->reverse_options[$option['id']] = $option['type'];
108
109 $this->option_defaults[$option['id']] = $defaults[$option['id']];
110 $option['std'] = $defaults[$option['id']];
111
112 if (isset($option['options'])) {
113 if ('radio-group' !== $option['type']) {
114 $this->allowed_values[$option['id']] = $option['options'];
115 }
116 else {
117 $this->allowed_values[$option['id']] = [];
118 foreach ($option['options'] as $radio_group) {
119 $this->allowed_values[$option['id']] = array_merge($this->allowed_values[$option['id']], $radio_group['options']);
120 }
121 }
122 }
123
124 if (isset($option['grouping'])) {
125 if (!isset($this->nested_options[$option['grouping']])) {
126 $this->nested_options[$option['grouping']] = [];
127 }
128 $this->nested_options[$option['grouping']][] = $option['id'];
129 }
130 }
131 }
132 }
133
134 public function render_content() {
135 $saved_options = get_option('photonic_options');
136 if (!empty($saved_options) && current_user_can('edit_theme_options')) {
137 $generated_css = $this->core->generate_css(false);
138 update_option('photonic_css', $generated_css);
139 if (!empty($saved_options['css_in_file'])) {
140 $this->save_css_to_file($generated_css);
141 }
142 }
143 ?>
144 <div class="photonic-tabbed-options">
145 <div class="photonic-header-nav">
146 <div class="photonic-header-nav-top fix">
147 </div>
148 <div class="photonic-options-header-bar fix">
149 <h2 class='nav-tab-wrapper'>
150 <a class='nav-tab <?php echo ('Generic.php' === $this->tab) ? 'nav-tab-active' : ''; ?>'
151 id='photonic-options-generic' href='?page=photonic-options-manager&amp;tab=Generic.php'><span
152 class="icon">&nbsp;</span> Generic Options</a>
153 <a class='nav-tab <?php echo ('Flickr.php' === $this->tab) ? 'nav-tab-active' : ''; ?>'
154 id='photonic-options-flickr' href='?page=photonic-options-manager&amp;tab=Flickr.php'><span
155 class="icon">&nbsp;</span> Flickr</a>
156 <a class='nav-tab <?php echo ('SmugMug.php' === $this->tab) ? 'nav-tab-active' : ''; ?>'
157 id='photonic-options-smugmug' href='?page=photonic-options-manager&amp;tab=SmugMug.php'><span
158 class="icon">&nbsp;</span> SmugMug</a>
159 <a class='nav-tab <?php echo ('Zenfolio.php' === $this->tab) ? 'nav-tab-active' : ''; ?>'
160 id='photonic-options-zenfolio'
161 href='?page=photonic-options-manager&amp;tab=Zenfolio.php'><span class="icon">&nbsp;</span>
162 Zenfolio</a>
163 <!-- <a class='nav-tab <?php /*echo ('DeviantArt.php' === $this->tab) ? 'nav-tab-active' : ''; */ ?>'
164 id='photonic-options-deviantart'
165 href='?page=photonic-options-manager&amp;tab=DeviantArt.php'><span class="icon">&nbsp;</span>
166 DeviantArt</a>
167 --> <a class='nav-tab <?php echo ('Lightbox.php' === $this->tab) ? 'nav-tab-active' : ''; ?>'
168 id='photonic-options-lightbox'
169 href='?page=photonic-options-manager&amp;tab=Lightbox.php'><span class="icon">&nbsp;</span>
170 Lightboxes</a>
171 </h2>
172 </div>
173 </div>
174 <?php
175 $option_structure = $this->get_option_structure();
176 $group = substr($this->tab, 0, stripos($this->tab, '.'));
177
178 echo "<div class='photonic-options photonic-options-" . esc_attr($group) . "' id='photonic-options'>";
179 echo "<ul class='photonic-section-tabs'>";
180 foreach ($option_structure as $l1_slug => $l1) {
181 echo wp_kses_post("<li><a href='#$l1_slug'>" . $l1['name'] . "</a></li>\n");
182 }
183 echo "</ul>";
184
185 do_settings_sections($this->file);
186
187 $last_option = end($option_structure);
188 $last_slug = key($option_structure);
189 $this->show_buttons($last_slug, $last_option);
190
191 echo "</form>\n";
192 echo "</div><!-- /photonic-options-panel -->\n";
193
194 echo "</div><!-- /#photonic-options -->\n";
195 ?>
196 </div><!-- /#photonic-tabbed-options -->
197 <?php
198 }
199
200 public function show_buttons($slug, $option) {
201 if (!isset($option['buttons']) || ('no-buttons' !== $option['buttons'] && 'special-buttons' !== $option['buttons'])) {
202 echo "<div class=\"photonic-button-bar photonic-button-bar-" . esc_attr($slug) . "\">\n";
203 echo "<input name=\"photonic_options[submit-" . esc_attr($slug) . "]\" type='submit' value=\"Save page &ldquo;" . esc_attr($option['name']) . "&rdquo;\" class=\"button button-primary\" />\n";
204 echo "<input name=\"photonic_options[submit-" . esc_attr($slug) . "]\" type='submit' value=\"Reset page &ldquo;" . esc_attr($option['name']) . "&rdquo;\" class=\"button\" />\n";
205 echo "<input name=\"photonic_options[submit-" . esc_attr($slug) . "]\" type='submit' value=\"Delete all options\" class=\"button\" />\n";
206 echo "</div><!-- photonic-button-bar -->\n";
207 }
208 }
209
210 public function init() {
211 foreach ($this->option_structure as $slug => $option) {
212 if (!in_array($slug, Defaults::get_options_pages(), true)) {
213 wp_die(esc_html("Invalid option section: $slug"));
214 }
215 // Since we are not including this file on all admin pages due to the size and associated load, register_setting cannot be done here.
216 // It is instead done via Admin_Menu, which is loaded for all admin pages.
217 // register_setting('photonic_options-'.$slug, 'photonic_options', [&$this, 'validate_options']);
218
219 add_settings_section($slug, "", [&$this, "create_settings_section"], $this->file);
220 $this->add_settings_fields($this->file);
221 }
222 }
223
224 public function validate_options($options): array {
225 foreach ($options as $option => $option_value) {
226 if (isset($this->reverse_options[$option])) {
227 // Sanitize options
228 switch ($this->reverse_options[$option]) {
229 // For all text type of options make sure that the eventual text is properly escaped.
230 case "text":
231 case "background":
232 case "border":
233 $options[$option] = sanitize_text_field($option_value);
234 break;
235
236 case "textarea":
237 $options[$option] = sanitize_textarea_field($option_value);
238 break;
239
240 case "select":
241 case "radio":
242 case "radio-group":
243 if (isset($this->allowed_values[$option])) {
244 if (!array_key_exists($option_value, $this->allowed_values[$option])) {
245 $options[$option] = $this->option_defaults[$option];
246 }
247 }
248 break;
249
250 case "multi-select":
251 $selections = explode(',', $option_value);
252 $final_selections = [];
253 foreach ($selections as $selection) {
254 if (array_key_exists($selection, $this->allowed_values[$option])) {
255 $final_selections[] = $selection;
256 }
257 }
258 $options[$option] = implode(',', $final_selections);
259 break;
260
261 case "checkbox":
262 if (!in_array($option_value, ['on', 'off', 'true', 'false'], true) && isset($this->option_defaults[$option])) {
263 $options[$option] = $this->option_defaults[$option];
264 }
265 break;
266 }
267 }
268 }
269
270 /*
271 * The Settings API does an update_option($option, $value), overwriting the $photonic_options array with the values on THIS page
272 * This is problematic because all options are stored in a single array, but are displayed on different options pages.
273 * Hence the overwrite kills the options from the other pages.
274 * So this is a workaround to include the options from other pages as hidden fields on this page, so that the array gets properly updated.
275 * The alternative would be to separate options for each page, but that would cause a migration headache for current users.
276 */
277 $current_options = array_keys($options);
278 if (isset($this->hidden_options) && is_array($this->hidden_options)) {
279 foreach ($this->hidden_options as $hidden_option => $hidden_value) {
280 if (strlen($hidden_option) >= 7 && ('submit-' === substr($hidden_option, 0, 7) || 'reset-' === substr($hidden_option, 0, 6)) || in_array($hidden_option, $current_options, true)) {
281 continue;
282 }
283 $options[$hidden_option] = esc_attr($hidden_value);
284 }
285 }
286
287 foreach ($this->nested_options as $section => $children) {
288 if (isset($options['submit-' . $section])) {
289 $options['last-set-section'] = $section;
290 if ('Save page' === substr($options['submit-' . $section], 0, 9) || 'Reset page' === substr($options['submit-' . $section], 0, 10)) {
291 global $photonic_options;
292 foreach ($this->nested_options as $inner_section => $inner_children) {
293 if ($section !== $inner_section) {
294 foreach ($inner_children as $inner_child) {
295 if (isset($photonic_options[$inner_child]) && !in_array($inner_child, $current_options, true)) {
296 $options[$inner_child] = $photonic_options[$inner_child];
297 }
298 }
299 }
300 }
301
302 if ('Reset page' === substr($options['submit-' . $section], 0, 10)) {
303 unset($options['submit-' . $section]);
304 // This is a reset for an individual section. So we will unset the child fields.
305 foreach ($children as $child) {
306 unset($options[$child]);
307 }
308 }
309 unset($options['submit-' . $section]);
310 }
311 elseif ('Delete' === substr($options['submit-' . $section], 0, 6)) {
312 return [];
313 }
314 break;
315 }
316 }
317 return $options;
318 }
319
320 public function get_option_structure() {
321 if (isset($this->option_structure)) {
322 return $this->option_structure;
323 }
324 $options = $this->tab_options;
325 $option_structure = [];
326 foreach ($options as $value) {
327 switch ($value['type']) {
328 case "title":
329 case "section":
330 $option_structure[$value['category']] = [];
331 $option_structure[$value['category']]['slug'] = $value['category'];
332 $option_structure[$value['category']]['name'] = $value['name'];
333 $option_structure[$value['category']]['children'] = [];
334
335 if (isset($value['help'])) {
336 $option_structure[$value['category']]['help'] = $value['help'];
337 }
338 if (isset($value['buttons'])) {
339 $option_structure[$value['category']]['buttons'] = $value['buttons'];
340 }
341 if (isset($value['preface'])) {
342 $option_structure[$value['category']]['preface'] = $value['preface'];
343 }
344 break;
345
346 default:
347 if (isset($value['id'])) {
348 $option_structure[$value['grouping']]['children'][$value['id']] = $value['name'];
349 }
350 }
351 }
352 return $option_structure;
353 }
354
355 private function add_settings_fields($page) {
356 $ctr = 0;
357 foreach ($this->tab_options as $value) {
358 $ctr++;
359 switch ($value['type']) {
360 case "blurb":
361 add_settings_field($value['grouping'] . '-' . $ctr, $value['name'], [&$this, "create_section_for_blurb"], $page, $value['grouping'], $value);
362 break;
363
364 case "text":
365 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_text"], $page, $value['grouping'], $value);
366 break;
367
368 case "textarea":
369 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_textarea"], $page, $value['grouping'], $value);
370 break;
371
372 case "select":
373 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_select"], $page, $value['grouping'], $value);
374 break;
375
376 case "multi-select":
377 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_multi_select"], $page, $value['grouping'], $value);
378 break;
379
380 case "radio":
381 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_radio"], $page, $value['grouping'], $value);
382 break;
383
384 case "radio-group":
385 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_radio_group"], $page, $value['grouping'], $value);
386 break;
387
388 case "checkbox":
389 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_checkbox"], $page, $value['grouping'], $value);
390 break;
391
392 case "background":
393 add_settings_field($value['id'], $value['name'], [&$this, "create_section_for_background"], $page, $value['grouping'], $value);
394 break;
395 }
396 }
397 }
398
399 public function create_section_for_radio($value) {
400 $defaults = Defaults::get_options();
401 $this->create_opening_tag($value);
402 foreach ($value['options'] as $option_value => $option_text) {
403 $this->create_individual_radio_item($value, $option_value, $option_text, $defaults);
404 }
405 $this->create_closing_tag();
406 }
407
408 public function create_section_for_radio_group($value) {
409 $defaults = Defaults::get_options();
410 $this->create_opening_tag($value);
411
412 foreach ($value['options'] as $radio_group) {
413 if (!empty($radio_group['header'])) {
414 echo "<h4>" . wp_kses_post($radio_group['header']) . "</h4>\n";
415 }
416 if (!empty($radio_group['description'])) {
417 echo wp_kses_post($radio_group['description']) . "\n";
418 }
419 foreach ($radio_group['options'] as $option_value => $option_text) {
420 $this->create_individual_radio_item($value, $option_value, $option_text, $defaults);
421 }
422 }
423 $this->create_closing_tag();
424 }
425
426 private function create_individual_radio_item($value, $option_value, $option_text, $defaults) {
427 global $photonic_options;
428 $replacements = Defaults::get_migrated_options();
429
430 if (isset($photonic_options[$value['id']])) {
431 $check_value = (isset($replacements[$value['id']]) && isset($replacements[$value['id']][$photonic_options[$value['id']]])) ? $replacements[$value['id']][$photonic_options[$value['id']]] : $photonic_options[$value['id']];
432 $checked = checked($check_value, $option_value, false);
433 }
434 else {
435 $checked = checked($defaults[$value['id']], $option_value, false);
436 }
437 echo '<div class="photonic-radio"><label><input type="radio" name="photonic_options[' . esc_attr($value['id']) . ']" value="' . esc_attr($option_value) . '" ' . esc_attr($checked) . "/>" . wp_kses_post($option_text) . "</label></div>\n";
438 }
439
440 public function create_section_for_text($value) {
441 global $photonic_options;
442 $defaults = Defaults::get_options();
443 $this->create_opening_tag($value);
444 if (!isset($photonic_options[$value['id']])) {
445 $text = $defaults[$value['id']];
446 }
447 else {
448 $text = $photonic_options[$value['id']];
449 $text = stripslashes($text);
450 }
451
452 echo '<input type="text" name="photonic_options[' . esc_attr($value['id']) . ']" value="' . esc_attr($text) . '" />' . "\n";
453 if (isset($value['hint'])) {
454 echo "<em> &laquo; " . wp_kses_post($value['hint']) . "<br /></em>\n";
455 }
456 $this->create_closing_tag();
457 }
458
459 public function create_section_for_textarea($value) {
460 global $photonic_options;
461 $defaults = Defaults::get_options();
462 $this->create_opening_tag($value);
463 echo '<textarea name="photonic_options[' . esc_attr($value['id']) . ']" cols="" rows="">' . "\n";
464 if (isset($photonic_options[$value['id']]) && "" !== $photonic_options[$value['id']]) {
465 $text = stripslashes($photonic_options[$value['id']]);
466 }
467 else {
468 $text = $defaults[$value['id']];
469 }
470 echo esc_attr($text);
471 echo '</textarea>';
472 if (isset($value['hint'])) {
473 echo "<em> &laquo; " . wp_kses_post($value['hint']) . "<br /></em>\n";
474 }
475 $this->create_closing_tag();
476 }
477
478 public function create_section_for_select($value) {
479 global $photonic_options;
480 $defaults = Defaults::get_options();
481 $replacements = Defaults::get_migrated_options();
482
483 $this->create_opening_tag($value);
484 echo '<select name="photonic_options[' . esc_attr($value['id']) . ']">' . "\n";
485 foreach ($value['options'] as $option_value => $option_text) {
486 echo "<option ";
487 if (isset($photonic_options[$value['id']])) {
488 $check_value = (isset($replacements[$value['id']]) && isset($replacements[$value['id']][$photonic_options[$value['id']]])) ? $replacements[$value['id']][$photonic_options[$value['id']]] : $photonic_options[$value['id']];
489 selected($check_value, $option_value);
490 }
491 else {
492 selected($defaults[$value['id']], $option_value);
493 }
494 echo " value='" . esc_attr($option_value) . "' >" . esc_attr($option_text) . "</option>\n";
495 }
496 echo "</select>\n";
497 $this->create_closing_tag();
498 }
499
500 public function create_section_for_multi_select($value) {
501 global $photonic_options;
502 $defaults = Defaults::get_options();
503 $this->create_opening_tag($value);
504 echo '<div class="photonic-checklist">' . "\n";
505 echo '<ul class="photonic-checklist" id="' . esc_attr($value['id']) . '-chk" >' . "\n";
506 if (isset($defaults[$value['id']])) {
507 $consolidated_value = $defaults[$value['id']];
508 }
509 if (isset($photonic_options[$value['id']])) {
510 $consolidated_value = $photonic_options[$value['id']];
511 }
512 if (!isset($consolidated_value)) {
513 $consolidated_value = "";
514 }
515 $consolidated_value = trim($consolidated_value);
516 $exploded = [];
517 if ('' !== $consolidated_value) {
518 $exploded = explode(',', $consolidated_value);
519 }
520
521 foreach ($value['options'] as $option_value => $option_list) {
522 $checked = " ";
523 if ($consolidated_value) {
524 foreach ($exploded as $checked_value) {
525 $checked = checked($checked_value, $option_value, false);
526 if ('' !== trim($checked)) {
527 break;
528 }
529 }
530 }
531 echo "<li>\n";
532 $depth = 0;
533 if (isset($option_list['depth'])) {
534 $depth = $option_list['depth'];
535 }
536 echo '<label><input type="checkbox" name="' . esc_attr($value['id']) . "_" . esc_attr($option_value) . '" value="true" ' . esc_attr($checked) . ' class="depth-' . esc_attr($depth + 1) . ' photonic-options-checkbox-' . esc_attr($value['id']) . '" data-photonic-selection-for="' . esc_attr($value['id']) . '" data-photonic-value="' . esc_attr($option_value) . '" />' .
537 wp_kses_post($option_list['title']) . "</label>\n";
538 echo "</li>\n";
539 }
540 echo "</ul>\n";
541
542 if (isset($photonic_options[$value['id']])) {
543 $set_value = $photonic_options[$value['id']];
544 }
545 elseif (isset($defaults[$value['id']])) {
546 $set_value = $defaults[$value['id']];
547 }
548 else {
549 $set_value = "";
550 }
551 echo '<input type="hidden" name="photonic_options[' . esc_attr($value['id']) . ']" id="' . esc_attr($value['id']) . '" value="' . esc_attr($set_value) . '"/>' . "\n";
552 echo "</div>\n";
553 $this->create_closing_tag();
554 }
555
556 public function create_settings_section($section) {
557 $option_structure = $this->option_structure;
558 if (0 !== $this->displayed_sections) {
559 $this->show_buttons($this->previous_displayed_section, $option_structure[$this->previous_displayed_section]);
560 echo "</form>\n";
561 echo "</div><!-- /photonic-options-panel -->\n";
562 }
563
564 echo "<div id='" . esc_attr($section['id']) . "' class='photonic-options-panel'> \n";
565 echo "<form method=\"post\" action=\"options.php\" id=\"photonic-options-form-" . esc_attr($section['id']) . "\" class='photonic-options-form'>\n";
566 if (!empty($option_structure[$section['id']]['preface'])) {
567 echo wp_kses_post($option_structure[$section['id']]['preface']);
568 }
569 echo '<h3>' . wp_kses_post($option_structure[$section['id']]['name']) . "</h3>\n";
570
571 /*
572 * We store all options in one array, but display them across multiple pages. Hence we need the following hack.
573 * We are registering the same setting across multiple pages, hence we need to pass the "page" parameter to options.php.
574 * Otherwise options.php returns an error saying "Options page not found"
575 */
576 echo "<input type='hidden' name='page' value='" . esc_attr(sanitize_text_field($_REQUEST['page'] ?? '')) . "' />\n"; // phpcs:ignore WordPress.Security.NonceVerification
577 if (!isset($_REQUEST['tab'])) { // phpcs:ignore WordPress.Security.NonceVerification
578 $tab = 'Generic.php';
579 }
580 else {
581 $tab = sanitize_text_field($_REQUEST['tab']); // phpcs:ignore WordPress.Security.NonceVerification
582 }
583 echo "<input type='hidden' name='tab' value='" . esc_attr($tab) . "' />\n";
584
585 settings_fields("photonic_options-{$section['id']}");
586 $this->displayed_sections++;
587 $this->previous_displayed_section = $section['id'];
588 }
589
590 public function create_section_for_blurb($value) {
591 $this->create_opening_tag($value);
592 $this->create_closing_tag();
593 }
594
595 /**
596 * Renders an option whose type is "checkbox". Invoked by add_settings_field.
597 *
598 * @param $value
599 * @return void
600 */
601 public function create_section_for_checkbox($value) {
602 global $photonic_options;
603 $checked = '';
604 if (isset($photonic_options[$value['id']])) {
605 $checked = checked(esc_attr($photonic_options[$value['id']]), 'on', false);
606 }
607 $this->create_opening_tag($value);
608 echo '<label><input type="checkbox" name="photonic_options[' . esc_attr($value['id']) . ']" ' . esc_attr($checked) . "/>" . wp_kses_post($value['desc']) . "</label>\n";
609 $this->create_closing_tag();
610 }
611
612 /**
613 * Renders an option whose type is "background". Invoked by add_settings_field.
614 *
615 * @param $value
616 * @return void
617 */
618 public function create_section_for_background($value) {
619 global $photonic_options;
620 $defaults = Defaults::get_options();
621
622 $this->create_opening_tag($value);
623 $original = $defaults[$value['id']];
624 if (!isset($photonic_options[$value['id']])) {
625 $default = $defaults[$value['id']];
626 $default_txt = "";
627 foreach ($defaults[$value['id']] as $opt => $opt_val) {
628 $default_txt .= $opt . "=" . $opt_val . ";";
629 }
630 }
631 else {
632 $default_txt = $photonic_options[$value['id']];
633 $default = $default_txt;
634 $vals = explode(";", $default);
635 $default = [];
636 foreach ($vals as $val) {
637 $pair = explode("=", $val);
638 if (isset($pair[0]) && isset($pair[1])) {
639 $default[$pair[0]] = $pair[1];
640 }
641 elseif (isset($pair[0]) && !isset($pair[1])) {
642 $default[$pair[0]] = "";
643 }
644 }
645 }
646 $repeats = [
647 "repeat" => "Repeat horizontally and vertically",
648 "repeat-x" => "Repeat horizontally only",
649 "repeat-y" => "Repeat vertically only",
650 "no-repeat" => "Do not repeat"
651 ];
652
653 $positions = [
654 "top left" => "Top left",
655 "top center" => "Top center",
656 "top right" => "Top right",
657 "center left" => "Center left",
658 "center center" => "Middle of the page",
659 "center right" => "Center right",
660 "bottom left" => "Bottom left",
661 "bottom center" => "Bottom center",
662 "bottom right" => "Bottom right"
663 ];
664
665 foreach ($value['options'] as $option_value => $option_text) {
666 if (isset($photonic_options[$value['id']])) {
667 $checked = checked($photonic_options[$value['id']], $option_value, false);
668 }
669 else {
670 $checked = checked($defaults[$value['id']], $option_value, false);
671 }
672 echo '<div class="photonic-radio"><input type="radio" name="' . esc_attr($value['id']) . '" value="' . esc_attr($option_value) . '" ' . esc_attr($checked) . "/>" . wp_kses_post($option_text) . "</div>\n";
673 }
674 ?>
675 <div class='photonic-background-options'>
676 <table class='opt-sub-table'>
677 <colgroup>
678 <col class='opt-sub-table-cols'/>
679 <col class='opt-sub-table-cols'/>
680 </colgroup>
681 <tr>
682 <td style='vertical-align: top'>
683 <div class="color-picker-group">
684 <strong>Background Color:</strong><br/>
685 <label><input type="radio" name="<?php echo esc_attr($value['id']); ?>-colortype"
686 value="transparent" <?php checked($default['colortype'], 'transparent'); ?> />
687 Transparent / No color</label><br/>
688 <label><input type="radio" name="<?php echo esc_attr($value['id']); ?>-colortype"
689 value="custom" <?php checked($default['colortype'], 'custom'); ?>/>
690 Custom</label>
691 <input type="text" id="<?php echo esc_attr($value['id']); ?>-bgcolor"
692 name="<?php echo esc_attr($value['id']); ?>-bgcolor" value="<?php echo esc_attr($default['color']); ?>"
693 data-photonic-default-color="<?php echo esc_attr($original['color']); ?>" class="color"/><br/>
694 Default: <span> <?php echo esc_attr($original['color']); ?> </span>
695 </div>
696 </td>
697 <td style='vertical-align: top'>
698 <strong>Image URL:</strong><br/>
699 <?php $this->display_upload_field($default['image'], $value['id'] . "-bgimg", $value['id'] . "-bgimg"); ?>
700 </td>
701 </tr>
702
703 <tr>
704 <td style='vertical-align: top'>
705 <label>
706 <strong>Image Position:</strong><br/>
707 <select name="<?php echo esc_attr($value['id']); ?>-position"
708 id="<?php echo esc_attr($value['id']); ?>-position">
709 <?php
710 foreach ($positions as $option_value => $option_text) {
711 echo "<option ";
712 selected($default['position'], $option_value);
713 echo " value='" . esc_attr($option_value) . "' >" . esc_attr($option_text) . "</option>\n";
714 }
715 ?>
716 </select>
717 </label>
718 </td>
719
720 <td style='vertical-align: top'>
721 <label>
722 <strong>Image Repeat:</strong><br/>
723 <select name="<?php echo esc_attr($value['id']); ?>-repeat"
724 id="<?php echo esc_attr($value['id']); ?>-repeat">
725 <?php
726 foreach ($repeats as $option_value => $option_text) {
727 echo "<option ";
728 selected($default['repeat'], $option_value);
729 echo " value='" . esc_attr($option_value) . "' >" . esc_attr($option_text) . "</option>\n";
730 }
731 ?>
732 </select>
733 </label>
734 </td>
735 </tr>
736 <tr>
737 <td style='vertical-align: top' colspan='2'>
738 <div class='slider'>
739 <p>
740 <label>
741 <strong>Layer Transparency (not for IE):</strong>
742 <select id="<?php echo esc_attr($value['id']); ?>-trans"
743 name="<?php echo esc_attr($value['id']); ?>-trans">
744 <?php
745 for ($i = 0; $i <= 100; $i++) {
746 ?>
747 <option <?php echo selected($default['trans'], $i); ?> value="<?php echo esc_attr($i); ?>" ><?php echo esc_html($i); ?></option>
748 <?php
749 }
750 ?>
751 </select>
752 </label>
753 </p>
754 </div>
755 </td>
756 </tr>
757 </table>
758 <input type='hidden' id="<?php echo esc_attr($value['id']); ?>" name="photonic_options[<?php echo esc_attr($value['id']); ?>]"
759 value="<?php echo esc_attr($default_txt); ?>"/>
760 </div>
761 <?php
762 $this->create_closing_tag();
763 }
764
765 /**
766 * Creates the opening markup for each option.
767 *
768 * @param $value
769 * @return void
770 */
771 public function create_opening_tag($value) {
772 echo "<div class='photonic-section fix'>\n";
773 if (isset($value['desc']) && 'checkbox' !== $value['type']) {
774 echo wp_kses_post($value['desc']) . "<br />";
775 }
776 if (isset($value['note'])) {
777 echo "<span class=\"note\">" . wp_kses_post($value['note']) . "</span><br />";
778 }
779 }
780
781 /**
782 * Creates the closing markup for each option.
783 *
784 * @return void
785 */
786 public function create_closing_tag() {
787 echo "</div><!-- photonic-section -->\n";
788 }
789
790 /**
791 * This method displays an upload field and button. This has been separated from the create_section_for_upload method,
792 * because this is used by the create_section_for_background as well.
793 *
794 * @param $upload
795 * @param $id
796 * @param $name
797 * @param null $hint
798 * @return void
799 */
800 private function display_upload_field($upload, $id, $name, $hint = null) {
801 echo '<input type="text" name="' . esc_attr($name) . '" id="' . esc_attr($id) . '" value="' . esc_attr($upload) . '" />' . "\n";
802 if (null !== $hint) {
803 echo "<em> &laquo; " . wp_kses_post($hint) . "<br /></em>\n";
804 }
805 }
806
807 /**
808 * Save generated options to a file. This uses the WP_Filesystem to validate the credentials of the user attempting to save options.
809 *
810 * @param $custom_css
811 * @return bool
812 */
813 public function save_css_to_file($custom_css): bool {
814 if (!isset($_GET['settings-updated'])) { // phpcs:ignore WordPress.Security.NonceVerification
815 return false;
816 }
817
818 $url = wp_nonce_url('admin.php?page=photonic-options-manager');
819 $creds = request_filesystem_credentials($url, '', false, false);
820 if (false === $creds) {
821 return true;
822 }
823
824 if (!WP_Filesystem($creds)) {
825 request_filesystem_credentials($url, '', true, false);
826 return true;
827 }
828
829 /** @var $wp_filesystem \WP_Filesystem_Base */
830 global $wp_filesystem;
831 if (!is_dir(PHOTONIC_UPLOAD_DIR)) {
832 if (!$wp_filesystem->mkdir(PHOTONIC_UPLOAD_DIR)) {
833 echo "<div class='error'><p>Failed to create directory " . esc_attr(PHOTONIC_UPLOAD_DIR) . ". Please check your folder permissions.</p></div>";
834 return false;
835 }
836 }
837
838 $filename = trailingslashit(PHOTONIC_UPLOAD_DIR) . 'custom-styles.css';
839
840 if (empty($custom_css)) {
841 return false;
842 }
843
844 if (!$wp_filesystem->put_contents($filename, $custom_css, FS_CHMOD_FILE)) {
845 echo wp_kses_post("<div class='error'><p>Failed to save file $filename. Please check your folder permissions.</p></div>");
846 return false;
847 }
848 return true;
849 }
850 }
851