PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 2.21
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v2.21
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 / extensions / Photonic_Processor.php

Photonic_Processor.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 2.21, at extensions/Photonic_Processor.php

661 lines 22.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Gallery processor class to be extended by individual processors. This class has an abstract method called <code>get_gallery_images</code>
4 * that has to be defined by each inheriting processor.
5 *
6 * This is also where the OAuth support is implemented. The URLs are defined using abstract functions, while a handful of utility functions are defined.
7 * Most utility functions have been adapted from the OAuth PHP package distributed here: https://code.google.com/p/oauth-php/.
8 *
9 * @package Photonic
10 * @subpackage Extensions
11 */
12
13 abstract class Photonic_Processor {
14 public $library, $thumb_size, $full_size, $api_key, $api_secret, $provider, $nonce, $oauth_timestamp, $signature_parameters, $link_lightbox_title, $layout,
15 $oauth_version, $oauth_done, $show_more_link, $is_server_down, $is_more_required, $login_shown, $login_box_counter, $gallery_index, $bypass_popup, $common_parameters,
16 $doc_links, $password_protected, $token, $token_secret, $show_buy_link, $stack_trace;
17
18 function __construct() {
19 global $photonic_slideshow_library, $photonic_custom_lightbox, $photonic_enable_popup, $photonic_thumbnail_style;
20 if ($photonic_slideshow_library != 'custom') {
21 $this->library = $photonic_slideshow_library;
22 }
23 else {
24 $this->library = $photonic_custom_lightbox;
25 }
26 $this->nonce = Photonic_Processor::nonce();
27 $this->oauth_timestamp = time();
28 $this->oauth_version = '1.0';
29 $this->show_more_link = false;
30 $this->is_server_down = false;
31 $this->is_more_required = true;
32 $this->login_shown = false;
33 $this->login_box_counter = 0;
34 $this->gallery_index = 0;
35 $this->bypass_popup = !isset($photonic_enable_popup) || $photonic_enable_popup === false || $photonic_enable_popup == '' || $photonic_enable_popup == 'off';
36 $this->common_parameters = array(
37 'columns' => 'auto',
38 'layout' => !empty($photonic_thumbnail_style) ? $photonic_thumbnail_style : 'square',
39 'more' => '',
40 'display' => 'in-page',
41 'panel' => '',
42 'filter' => '',
43 'filter_type' => 'include',
44 'fx' => 'slide', // LightSlider effects: fade and slide
45 'timeout' => 4000, // Time between slides in ms
46 'speed' => 1000, // Time for each transition
47 'pause' => true, // Pause on hover
48 'strip-style' => 'thumbs',
49 'controls' => 'show',
50 'popup' => $this->bypass_popup ? 'hide' : 'show',
51
52 'custom_classes' => '',
53 'alignment' => '',
54 );
55
56 $this->doc_links = array();
57 $this->password_protected = esc_html__('This album is password-protected. Please provide a valid password.', 'photonic');
58 $this->show_buy_link = false;
59 $this->stack_trace = array();
60 $this->add_hooks();
61 }
62
63 /**
64 * Main function that fetches the images associated with the shortcode. This is implemented by all sub-classes.
65 *
66 * @abstract
67 * @param array $attr
68 */
69 abstract protected function get_gallery_images($attr = array());
70
71 public function oauth_signature_method() {
72 return 'HMAC-SHA1';
73 }
74
75 /**
76 * Takes a token response from a request token call, then puts it in an appropriate array.
77 *
78 * @param $response
79 * @return array
80 */
81 public function parse_token($response) {
82 return array();
83 }
84
85 public function save_token($token) {
86 $photonic_authentication = get_option('photonic_authentication');
87 if (!isset($photonic_authentication)) {
88 $photonic_authentication = array();
89 }
90 $photonic_authentication[$this->provider] = $token;
91 update_option('photonic_authentication', $photonic_authentication);
92 }
93
94 /**
95 * Generates a nonce for use in signing calls.
96 *
97 * @static
98 * @return string
99 */
100 public static function nonce() {
101 $mt = microtime();
102 $rand = mt_rand();
103 return md5($mt . $rand);
104 }
105
106 /**
107 * Encodes the URL as per RFC3986 specs. This replaces some strings in addition to the ones done by a rawurlencode.
108 * This has been adapted from the OAuth for PHP project.
109 *
110 * @static
111 * @param $input
112 * @return array|mixed|string
113 */
114 public static function urlencode_rfc3986($input) {
115 if (is_array($input)) {
116 return array_map(array('Photonic_Processor', 'urlencode_rfc3986'), $input);
117 }
118 else if (is_scalar($input)) {
119 return str_replace(
120 '+',
121 ' ',
122 str_replace('%7E', '~', rawurlencode($input))
123 );
124 }
125 else {
126 return '';
127 }
128 }
129
130 /**
131 * Takes an array of parameters, then parses it and generates a query string. Prior to generating the query string the parameters are sorted in their natural order.
132 * Without sorting the signatures between this application and the provider might differ.
133 *
134 * @static
135 * @param $params
136 * @return string
137 */
138 public static function build_query($params) {
139 if (!$params) {
140 return '';
141 }
142 $keys = array_map(array('Photonic_Processor', 'urlencode_rfc3986'), array_keys($params));
143 $values = array_map(array('Photonic_Processor', 'urlencode_rfc3986'), array_values($params));
144 $params = array_combine($keys, $values);
145
146 // Sort by keys (natsort)
147 uksort($params, 'strnatcmp');
148 $pairs = array();
149 foreach ($params as $key => $value) {
150 if (is_array($value)) {
151 natsort($value);
152 foreach ($value as $v2) {
153 $pairs[] = ($v2 == '') ? "$key=0" : "$key=$v2";
154 }
155 }
156 else {
157 $pairs[] = ($value == '') ? "$key=0" : "$key=$value";
158 }
159 }
160
161 $string = implode('&', $pairs);
162 return $string;
163 }
164
165 /**
166 * Takes a string of parameters in an HTML encoded string, then returns an array of name-value pairs, with the parameter
167 * name and the associated value.
168 *
169 * @static
170 * @param $input
171 * @return array
172 */
173 public static function parse_parameters($input) {
174 if (!isset($input) || !$input) return array();
175
176 $pairs = explode('&', $input);
177
178 $parsed_parameters = array();
179 foreach ($pairs as $pair) {
180 $split = explode('=', $pair, 2);
181 $parameter = urldecode($split[0]);
182 $value = isset($split[1]) ? urldecode($split[1]) : '';
183
184 if (isset($parsed_parameters[$parameter])) {
185 // We have already recieved parameter(s) with this name, so add to the list
186 // of parameters with this name
187 if (is_scalar($parsed_parameters[$parameter])) {
188 // This is the first duplicate, so transform scalar (string) into an array
189 // so we can add the duplicates
190 $parsed_parameters[$parameter] = array($parsed_parameters[$parameter]);
191 }
192
193 $parsed_parameters[$parameter][] = $value;
194 }
195 else {
196 $parsed_parameters[$parameter] = $value;
197 }
198 }
199 return $parsed_parameters;
200 }
201
202 /**
203 * If authentication is enabled for this processor and the user has not authenticated this site to access his profile,
204 * this shows a login box.
205 *
206 * @param $post_id
207 * @return string
208 */
209 public function get_login_box($post_id = '') {
210 $login_box_option = 'photonic_'.$this->provider.'_login_box';
211 $login_button_option = 'photonic_'.$this->provider.'_login_button';
212 global ${$login_box_option}, ${$login_button_option};
213 $login_box = ${$login_box_option};
214 $login_button = ${$login_button_option};
215 $this->login_box_counter++;
216 $ret = '<div id="photonic-login-box-'.$this->provider.'-'.$this->login_box_counter.'" class="photonic-login-box photonic-login-box-'.$this->provider.'">'."\n";
217 if ($this->is_server_down) {
218 $ret .= esc_html__("The authentication server is down. Please try after some time.", 'photonic');
219 }
220 else {
221 $ret .= "\t".wp_specialchars_decode($login_box, ENT_QUOTES)."\n";
222 if (trim($login_button) == '') {
223 $login_button = 'Login';
224 }
225 else {
226 $login_button = wp_specialchars_decode($login_button, ENT_QUOTES);
227 }
228
229 if (!empty($post_id)) {
230 $rel = "rel='auth-button-single-$post_id'";
231 }
232 else {
233 $rel = '';
234 }
235 $ret .= "\t<p class='photonic-auth-button'>\n\t\t<a href='#' class='auth-button auth-button-{$this->provider}' $rel>".$login_button."</a>\n\t</p>\n";
236 }
237 $ret .= "</div><!-- photonic-login-box -->\n";
238 return $ret;
239 }
240
241 function more_link_button($link_to = '') {
242 global $photonic_archive_link_more;
243 if (empty($photonic_archive_link_more) && $this->is_more_required) {
244 return "<div class='photonic-more-link-container'><a href='$link_to' class='photonic-more-button more-button-{$this->provider}'>See the rest</a></div>";
245 }
246 $this->is_more_required = true;
247 return '';
248 }
249
250 /**
251 * Prints the header for a section. Typically used for albums / photosets / groups, where some generic information about the album / photoset / group is available.
252 * The <code>$options</code> array accepts the following prarameters:
253 * - string type Indicates what type of object is being displayed like gallery / photoset / album etc. This is added to the CSS class.
254 * - array $hidden Contains the elements that should be hidden from the header display.
255 * - array $counters Contains counts of the object that the header represents. In most cases this has just one value. Zenfolio objects have multiple values.
256 * - string $link Should clicking on the thumbnail / title take you anywhere?
257 * - string $display Indicates if this is on the page or in a popup
258 * - bool $iterate_level_3 If this is a level 3 header, this field indicates whether an expansion icon should be shown. This is to improve performance for Flickr collections.
259 * - string $provider What is the source of the data?
260 *
261 * @param array $header The header object, which contains the title, thumbnail source URL and the link where clicking on the thumb will take you
262 * @param array $options The options to display this header. Options contain the listed internal fields fields
263 * @return string
264 */
265 function process_object_header($header, $options = array()) {
266 $type = empty($options['type']) ? 'group' : $options['type'];
267 $hidden = isset($options['hidden']) && is_array($options['hidden']) ? $options['hidden'] : array();
268 $counters = isset($options['counters']) && is_array($options['counters']) ? $options['counters'] : array();
269 $link = !isset($options['link']) ? true : $options['link'];
270 $display = empty($options['display']) ? 'in-page' : $options['display'];
271 $iterate_level_3 = !isset($options['iterate_level_3']) ? true : $options['iterate_level_3'];
272
273 if ($this->bypass_popup && $display != 'in-page') {
274 return '';
275 }
276 $ret = '';
277 if (!empty($header['title'])) {
278 global $photonic_external_links_in_new_tab;
279 $title = esc_attr($header['title']);
280 if (!empty($photonic_external_links_in_new_tab)) {
281 $target = ' target="_blank" ';
282 }
283 else {
284 $target = '';
285 }
286
287 $anchor = '';
288 if (!empty($header['thumb_url'])) {
289 $image = '<img src="'.esc_url($header['thumb_url']).'" alt="'.$title.'" />';
290
291 if ($link) {
292 $anchor = "<a href='".esc_url($header['link_url'])."' class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb' title='".$title."' $target>".$image."</a>";
293 }
294 else {
295 $anchor = "<div class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb'>$image</div>";
296 }
297 }
298
299 if (empty($hidden['thumbnail']) || empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
300 $popup_header_class = '';
301 if ($display == 'popup') {
302 $popup_header_class = 'photonic-panel-header';
303 }
304 $ret .= "<div class='photonic-object-header photonic-{$this->provider}-$type $popup_header_class'>";
305
306 if (empty($hidden['thumbnail'])) {
307 $ret .= $anchor;
308 }
309 if (empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
310 $ret .= "<div class='photonic-header-details photonic-$type-details'>";
311 if (empty($hidden['title']) || empty($iterate_level_3)) {
312 $provider = $this->provider;
313 $expand = empty($iterate_level_3) ? '<a href="#" title="'.esc_attr__('Show', 'photonic').'" class="photonic-level-3-expand photonic-level-3-expand-plus" data-photonic-level-3="'.$provider.'-'.$type.'-'.$header['id'].'" data-photonic-layout="'.$options['layout'].'">&nbsp;</a>' : '';
314
315 if ($link) {
316 $ret .= "<div class='photonic-header-title photonic-$type-title'><a href='".esc_url($header['link_url'])."' $target>".$title.'</a>'.$expand.'</div>';
317 }
318 else {
319 $ret .= "<div class='photonic-header-title photonic-$type-title'>".$title.$expand.'</div>';
320 }
321 }
322 if (empty($hidden['counter'])) {
323 $counter_texts = array();
324 if (!empty($counters['groups'])) {
325 $counter_texts[] = esc_html(sprintf(_n('%s group', '%s groups', $counters['groups'], 'photonic'), $counters['groups']));
326 }
327 if (!empty($counters['sets'])) {
328 $counter_texts[] = esc_html(sprintf(_n('%s set', '%s sets', $counters['sets'], 'photonic'), $counters['sets']));
329 }
330 if (!empty($counters['photos'])) {
331 $counter_texts[] = esc_html(sprintf(_n('%s photo', '%s photos', $counters['photos'], 'photonic'), $counters['photos']));
332 }
333 if (!empty($counters['videos'])) {
334 $counter_texts[] = esc_html(sprintf(_n('%s video', '%s videos', $counters['videos'], 'photonic'), $counters['videos']));
335 }
336
337 apply_filters('photonic_modify_counter_texts', $counter_texts, $counters);
338
339 if (!empty($counter_texts)) {
340 $ret .= "<span class='photonic-header-info photonic-$type-photos'>".implode(', ', $counter_texts).'</span>';
341 }
342 }
343
344 $ret .= "</div><!-- .photonic-$type-details -->";
345 }
346 $ret .= "</div>";
347 }
348 }
349
350 return $ret;
351 }
352
353 /**
354 * Generates the markup for a single photo.
355 *
356 * @param $provider string Name of the photo provider. A CSS class is created in the header, photonic-single-<code>$provider</code>-photo-header
357 * @param $data array Pertinent pieces of information about the photo - the source (src), the photo page (href), title and caption
358 * @return string
359 */
360 function generate_single_photo_markup($provider, $data) {
361 $ret = '';
362 $photo = array_merge(
363 array('src' => '', 'href' => '', 'title' => '', 'caption' => ''),
364 $data
365 );
366
367 if (empty($photo['src'])) {
368 return $ret;
369 }
370
371 global $photonic_external_links_in_new_tab;
372 if (!empty($photo['title'])) {
373 $ret .= "\t".'<h3 class="photonic-single-photo-header photonic-single-'.$provider.'-photo-header">'.$photo['title']."</h3>\n";
374 }
375
376 $img = '<img src="'.esc_url($photo['src']).'" alt="'.esc_attr(empty($photo['caption']) ? $photo['title'] : $photo['caption']).'" />';
377 if (!empty($photo['href'])) {
378 $img = '<a href="'.esc_url($photo['href']).'" title="'.esc_attr(empty($photo['caption']) ? $photo['title'] : $photo['caption']).'" '.
379 (!empty($photonic_external_links_in_new_tab) ? ' target="_blank" ' : '').'>'.$img.'</a>';
380 }
381
382 if (!empty($photo['caption'])) {
383 $ret .= "\t".'<div class="wp-caption">'."\n\t\t".$img."\n\t\t".'<div class="wp-caption-text">'.$photo['caption']."</div>\n\t</div><!-- .wp-caption -->\n";
384 }
385 else {
386 $ret .= $img;
387 }
388
389 return $ret;
390 }
391
392 /**
393 * Generates the HTML for the lowest level gallery, i.e. the photos. This is used for both, in-page and popup displays.
394 * This calls an individual layout generator for rendering the gallery.
395 * The code for the random layouts is handled in JS, but just the HTML markers for it are provided here.
396 *
397 * @param $photos
398 * @param array $options
399 * @param $short_code
400 * @return string
401 */
402 function display_level_1_gallery($photos, $options, $short_code) {
403 $layout = !empty($short_code['layout']) ? $short_code['layout'] : 'square';
404 $layout_manager = $this->get_layout_manager($layout);
405 $ret = $layout_manager->generate_level_1_gallery($photos, $options, $short_code, $this);
406 return $ret;
407 }
408
409 function display_level_2_gallery($objects, $options, $short_code) {
410 $layout = !isset($options['layout']) ? 'square' : $options['layout'];
411 $layout_manager = $this->get_layout_manager($layout);
412 $ret = $layout_manager->generate_level_2_gallery($objects, $options, $short_code, $this);
413 return $ret;
414 }
415
416 function finalize_markup($content, $short_code) {
417 if ($short_code['display'] != 'popup') {
418 $additional_classes = '';
419 if (!empty($short_code['custom_classes'])) {
420 $additional_classes = $short_code['custom_classes'];
421 }
422 if (!empty($short_code['alignment'])) {
423 $additional_classes .= ' align'.$short_code['alignment'];
424 }
425 $ret = "<div class='photonic-{$this->provider}-stream photonic-stream $additional_classes' id='photonic-{$this->provider}-stream-{$this->gallery_index}'>\n";
426 }
427 else {
428 $popup_id = "id='photonic-{$this->provider}-panel-" . $short_code['panel'] . "'";
429 $ret = "<div class='photonic-{$this->provider}-panel photonic-panel' $popup_id>\n";
430 }
431 $ret .= $content."\n";
432 $ret .= "</div><!-- .photonic-stream or .photonic-panel -->\n";
433 return $ret;
434 }
435
436 function get_layout_manager($layout) {
437 global $photonic_layout_manager_default, $photonic_layout_manager_slideshow;
438 if (in_array($layout, array('strip-above', 'strip-below', 'strip-right', 'no-strip'))) {
439 if (!isset($photonic_layout_manager_slideshow)) {
440 $photonic_layout_manager_slideshow = new Photonic_Layout_Slideshow();
441 }
442 $layout_manager = $photonic_layout_manager_slideshow;
443 }
444 else {
445 if (!isset($photonic_layout_manager_default)) {
446 $photonic_layout_manager_default = new Photonic_Layout();
447 }
448 $layout_manager = $photonic_layout_manager_default;
449 }
450 return $layout_manager;
451 }
452
453 function get_header_display($args) {
454 if (!isset($args['headers'])) {
455 return array(
456 'thumbnail' => 'inherit',
457 'title' => 'inherit',
458 'counter' => 'inherit',
459 );
460 }
461 else if (empty($args['headers'])) {
462 return array (
463 'thumbnail' => 'none',
464 'title' => 'none',
465 'counter' => 'none',
466 );
467 }
468 else {
469 $header_array = explode(',', $args['headers']);
470 return array(
471 'thumbnail' => in_array('thumbnail', $header_array) ? 'show' : 'none',
472 'title' => in_array('title', $header_array) ? 'show' : 'none',
473 'counter' => in_array('counter', $header_array) ? 'show' : 'none',
474 );
475 }
476 }
477
478 function get_hidden_headers($arg_headers, $setting_headers) {
479 return array(
480 'thumbnail' => $arg_headers['thumbnail'] === 'inherit' ? $setting_headers['thumbnail'] : ($arg_headers['thumbnail'] === 'none' ? true : false),
481 'title' => $arg_headers['title'] === 'inherit' ? $setting_headers['title'] : ($arg_headers['title'] === 'none' ? true : false),
482 'counter' => $arg_headers['counter'] === 'inherit' ? $setting_headers['counter'] : ($arg_headers['counter'] === 'none' ? true : false),
483 );
484 }
485
486 /**
487 * Wraps an error message in appropriately-styled markup for display in the front-end
488 *
489 * @param $message
490 * @return string
491 */
492 function error($message) {
493 return "<div class='photonic-error photonic-{$this->provider}-error'>\n\t<span class='photonic-error-icon photonic-icon'>&nbsp;</span>\n\t<div class='photonic-message'>\n\t\t$message\n\t</div>\n</div>\n";
494 }
495
496 /**
497 * Retrieves the error messages from a WP_Response object and formats them in a display-ready markup.
498 *
499 * @param WP_Error $response
500 * @param bool $server_msg
501 * @return string
502 */
503 function wp_error_message($response, $server_msg = true) {
504 $ret = '';
505 if ($server_msg) {
506 $ret = $this->get_server_error()."<br/>\n";
507 }
508 if (is_wp_error($response)) {
509 $messages = $response->get_error_messages();
510 $ret .= '<strong>'.esc_html(sprintf(_n('%s Message:', '%s Messages:', count($messages), 'photonic'), count($messages)))."</strong><br/>\n";
511 foreach ($messages as $message) {
512 $ret .= $message."<br>\n";
513 }
514 }
515 return $ret;
516 }
517
518 function push_to_stack($event) {
519 global $photonic_performance_logging;
520 if (empty($photonic_performance_logging)) {
521 return;
522 }
523
524 if (!isset($this->stack_trace[$this->gallery_index])) {
525 $events = array();
526 }
527 else {
528 $events = $this->stack_trace[$this->gallery_index];
529 }
530
531 $this->add_to_first_open_event($events, $event);
532 $this->stack_trace[$this->gallery_index] = $events;
533 }
534
535 private function add_to_first_open_event(&$events, $new_event) {
536 $found = false;
537 foreach ($events as $id => $event) {
538 if (isset($event['start']) && !isset($event['end'])) {
539 // Ongoing event. Need to add to this.
540 $found = true;
541 if (!isset($event['children'])) {
542 $children = array();
543 }
544 else {
545 $children = $event['children'];
546 }
547 $this->add_to_first_open_event($children, $new_event);
548 $event['children'] = $children;
549 $events[$id] = $event;
550 }
551 if ($found) {
552 break;
553 }
554 }
555 if (!$found) {
556 $events[] = array(
557 'event' => $new_event,
558 'start' => microtime(true),
559 );
560 }
561 }
562
563 function pop_from_stack() {
564 global $photonic_performance_logging;
565 if (empty($photonic_performance_logging)) {
566 return;
567 }
568
569 if (!isset($this->stack_trace[$this->gallery_index])) {
570 return;
571 }
572 else {
573 $events = $this->stack_trace[$this->gallery_index];
574 $this->pop_from_first_open_event($events);
575 $this->stack_trace[$this->gallery_index] = $events;
576 }
577 }
578
579 private function pop_from_first_open_event(&$events) {
580 $found = false;
581 foreach ($events as $id => $event) {
582 if (isset($event['start']) && !isset($event['end'])) {
583 // Ongoing event. Need to pop this or its open child
584 $found = true;
585 $found_child = false;
586 if (isset($event['children'])) {
587 $children = $event['children'];
588 $found_child = $this->pop_from_first_open_event($children);
589 $event['children'] = $children;
590 }
591 if (!$found_child) {
592 $event['end'] = microtime(true);
593 $event['time'] = $event['end'] - $event['start'];
594 }
595 $events[$id] = $event;
596 }
597 if ($found) {
598 break;
599 }
600 }
601 return $found;
602 }
603
604 function get_stack_markup() {
605 global $photonic_performance_logging;
606 if (empty($photonic_performance_logging)) {
607 return '';
608 }
609
610 $ret = '';
611 if (!empty($this->stack_trace[$this->gallery_index])) {
612 $ret = "<!--\n";
613 $ret .= "Stats for Provider: {$this->provider}, Gallery: {$this->gallery_index}\n";
614 $events = $this->stack_trace[$this->gallery_index];
615 $ret .= $this->get_nested_element($events);
616 $ret .= "-->\n";
617 }
618 return $ret;
619 }
620
621 private function get_nested_element($events, $indent = "\t") {
622 $ret = '';
623 foreach ($events as $trace) {
624 $trace_items = array();
625 foreach ($trace as $key => $trace_item) {
626 if ($key != 'children') {
627 $trace_items[] = strtoupper(substr($key, 0, 1)).substr($key, 1).': '.$trace_item;
628 }
629 }
630 $ret .= $indent.implode(', ', $trace_items)."\n";
631 if (!empty($trace['children'])) {
632 $ret .= $this->get_nested_element($trace['children'], $indent."\t");
633 }
634 }
635 return $ret;
636 }
637
638 function ssl_verify_peer(&$handle) {
639 curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
640 }
641
642 function get_server_error() {
643 return sprintf(esc_html__('There was an error connecting to %s. Please try again later.', 'photonic'), $this->provider);
644 }
645
646 /**
647 * Helper execution, implemented by child classes
648 *
649 * @param $args
650 * @return string
651 */
652 function execute_helper($args) {
653 // Blank method, to be overridden by child classes
654 return '';
655 }
656
657 function add_hooks() {
658 // Blank method, implemented by child classes, if required
659 }
660 }
661