PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 2.42
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v2.42
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 / Modules / Core.php

Core.php in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 2.42, at Modules/Core.php

545 lines 18.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Photonic_Plugin\Modules;
3
4 use Photonic_Plugin\Layouts\Grid;
5 use Photonic_Plugin\Layouts\Slideshow;
6 use WP_Error;
7
8 /**
9 * Gallery processor class to be extended by individual processors. This class has an abstract method called <code>get_gallery_images</code>
10 * that has to be defined by each inheriting processor.
11 *
12 * This is also where the OAuth support is implemented. The URLs are defined using abstract functions, while a handful of utility functions are defined.
13 * Most utility functions have been adapted from the OAuth PHP package distributed here: https://code.google.com/p/oauth-php/.
14 *
15 */
16
17 abstract class Core {
18 public $library, $api_key, $api_secret, $provider, $nonce, $oauth_timestamp, $signature_parameters, $link_lightbox_title,
19 $oauth_version, $oauth_done, $show_more_link, $is_server_down, $is_more_required, $gallery_index, $bypass_popup, $common_parameters,
20 $doc_links, $password_protected, $token, $token_secret, $show_buy_link, $stack_trace;
21
22 protected function __construct() {
23 global $photonic_slideshow_library, $photonic_custom_lightbox, $photonic_enable_popup, $photonic_thumbnail_style;
24 if ($photonic_slideshow_library != 'custom') {
25 $this->library = $photonic_slideshow_library;
26 }
27 else {
28 $this->library = $photonic_custom_lightbox;
29 }
30 $this->nonce = self::nonce();
31 $this->oauth_timestamp = time();
32 $this->oauth_version = '1.0';
33 $this->show_more_link = false;
34 $this->is_server_down = false;
35 $this->is_more_required = true;
36 $this->gallery_index = 0;
37 $this->bypass_popup = empty($photonic_enable_popup) || $photonic_enable_popup == 'off' || $photonic_enable_popup == 'hide';
38 $this->common_parameters = [
39 'columns' => 'auto',
40 'layout' => !empty($photonic_thumbnail_style) ? $photonic_thumbnail_style : 'square',
41 'more' => '',
42 'display' => 'in-page',
43 'panel' => '',
44 'filter' => '',
45 'filter_type' => 'include',
46 'fx' => 'slide', // LightSlider effects: fade and slide
47 'timeout' => 4000, // Time between slides in ms
48 'speed' => 1000, // Time for each transition
49 'pause' => true, // Pause on hover
50 'strip-style' => 'thumbs',
51 'controls' => 'show',
52 'popup' => $this->bypass_popup ? 'hide' : $photonic_enable_popup,
53
54 'custom_classes' => '',
55 'alignment' => '',
56 ];
57 $this->common_parameters['photo_layout'] = $this->common_parameters['layout'];
58
59 $this->doc_links = [];
60 $this->password_protected = esc_html__('This album is password-protected. Please provide a valid password.', 'photonic');
61 $this->show_buy_link = false;
62 $this->stack_trace = [];
63 $this->add_hooks();
64 }
65
66 /**
67 * Main function that fetches the images associated with the shortcode. This is implemented by all sub-classes.
68 *
69 * @abstract
70 * @param array $attr
71 * @param array $gallery_meta
72 */
73 abstract public function get_gallery_images($attr = [], &$gallery_meta = []);
74
75 /**
76 * Generates a nonce for use in signing calls.
77 *
78 * @static
79 * @return string
80 */
81 public static function nonce() {
82 $mt = microtime();
83 $rand = mt_rand();
84 return md5($mt . $rand);
85 }
86
87 /**
88 * Takes a string of parameters in an HTML encoded string, then returns an array of name-value pairs, with the parameter
89 * name and the associated value.
90 *
91 * @static
92 * @param $input
93 * @return array
94 */
95 public static function parse_parameters($input) {
96 if (!isset($input) || !$input) return [];
97
98 $pairs = explode('&', $input);
99
100 $parsed_parameters = [];
101 foreach ($pairs as $pair) {
102 $split = explode('=', $pair, 2);
103 $parameter = urldecode($split[0]);
104 $value = isset($split[1]) ? urldecode($split[1]) : '';
105
106 if (isset($parsed_parameters[$parameter])) {
107 // We have already recieved parameter(s) with this name, so add to the list
108 // of parameters with this name
109 if (is_scalar($parsed_parameters[$parameter])) {
110 // This is the first duplicate, so transform scalar (string) into an array
111 // so we can add the duplicates
112 $parsed_parameters[$parameter] = [$parsed_parameters[$parameter]];
113 }
114
115 $parsed_parameters[$parameter][] = $value;
116 }
117 else {
118 $parsed_parameters[$parameter] = $value;
119 }
120 }
121 return $parsed_parameters;
122 }
123
124 function more_link_button($link_to = '') {
125 global $photonic_archive_link_more;
126 if (empty($photonic_archive_link_more) && $this->is_more_required) {
127 return "<div class='photonic-more-link-container'><a href='$link_to' class='photonic-more-button more-button-{$this->provider}'>See the rest</a></div>";
128 }
129 $this->is_more_required = true;
130 return '';
131 }
132
133 /**
134 * Prints the header for a section. Typically used for albums / photosets / groups, where some generic information about the album / photoset / group is available.
135 * The <code>$options</code> array accepts the following prarameters:
136 * - string type Indicates what type of object is being displayed like gallery / photoset / album etc. This is added to the CSS class.
137 * - array $hidden Contains the elements that should be hidden from the header display.
138 * - array $counters Contains counts of the object that the header represents. In most cases this has just one value. Zenfolio objects have multiple values.
139 * - string $link Should clicking on the thumbnail / title take you anywhere?
140 * - string $display Indicates if this is on the page or in a popup
141 * - 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.
142 * - string $provider What is the source of the data?
143 *
144 * @param array $header The header object, which contains the title, thumbnail source URL and the link where clicking on the thumb will take you
145 * @param array $options The options to display this header. Options contain the listed internal fields fields
146 * @param array $gallery_meta
147 * @return string
148 */
149 function process_object_header($header, $options = [], &$gallery_meta = []) {
150 $type = empty($options['type']) ? 'group' : $options['type'];
151 $hidden = isset($options['hidden']) && is_array($options['hidden']) ? $options['hidden'] : [];
152 $counters = isset($options['counters']) && is_array($options['counters']) ? $options['counters'] : [];
153 $link = !isset($options['link']) ? true : $options['link'];
154 $display = empty($options['display']) ? 'in-page' : $options['display'];
155 $iterate_level_3 = !isset($options['iterate_level_3']) ? true : $options['iterate_level_3'];
156
157 if ($this->bypass_popup && $display != 'in-page') {
158 return '';
159 }
160
161 $ret = '';
162 global $photonic_gallery_template_page, $photonic_page_content;
163 if (is_page($photonic_gallery_template_page) && in_array($photonic_page_content, ['replace-if-available', 'append-if-available'])) {
164 $ret = wp_kses_post($header['description']);
165 }
166 else if (!is_page($photonic_gallery_template_page) && !empty($header['title'])) {
167 global $photonic_external_links_in_new_tab;
168 $title = esc_attr($header['title']);
169
170 $gallery_meta['title'] = $title;
171 $gallery_meta['type'] = $type;
172
173 if (!empty($photonic_external_links_in_new_tab)) {
174 $target = ' target="_blank" ';
175 }
176 else {
177 $target = '';
178 }
179
180 $anchor = '';
181 if (!empty($header['thumb_url'])) {
182 $image = '<img src="'.esc_url($header['thumb_url']).'" alt="'.$title.'" />';
183
184 if ($link) {
185 $anchor = "<a href='".esc_url($header['link_url'])."' class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb' title='".$title."' $target>".$image."</a>";
186 }
187 else {
188 $anchor = "<div class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb'>$image</div>";
189 }
190 }
191
192 if (empty($hidden['thumbnail']) || empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
193 $popup_header_class = '';
194 if ($display == 'popup') {
195 $popup_header_class = 'photonic-panel-header';
196 }
197 $ret .= "<div class='photonic-object-header photonic-{$this->provider}-$type $popup_header_class'>";
198
199 if (empty($hidden['thumbnail'])) {
200 $ret .= $anchor;
201 }
202 if (empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
203 $ret .= "<div class='photonic-header-details photonic-$type-details'>";
204 if (empty($hidden['title']) || empty($iterate_level_3)) {
205 $provider = $this->provider;
206 $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>' : '';
207
208 if ($link) {
209 $ret .= "<div class='photonic-header-title photonic-$type-title'><a href='".esc_url($header['link_url'])."' $target>".$title.'</a>'.$expand.'</div>';
210 }
211 else {
212 $ret .= "<div class='photonic-header-title photonic-$type-title'>".$title.$expand.'</div>';
213 }
214 }
215 if (empty($hidden['counter'])) {
216 $counter_texts = [];
217 if (!empty($counters['groups'])) {
218 $counter_texts[] = esc_html(sprintf(_n('%s group', '%s groups', $counters['groups'], 'photonic'), $counters['groups']));
219 }
220 if (!empty($counters['sets'])) {
221 $counter_texts[] = esc_html(sprintf(_n('%s set', '%s sets', $counters['sets'], 'photonic'), $counters['sets']));
222 }
223 if (!empty($counters['photos'])) {
224 $counter_texts[] = esc_html(sprintf(_n('%s photo', '%s photos', $counters['photos'], 'photonic'), $counters['photos']));
225 }
226 if (!empty($counters['videos'])) {
227 $counter_texts[] = esc_html(sprintf(_n('%s video', '%s videos', $counters['videos'], 'photonic'), $counters['videos']));
228 }
229
230 apply_filters('photonic_modify_counter_texts', $counter_texts, $counters);
231
232 if (!empty($counter_texts)) {
233 $ret .= "<span class='photonic-header-info photonic-$type-photos'>".implode(', ', $counter_texts).'</span>';
234 }
235 }
236
237 $ret .= "</div><!-- .photonic-$type-details -->";
238 }
239 $ret .= "</div>";
240 }
241 }
242
243 return $ret;
244 }
245
246 /**
247 * Generates the markup for a single photo.
248 *
249 * @param $data array Pertinent pieces of information about the photo - the source (src), the photo page (href), title and caption
250 * @return string
251 */
252 function generate_single_photo_markup($data) {
253 $layout_manager = $this->get_layout_manager('square');
254 $ret = $layout_manager->generate_single_photo_markup($data, $this);
255 return $ret;
256 }
257
258 /**
259 * Generates the HTML for the gallery, based on the level.
260 * Level 1 corresponds to a group of photos. This is used for both, in-page and popup displays.
261 * Level 2 corresponds to a group of albums.
262 * This calls an individual layout generator for rendering the gallery.
263 * The code for the random layouts is handled in JS, but just the HTML markers for it are provided here.
264 *
265 * @param $photos
266 * @param array $options
267 * @param $short_code
268 * @param $level
269 * @return string
270 */
271 function layout_gallery($photos, $options, $short_code, $level) {
272 global $photonic_thumbnail_style;
273 $layout = !empty($short_code['layout']) ? $short_code['layout'] : $photonic_thumbnail_style;
274 $layout_manager = $this->get_layout_manager($layout);
275 $ret = '';
276 if ($level == 1) {
277 $ret = $layout_manager->generate_level_1_gallery($photos, $options, $short_code, $this);
278 }
279 else if ($level == 2) {
280 $ret = $layout_manager->generate_level_2_gallery($photos, $options, $short_code, $this);
281 }
282 return $ret;
283 }
284
285 function finalize_markup($content, $short_code) {
286 if ($short_code['display'] != 'popup') {
287 $additional_classes = '';
288 if (!empty($short_code['custom_classes'])) {
289 $additional_classes = $short_code['custom_classes'];
290 }
291 if (!empty($short_code['alignment'])) {
292 $additional_classes .= ' align'.$short_code['alignment'];
293 }
294 $ret = "<div class='photonic-{$this->provider}-stream photonic-stream $additional_classes' id='photonic-{$this->provider}-stream-{$this->gallery_index}'>\n";
295 }
296 else {
297 $popup_id = "id='photonic-{$this->provider}-panel-" . $short_code['panel'] . "'";
298 $ret = "<div class='photonic-{$this->provider}-panel photonic-panel' $popup_id>\n";
299 }
300 $ret .= $content."\n";
301 $ret .= "</div><!-- .photonic-stream or .photonic-panel -->\n";
302 return $ret;
303 }
304
305 function get_layout_manager($layout) {
306 if (in_array($layout, ['strip-above', 'strip-below', 'strip-right', 'no-strip'])) {
307 require_once(PHOTONIC_PATH.'/Layouts/Slideshow.php');
308 $layout_manager = Slideshow::get_instance();
309 }
310 else {
311 require_once(PHOTONIC_PATH.'/Layouts/Grid.php');
312 $layout_manager = Grid::get_instance();
313 }
314 return $layout_manager;
315 }
316
317 function get_header_display($args) {
318 if (!isset($args['headers'])) {
319 return [
320 'thumbnail' => 'inherit',
321 'title' => 'inherit',
322 'counter' => 'inherit',
323 ];
324 }
325 else if (empty($args['headers'])) {
326 return [
327 'thumbnail' => 'none',
328 'title' => 'none',
329 'counter' => 'none',
330 ];
331 }
332 else {
333 $header_array = explode(',', $args['headers']);
334 return [
335 'thumbnail' => in_array('thumbnail', $header_array) ? 'show' : 'none',
336 'title' => in_array('title', $header_array) ? 'show' : 'none',
337 'counter' => in_array('counter', $header_array) ? 'show' : 'none',
338 ];
339 }
340 }
341
342 function get_hidden_headers($arg_headers, $setting_headers) {
343 return [
344 'thumbnail' => $arg_headers['thumbnail'] === 'inherit' ? $setting_headers['thumbnail'] : ($arg_headers['thumbnail'] === 'none' ? true : false),
345 'title' => $arg_headers['title'] === 'inherit' ? $setting_headers['title'] : ($arg_headers['title'] === 'none' ? true : false),
346 'counter' => $arg_headers['counter'] === 'inherit' ? $setting_headers['counter'] : ($arg_headers['counter'] === 'none' ? true : false),
347 ];
348 }
349
350 /**
351 * Wraps an error message in appropriately-styled markup for display in the front-end
352 *
353 * @param $message
354 * @return string
355 */
356 function error($message) {
357 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";
358 }
359
360 /**
361 * Retrieves the error messages from a WP_Response object and formats them in a display-ready markup.
362 *
363 * @param WP_Error $response
364 * @param bool $server_msg
365 * @return string
366 */
367 function wp_error_message($response, $server_msg = true) {
368 $ret = '';
369 if ($server_msg) {
370 $ret = $this->get_server_error()."<br/>\n";
371 }
372 if (is_wp_error($response)) {
373 $messages = $response->get_error_messages();
374 $ret .= '<strong>'.esc_html(sprintf(_n('%s Message:', '%s Messages:', count($messages), 'photonic'), count($messages)))."</strong><br/>\n";
375 foreach ($messages as $message) {
376 $ret .= $message."<br>\n";
377 }
378 }
379 return $ret;
380 }
381
382 function push_to_stack($event) {
383 global $photonic_performance_logging;
384 if (empty($photonic_performance_logging)) {
385 return;
386 }
387
388 if (!isset($this->stack_trace[$this->gallery_index])) {
389 $events = [];
390 }
391 else {
392 $events = $this->stack_trace[$this->gallery_index];
393 }
394
395 $this->add_to_first_open_event($events, $event);
396 $this->stack_trace[$this->gallery_index] = $events;
397 }
398
399 private function add_to_first_open_event(&$events, $new_event) {
400 $found = false;
401 foreach ($events as $id => $event) {
402 if (isset($event['start']) && !isset($event['end'])) {
403 // Ongoing event. Need to add to this.
404 $found = true;
405 if (!isset($event['children'])) {
406 $children = [];
407 }
408 else {
409 $children = $event['children'];
410 }
411 $this->add_to_first_open_event($children, $new_event);
412 $event['children'] = $children;
413 $events[$id] = $event;
414 }
415 if ($found) {
416 break;
417 }
418 }
419 if (!$found) {
420 $events[] = [
421 'event' => $new_event,
422 'start' => microtime(true),
423 ];
424 }
425 }
426
427 function pop_from_stack() {
428 global $photonic_performance_logging;
429 if (empty($photonic_performance_logging)) {
430 return;
431 }
432
433 if (!isset($this->stack_trace[$this->gallery_index])) {
434 return;
435 }
436 else {
437 $events = $this->stack_trace[$this->gallery_index];
438 $this->pop_from_first_open_event($events);
439 $this->stack_trace[$this->gallery_index] = $events;
440 }
441 }
442
443 private function pop_from_first_open_event(&$events) {
444 $found = false;
445 foreach ($events as $id => $event) {
446 if (isset($event['start']) && !isset($event['end'])) {
447 // Ongoing event. Need to pop this or its open child
448 $found = true;
449 $found_child = false;
450 if (isset($event['children'])) {
451 $children = $event['children'];
452 $found_child = $this->pop_from_first_open_event($children);
453 $event['children'] = $children;
454 }
455 if (!$found_child) {
456 $event['end'] = microtime(true);
457 $event['time'] = $event['end'] - $event['start'];
458 }
459 $events[$id] = $event;
460 }
461 if ($found) {
462 break;
463 }
464 }
465 return $found;
466 }
467
468 function get_stack_markup() {
469 global $photonic_performance_logging;
470 if (empty($photonic_performance_logging)) {
471 return '';
472 }
473
474 $ret = '';
475 if (!empty($this->stack_trace[$this->gallery_index])) {
476 $ret = "<!--\n";
477 $ret .= "Stats for Provider: {$this->provider}, Gallery: {$this->gallery_index}\n";
478 $events = $this->stack_trace[$this->gallery_index];
479 $ret .= $this->get_nested_element($events);
480 $ret .= "-->\n";
481 }
482 return $ret;
483 }
484
485 private function get_nested_element($events, $indent = "\t") {
486 $ret = '';
487 foreach ($events as $trace) {
488 $trace_items = [];
489 foreach ($trace as $key => $trace_item) {
490 if ($key != 'children') {
491 $trace_items[] = strtoupper(substr($key, 0, 1)).substr($key, 1).': '.$trace_item;
492 }
493 }
494 $ret .= $indent.implode(', ', $trace_items)."\n";
495 if (!empty($trace['children'])) {
496 $ret .= $this->get_nested_element($trace['children'], $indent."\t");
497 }
498 }
499 return $ret;
500 }
501
502 protected function get_gallery_url($short_code, $meta) {
503 global $photonic_alternative_shortcode, $photonic_gallery_template_page;
504
505 $shortcode_tag = $photonic_alternative_shortcode ?: 'gallery';
506 $shortcode_parts = [];
507 foreach ($short_code as $attr => $value) {
508 if (is_array($value)) {
509 continue;
510 }
511 $shortcode_parts[] = $attr.'="'.esc_attr($value).'"';
512 }
513 $raw_shortcode = '['.$shortcode_tag.' '.implode(' ', $shortcode_parts).']';
514
515 $gallery_url = add_query_arg([
516 'photonic_gallery' => base64_encode($raw_shortcode),
517 'photonic_gallery_title' => $meta['title'],
518 ], get_page_link($photonic_gallery_template_page));
519 return $gallery_url;
520 }
521
522 function ssl_verify_peer(&$handle) {
523 curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
524 }
525
526 function get_server_error() {
527 return sprintf(esc_html__('There was an error connecting to %s. Please try again later.', 'photonic'), $this->provider);
528 }
529
530 /**
531 * Helper execution, implemented by child classes
532 *
533 * @param $args
534 * @return string
535 */
536 function execute_helper($args) {
537 // Blank method, to be overridden by child classes
538 return '';
539 }
540
541 function add_hooks() {
542 // Blank method, implemented by child classes, if required
543 }
544 }
545