PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 2.44
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v2.44
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 2.45 All 140 releases
photonic / Modules / Core.php

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

536 lines 18.3 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 /**
125 * Prints the header for a section. Typically used for albums / photosets / groups, where some generic information about the album / photoset / group is available.
126 * The <code>$options</code> array accepts the following prarameters:
127 * - string type Indicates what type of object is being displayed like gallery / photoset / album etc. This is added to the CSS class.
128 * - array $hidden Contains the elements that should be hidden from the header display.
129 * - array $counters Contains counts of the object that the header represents. In most cases this has just one value. Zenfolio objects have multiple values.
130 * - string $link Should clicking on the thumbnail / title take you anywhere?
131 * - string $display Indicates if this is on the page or in a popup
132 * - 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.
133 * - string $provider What is the source of the data?
134 *
135 * @param array $header The header object, which contains the title, thumbnail source URL and the link where clicking on the thumb will take you
136 * @param array $options The options to display this header. Options contain the listed internal fields fields
137 * @param array $gallery_meta
138 * @return string
139 */
140 function process_object_header($header, $options = [], &$gallery_meta = []) {
141 $type = empty($options['type']) ? 'group' : $options['type'];
142 $hidden = isset($options['hidden']) && is_array($options['hidden']) ? $options['hidden'] : [];
143 $counters = isset($options['counters']) && is_array($options['counters']) ? $options['counters'] : [];
144 $link = !isset($options['link']) ? true : $options['link'];
145 $display = empty($options['display']) ? 'in-page' : $options['display'];
146 $iterate_level_3 = !isset($options['iterate_level_3']) ? true : $options['iterate_level_3'];
147
148 if ($this->bypass_popup && $display != 'in-page') {
149 return '';
150 }
151
152 $ret = '';
153 global $photonic_gallery_template_page, $photonic_page_content;
154 if (!empty($photonic_gallery_template_page) && is_page($photonic_gallery_template_page) && in_array($photonic_page_content, ['replace-if-available', 'append-if-available'])) {
155 $ret = wp_kses_post($header['description']);
156 }
157 else if (!is_page($photonic_gallery_template_page) && !empty($header['title'])) {
158 global $photonic_external_links_in_new_tab;
159 $title = esc_attr($header['title']);
160
161 $gallery_meta['title'] = $title;
162 $gallery_meta['type'] = $type;
163
164 if (!empty($photonic_external_links_in_new_tab)) {
165 $target = ' target="_blank" ';
166 }
167 else {
168 $target = '';
169 }
170
171 $anchor = '';
172 if (!empty($header['thumb_url'])) {
173 $image = '<img src="'.esc_url($header['thumb_url']).'" alt="'.$title.'" />';
174
175 if ($link) {
176 $anchor = "<a href='".esc_url($header['link_url'])."' class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb' title='".$title."' $target>".$image."</a>";
177 }
178 else {
179 $anchor = "<div class='photonic-header-thumb photonic-{$this->provider}-$type-solo-thumb'>$image</div>";
180 }
181 }
182
183 if (empty($hidden['thumbnail']) || empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
184 $popup_header_class = '';
185 if ($display == 'popup') {
186 $popup_header_class = 'photonic-panel-header';
187 }
188 $ret .= "<div class='photonic-object-header photonic-{$this->provider}-$type $popup_header_class'>";
189
190 if (empty($hidden['thumbnail'])) {
191 $ret .= $anchor;
192 }
193 if (empty($hidden['title']) || empty($hidden['counter']) || empty($iterate_level_3)) {
194 $ret .= "<div class='photonic-header-details photonic-$type-details'>";
195 if (empty($hidden['title']) || empty($iterate_level_3)) {
196 $provider = $this->provider;
197 $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>' : '';
198
199 if ($link) {
200 $ret .= "<div class='photonic-header-title photonic-$type-title'><a href='".esc_url($header['link_url'])."' $target>".$title.'</a>'.$expand.'</div>';
201 }
202 else {
203 $ret .= "<div class='photonic-header-title photonic-$type-title'>".$title.$expand.'</div>';
204 }
205 }
206 if (empty($hidden['counter'])) {
207 $counter_texts = [];
208 if (!empty($counters['groups'])) {
209 $counter_texts[] = esc_html(sprintf(_n('%s group', '%s groups', $counters['groups'], 'photonic'), $counters['groups']));
210 }
211 if (!empty($counters['sets'])) {
212 $counter_texts[] = esc_html(sprintf(_n('%s set', '%s sets', $counters['sets'], 'photonic'), $counters['sets']));
213 }
214 if (!empty($counters['photos'])) {
215 $counter_texts[] = esc_html(sprintf(_n('%s photo', '%s photos', $counters['photos'], 'photonic'), $counters['photos']));
216 }
217 if (!empty($counters['videos'])) {
218 $counter_texts[] = esc_html(sprintf(_n('%s video', '%s videos', $counters['videos'], 'photonic'), $counters['videos']));
219 }
220
221 apply_filters('photonic_modify_counter_texts', $counter_texts, $counters);
222
223 if (!empty($counter_texts)) {
224 $ret .= "<span class='photonic-header-info photonic-$type-photos'>".implode(', ', $counter_texts).'</span>';
225 }
226 }
227
228 $ret .= "</div><!-- .photonic-$type-details -->";
229 }
230 $ret .= "</div>";
231 }
232 }
233
234 return $ret;
235 }
236
237 /**
238 * Generates the markup for a single photo.
239 *
240 * @param $data array Pertinent pieces of information about the photo - the source (src), the photo page (href), title and caption
241 * @return string
242 */
243 function generate_single_photo_markup($data) {
244 $layout_manager = $this->get_layout_manager('square');
245 $ret = $layout_manager->generate_single_photo_markup($data, $this);
246 return $ret;
247 }
248
249 /**
250 * Generates the HTML for the gallery, based on the level.
251 * Level 1 corresponds to a group of photos. This is used for both, in-page and popup displays.
252 * Level 2 corresponds to a group of albums.
253 * This calls an individual layout generator for rendering the gallery.
254 * The code for the random layouts is handled in JS, but just the HTML markers for it are provided here.
255 *
256 * @param $photos
257 * @param array $options
258 * @param $short_code
259 * @param $level
260 * @return string
261 */
262 function layout_gallery($photos, $options, $short_code, $level) {
263 global $photonic_thumbnail_style;
264 $layout = !empty($short_code['layout']) ? $short_code['layout'] : $photonic_thumbnail_style;
265 $layout_manager = $this->get_layout_manager($layout);
266 $ret = '';
267 if ($level == 1) {
268 $ret = $layout_manager->generate_level_1_gallery($photos, $options, $short_code, $this);
269 }
270 else if ($level == 2) {
271 $ret = $layout_manager->generate_level_2_gallery($photos, $options, $short_code, $this);
272 }
273 return $ret;
274 }
275
276 function finalize_markup($content, $short_code) {
277 if ($short_code['display'] != 'popup') {
278 $additional_classes = '';
279 if (!empty($short_code['custom_classes'])) {
280 $additional_classes = $short_code['custom_classes'];
281 }
282 if (!empty($short_code['alignment'])) {
283 $additional_classes .= ' align'.$short_code['alignment'];
284 }
285 $ret = "<div class='photonic-{$this->provider}-stream photonic-stream $additional_classes' id='photonic-{$this->provider}-stream-{$this->gallery_index}'>\n";
286 }
287 else {
288 $popup_id = "id='photonic-{$this->provider}-panel-" . $short_code['panel'] . "'";
289 $ret = "<div class='photonic-{$this->provider}-panel photonic-panel' $popup_id>\n";
290 }
291 $ret .= $content."\n";
292 $ret .= "</div><!-- .photonic-stream or .photonic-panel -->\n";
293 return $ret;
294 }
295
296 function get_layout_manager($layout) {
297 if (in_array($layout, ['strip-above', 'strip-below', 'strip-right', 'no-strip'])) {
298 require_once(PHOTONIC_PATH.'/Layouts/Slideshow.php');
299 $layout_manager = Slideshow::get_instance();
300 }
301 else {
302 require_once(PHOTONIC_PATH.'/Layouts/Grid.php');
303 $layout_manager = Grid::get_instance();
304 }
305 return $layout_manager;
306 }
307
308 function get_header_display($args) {
309 if (!isset($args['headers'])) {
310 return [
311 'thumbnail' => 'inherit',
312 'title' => 'inherit',
313 'counter' => 'inherit',
314 ];
315 }
316 else if (empty($args['headers'])) {
317 return [
318 'thumbnail' => 'none',
319 'title' => 'none',
320 'counter' => 'none',
321 ];
322 }
323 else {
324 $header_array = explode(',', $args['headers']);
325 return [
326 'thumbnail' => in_array('thumbnail', $header_array) ? 'show' : 'none',
327 'title' => in_array('title', $header_array) ? 'show' : 'none',
328 'counter' => in_array('counter', $header_array) ? 'show' : 'none',
329 ];
330 }
331 }
332
333 function get_hidden_headers($arg_headers, $setting_headers) {
334 return [
335 'thumbnail' => $arg_headers['thumbnail'] === 'inherit' ? $setting_headers['thumbnail'] : ($arg_headers['thumbnail'] === 'none' ? true : false),
336 'title' => $arg_headers['title'] === 'inherit' ? $setting_headers['title'] : ($arg_headers['title'] === 'none' ? true : false),
337 'counter' => $arg_headers['counter'] === 'inherit' ? $setting_headers['counter'] : ($arg_headers['counter'] === 'none' ? true : false),
338 ];
339 }
340
341 /**
342 * Wraps an error message in appropriately-styled markup for display in the front-end
343 *
344 * @param $message
345 * @return string
346 */
347 function error($message) {
348 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";
349 }
350
351 /**
352 * Retrieves the error messages from a WP_Response object and formats them in a display-ready markup.
353 *
354 * @param WP_Error $response
355 * @param bool $server_msg
356 * @return string
357 */
358 function wp_error_message($response, $server_msg = true) {
359 $ret = '';
360 if ($server_msg) {
361 $ret = $this->get_server_error()."<br/>\n";
362 }
363 if (is_wp_error($response)) {
364 $messages = $response->get_error_messages();
365 $ret .= '<strong>'.esc_html(sprintf(_n('%s Message:', '%s Messages:', count($messages), 'photonic'), count($messages)))."</strong><br/>\n";
366 foreach ($messages as $message) {
367 $ret .= $message."<br>\n";
368 }
369 }
370 return $ret;
371 }
372
373 function push_to_stack($event) {
374 global $photonic_performance_logging;
375 if (empty($photonic_performance_logging)) {
376 return;
377 }
378
379 if (!isset($this->stack_trace[$this->gallery_index])) {
380 $events = [];
381 }
382 else {
383 $events = $this->stack_trace[$this->gallery_index];
384 }
385
386 $this->add_to_first_open_event($events, $event);
387 $this->stack_trace[$this->gallery_index] = $events;
388 }
389
390 private function add_to_first_open_event(&$events, $new_event) {
391 $found = false;
392 foreach ($events as $id => $event) {
393 if (isset($event['start']) && !isset($event['end'])) {
394 // Ongoing event. Need to add to this.
395 $found = true;
396 if (!isset($event['children'])) {
397 $children = [];
398 }
399 else {
400 $children = $event['children'];
401 }
402 $this->add_to_first_open_event($children, $new_event);
403 $event['children'] = $children;
404 $events[$id] = $event;
405 }
406 if ($found) {
407 break;
408 }
409 }
410 if (!$found) {
411 $events[] = [
412 'event' => $new_event,
413 'start' => microtime(true),
414 ];
415 }
416 }
417
418 function pop_from_stack() {
419 global $photonic_performance_logging;
420 if (empty($photonic_performance_logging)) {
421 return;
422 }
423
424 if (!isset($this->stack_trace[$this->gallery_index])) {
425 return;
426 }
427 else {
428 $events = $this->stack_trace[$this->gallery_index];
429 $this->pop_from_first_open_event($events);
430 $this->stack_trace[$this->gallery_index] = $events;
431 }
432 }
433
434 private function pop_from_first_open_event(&$events) {
435 $found = false;
436 foreach ($events as $id => $event) {
437 if (isset($event['start']) && !isset($event['end'])) {
438 // Ongoing event. Need to pop this or its open child
439 $found = true;
440 $found_child = false;
441 if (isset($event['children'])) {
442 $children = $event['children'];
443 $found_child = $this->pop_from_first_open_event($children);
444 $event['children'] = $children;
445 }
446 if (!$found_child) {
447 $event['end'] = microtime(true);
448 $event['time'] = $event['end'] - $event['start'];
449 }
450 $events[$id] = $event;
451 }
452 if ($found) {
453 break;
454 }
455 }
456 return $found;
457 }
458
459 function get_stack_markup() {
460 global $photonic_performance_logging;
461 if (empty($photonic_performance_logging)) {
462 return '';
463 }
464
465 $ret = '';
466 if (!empty($this->stack_trace[$this->gallery_index])) {
467 $ret = "<!--\n";
468 $ret .= "Stats for Provider: {$this->provider}, Gallery: {$this->gallery_index}\n";
469 $events = $this->stack_trace[$this->gallery_index];
470 $ret .= $this->get_nested_element($events);
471 $ret .= "-->\n";
472 }
473 return $ret;
474 }
475
476 private function get_nested_element($events, $indent = "\t") {
477 $ret = '';
478 foreach ($events as $trace) {
479 $trace_items = [];
480 foreach ($trace as $key => $trace_item) {
481 if ($key != 'children') {
482 $trace_items[] = strtoupper(substr($key, 0, 1)).substr($key, 1).': '.$trace_item;
483 }
484 }
485 $ret .= $indent.implode(', ', $trace_items)."\n";
486 if (!empty($trace['children'])) {
487 $ret .= $this->get_nested_element($trace['children'], $indent."\t");
488 }
489 }
490 return $ret;
491 }
492
493 protected function get_gallery_url($short_code, $meta) {
494 global $photonic_alternative_shortcode, $photonic_gallery_template_page;
495
496 $shortcode_tag = $photonic_alternative_shortcode ?: 'gallery';
497 $shortcode_parts = [];
498 foreach ($short_code as $attr => $value) {
499 if (is_array($value)) {
500 continue;
501 }
502 $shortcode_parts[] = $attr.'="'.esc_attr($value).'"';
503 }
504 $raw_shortcode = '['.$shortcode_tag.' '.implode(' ', $shortcode_parts).']';
505
506 $gallery_url = add_query_arg([
507 'photonic_gallery' => base64_encode($raw_shortcode),
508 'photonic_gallery_title' => $meta['title'],
509 ], get_page_link($photonic_gallery_template_page));
510 return $gallery_url;
511 }
512
513 function ssl_verify_peer(&$handle) {
514 curl_setopt($handle, CURLOPT_SSL_VERIFYPEER, false);
515 }
516
517 function get_server_error() {
518 return sprintf(esc_html__('There was an error connecting to %s. Please try again later.', 'photonic'), $this->provider);
519 }
520
521 /**
522 * Helper execution, implemented by child classes
523 *
524 * @param $args
525 * @return string
526 */
527 function execute_helper($args) {
528 // Blank method, to be overridden by child classes
529 return '';
530 }
531
532 function add_hooks() {
533 // Blank method, implemented by child classes, if required
534 }
535 }
536