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

543 lines 18.5 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 $layout_manager = Slideshow::get_instance();
308 }
309 else {
310 $layout_manager = Grid::get_instance();
311 }
312 return $layout_manager;
313 }
314
315 function get_header_display($args) {
316 if (!isset($args['headers'])) {
317 return [
318 'thumbnail' => 'inherit',
319 'title' => 'inherit',
320 'counter' => 'inherit',
321 ];
322 }
323 else if (empty($args['headers'])) {
324 return [
325 'thumbnail' => 'none',
326 'title' => 'none',
327 'counter' => 'none',
328 ];
329 }
330 else {
331 $header_array = explode(',', $args['headers']);
332 return [
333 'thumbnail' => in_array('thumbnail', $header_array) ? 'show' : 'none',
334 'title' => in_array('title', $header_array) ? 'show' : 'none',
335 'counter' => in_array('counter', $header_array) ? 'show' : 'none',
336 ];
337 }
338 }
339
340 function get_hidden_headers($arg_headers, $setting_headers) {
341 return [
342 'thumbnail' => $arg_headers['thumbnail'] === 'inherit' ? $setting_headers['thumbnail'] : ($arg_headers['thumbnail'] === 'none' ? true : false),
343 'title' => $arg_headers['title'] === 'inherit' ? $setting_headers['title'] : ($arg_headers['title'] === 'none' ? true : false),
344 'counter' => $arg_headers['counter'] === 'inherit' ? $setting_headers['counter'] : ($arg_headers['counter'] === 'none' ? true : false),
345 ];
346 }
347
348 /**
349 * Wraps an error message in appropriately-styled markup for display in the front-end
350 *
351 * @param $message
352 * @return string
353 */
354 function error($message) {
355 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";
356 }
357
358 /**
359 * Retrieves the error messages from a WP_Response object and formats them in a display-ready markup.
360 *
361 * @param WP_Error $response
362 * @param bool $server_msg
363 * @return string
364 */
365 function wp_error_message($response, $server_msg = true) {
366 $ret = '';
367 if ($server_msg) {
368 $ret = $this->get_server_error()."<br/>\n";
369 }
370 if (is_wp_error($response)) {
371 $messages = $response->get_error_messages();
372 $ret .= '<strong>'.esc_html(sprintf(_n('%s Message:', '%s Messages:', count($messages), 'photonic'), count($messages)))."</strong><br/>\n";
373 foreach ($messages as $message) {
374 $ret .= $message."<br>\n";
375 }
376 }
377 return $ret;
378 }
379
380 function push_to_stack($event) {
381 global $photonic_performance_logging;
382 if (empty($photonic_performance_logging)) {
383 return;
384 }
385
386 if (!isset($this->stack_trace[$this->gallery_index])) {
387 $events = [];
388 }
389 else {
390 $events = $this->stack_trace[$this->gallery_index];
391 }
392
393 $this->add_to_first_open_event($events, $event);
394 $this->stack_trace[$this->gallery_index] = $events;
395 }
396
397 private function add_to_first_open_event(&$events, $new_event) {
398 $found = false;
399 foreach ($events as $id => $event) {
400 if (isset($event['start']) && !isset($event['end'])) {
401 // Ongoing event. Need to add to this.
402 $found = true;
403 if (!isset($event['children'])) {
404 $children = [];
405 }
406 else {
407 $children = $event['children'];
408 }
409 $this->add_to_first_open_event($children, $new_event);
410 $event['children'] = $children;
411 $events[$id] = $event;
412 }
413 if ($found) {
414 break;
415 }
416 }
417 if (!$found) {
418 $events[] = [
419 'event' => $new_event,
420 'start' => microtime(true),
421 ];
422 }
423 }
424
425 function pop_from_stack() {
426 global $photonic_performance_logging;
427 if (empty($photonic_performance_logging)) {
428 return;
429 }
430
431 if (!isset($this->stack_trace[$this->gallery_index])) {
432 return;
433 }
434 else {
435 $events = $this->stack_trace[$this->gallery_index];
436 $this->pop_from_first_open_event($events);
437 $this->stack_trace[$this->gallery_index] = $events;
438 }
439 }
440
441 private function pop_from_first_open_event(&$events) {
442 $found = false;
443 foreach ($events as $id => $event) {
444 if (isset($event['start']) && !isset($event['end'])) {
445 // Ongoing event. Need to pop this or its open child
446 $found = true;
447 $found_child = false;
448 if (isset($event['children'])) {
449 $children = $event['children'];
450 $found_child = $this->pop_from_first_open_event($children);
451 $event['children'] = $children;
452 }
453 if (!$found_child) {
454 $event['end'] = microtime(true);
455 $event['time'] = $event['end'] - $event['start'];
456 }
457 $events[$id] = $event;
458 }
459 if ($found) {
460 break;
461 }
462 }
463 return $found;
464 }
465
466 function get_stack_markup() {
467 global $photonic_performance_logging;
468 if (empty($photonic_performance_logging)) {
469 return '';
470 }
471
472 $ret = '';
473 if (!empty($this->stack_trace[$this->gallery_index])) {
474 $ret = "<!--\n";
475 $ret .= "Stats for Provider: {$this->provider}, Gallery: {$this->gallery_index}\n";
476 $events = $this->stack_trace[$this->gallery_index];
477 $ret .= $this->get_nested_element($events);
478 $ret .= "-->\n";
479 }
480 return $ret;
481 }
482
483 private function get_nested_element($events, $indent = "\t") {
484 $ret = '';
485 foreach ($events as $trace) {
486 $trace_items = [];
487 foreach ($trace as $key => $trace_item) {
488 if ($key != 'children') {
489 $trace_items[] = strtoupper(substr($key, 0, 1)).substr($key, 1).': '.$trace_item;
490 }
491 }
492 $ret .= $indent.implode(', ', $trace_items)."\n";
493 if (!empty($trace['children'])) {
494 $ret .= $this->get_nested_element($trace['children'], $indent."\t");
495 }
496 }
497 return $ret;
498 }
499
500 protected function get_gallery_url($short_code, $meta) {
501 global $photonic_alternative_shortcode, $photonic_gallery_template_page;
502
503 $shortcode_tag = $photonic_alternative_shortcode ?: 'gallery';
504 $shortcode_parts = [];
505 foreach ($short_code as $attr => $value) {
506 if (is_array($value)) {
507 continue;
508 }
509 $shortcode_parts[] = $attr.'="'.esc_attr($value).'"';
510 }
511 $raw_shortcode = '['.$shortcode_tag.' '.implode(' ', $shortcode_parts).']';
512
513 $gallery_url = add_query_arg([
514 'photonic_gallery' => base64_encode($raw_shortcode),
515 'photonic_gallery_title' => $meta['title'],
516 ], get_page_link($photonic_gallery_template_page));
517 return $gallery_url;
518 }
519
520 function ssl_verify_peer(&$handle) {
521 curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
522 }
523
524 function get_server_error() {
525 return sprintf(esc_html__('There was an error connecting to %s. Please try again later.', 'photonic'), $this->provider);
526 }
527
528 /**
529 * Helper execution, implemented by child classes
530 *
531 * @param $args
532 * @return string
533 */
534 function execute_helper($args) {
535 // Blank method, to be overridden by child classes
536 return '';
537 }
538
539 function add_hooks() {
540 // Blank method, implemented by child classes, if required
541 }
542 }
543