| 1 |
<?php |
| 2 |
|
| 3 |
namespace Photonic_Plugin\Platforms; |
| 4 |
|
| 5 |
use Photonic_Plugin\Components\Pagination; |
| 6 |
use Photonic_Plugin\Components\Photo; |
| 7 |
use Photonic_Plugin\Components\Photo_List; |
| 8 |
|
| 9 |
require_once 'Base.php'; |
| 10 |
require_once 'Level_One_Module.php'; |
| 11 |
|
| 12 |
/** |
| 13 |
* Processor for native WP galleries. This extends the Photonic_Plugin\Platforms\Base class and defines methods local to WP. |
| 14 |
*/ |
| 15 |
class Native extends Base implements Level_One_Module { |
| 16 |
protected function __construct() { |
| 17 |
parent::__construct(); |
| 18 |
global $photonic_wp_disable_title_link; |
| 19 |
$this->provider = 'wp'; |
| 20 |
$this->link_lightbox_title = empty($photonic_wp_disable_title_link); |
| 21 |
$this->doc_links = [ |
| 22 |
'general' => 'https://aquoid.com/plugins/photonic/wp-galleries/', |
| 23 |
]; |
| 24 |
} |
| 25 |
|
| 26 |
/** |
| 27 |
* Gets all images associated with the gallery. This method is lifted almost verbatim from the gallery short-code function provided by WP. |
| 28 |
* We will take the gallery images and do some fun stuff with styling them in other methods. We cannot use the WP function because |
| 29 |
* this code is nested within the gallery_shortcode function and we want to tweak that (there is no hook that executes after |
| 30 |
* the gallery has been retrieved.) |
| 31 |
* |
| 32 |
* @param array $attr |
| 33 |
* @return array |
| 34 |
*/ |
| 35 |
public function get_gallery_images($attr = []): array { |
| 36 |
global $post, $photonic_wp_title_caption, $photonic_alternative_shortcode; |
| 37 |
|
| 38 |
$this->push_to_stack('Get Gallery Images'); |
| 39 |
|
| 40 |
// We're trusting author input, so let's at least make sure it looks like a valid orderby statement |
| 41 |
if (isset($attr['orderby'])) { |
| 42 |
$attr['orderby'] = sanitize_sql_orderby($attr['orderby']); |
| 43 |
if (!$attr['orderby']) { |
| 44 |
unset($attr['orderby']); |
| 45 |
} |
| 46 |
} |
| 47 |
|
| 48 |
if (!empty($attr['ids'])) { |
| 49 |
// 'ids' is explicitly ordered, unless you specify otherwise. |
| 50 |
if (empty($attr['orderby'])) { |
| 51 |
$attr['orderby'] = 'post__in'; |
| 52 |
} |
| 53 |
$attr['include'] = $attr['ids']; |
| 54 |
} |
| 55 |
|
| 56 |
$attr = shortcode_atts( |
| 57 |
[ |
| 58 |
'order' => 'ASC', |
| 59 |
'orderby' => 'menu_order ID', |
| 60 |
'id' => $post ? $post->ID : 0, |
| 61 |
'itemtag' => 'figure', |
| 62 |
'icontag' => 'div', |
| 63 |
'captiontag' => 'figcaption', |
| 64 |
'size' => 'thumbnail', |
| 65 |
'include' => '', |
| 66 |
'exclude' => '', |
| 67 |
'link' => '', |
| 68 |
'offset' => 0, |
| 69 |
], |
| 70 |
$attr, |
| 71 |
!empty($photonic_alternative_shortcode) ? $photonic_alternative_shortcode : 'gallery' |
| 72 |
); |
| 73 |
|
| 74 |
$attr['layout'] = $attr['style']; |
| 75 |
$attr['columns'] = !empty($attr['columns']) && ('random' !== $attr['layout'] && 'mosaic' !== $attr['layout']) ? $attr['columns'] : 'auto'; |
| 76 |
$attr['main_size'] = $attr['main_size'] ?? $attr['slide_size']; |
| 77 |
$attr['caption'] = $attr['caption'] ?? $photonic_wp_title_caption; |
| 78 |
|
| 79 |
$attr = array_map( |
| 80 |
function ($item) { |
| 81 |
if (!is_array($item)) { |
| 82 |
return trim($item); |
| 83 |
} |
| 84 |
return $item; |
| 85 |
}, |
| 86 |
$attr |
| 87 |
); |
| 88 |
|
| 89 |
$id = intval($attr['id']); |
| 90 |
if ('RAND' === $attr['order']) { |
| 91 |
$attr['orderby'] = 'none'; |
| 92 |
} |
| 93 |
|
| 94 |
// All arguments can be overridden by the standard pre_get_posts filter ... |
| 95 |
$args = ['post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => ['image'], 'order' => $attr['order'], 'orderby' => $attr['orderby'], 'paged' => $attr['page']]; |
| 96 |
|
| 97 |
$pagination = new Pagination(); |
| 98 |
if (!empty($attr['include'])) { |
| 99 |
$include = preg_replace('/[^0-9,]+/', '', $attr['include']); |
| 100 |
$args['include'] = $include; |
| 101 |
$attr['count'] = -1; // 'include' always ignores the 'posts_per_page'. Having the original value here shows the "More" button even when not required. |
| 102 |
$_attachments = get_posts($args); |
| 103 |
|
| 104 |
$attachments = []; |
| 105 |
foreach ($_attachments as $key => $val) { |
| 106 |
$attachments[$val->ID] = $_attachments[$key]; |
| 107 |
} |
| 108 |
} |
| 109 |
else { |
| 110 |
$args['post_parent'] = $id; |
| 111 |
if (!empty($attr['exclude'])) { |
| 112 |
$exclude = preg_replace('/[^0-9,]+/', '', $attr['exclude']); |
| 113 |
$args['exclude'] = $exclude; |
| 114 |
} |
| 115 |
// First get the total |
| 116 |
$attachments = get_children($args); |
| 117 |
$total_posts = count($attachments); |
| 118 |
|
| 119 |
$args['posts_per_page'] = $attr['count']; |
| 120 |
$attachments = get_children($args); |
| 121 |
|
| 122 |
$pagination->total = $total_posts; |
| 123 |
$pagination->start = ($attr['page'] - 1) * $attr['count']; |
| 124 |
$pagination->end = ($pagination->start + $attr['count']) > $total_posts ? $total_posts : ($pagination->start + $attr['count']); |
| 125 |
$pagination->per_page = $attr['count']; |
| 126 |
} |
| 127 |
|
| 128 |
$ret = $this->process_gallery($attachments, $attr, $pagination); |
| 129 |
$this->pop_from_stack(); |
| 130 |
if (empty($ret)) { // This is needed, because if the stack markup is added, it does not display a gallery |
| 131 |
return []; |
| 132 |
} |
| 133 |
|
| 134 |
if (!empty($this->stack_trace[$this->gallery_index])) { |
| 135 |
$ret[] = $this->stack_trace[$this->gallery_index]; |
| 136 |
} |
| 137 |
return $ret; |
| 138 |
} |
| 139 |
|
| 140 |
public function build_level_1_objects($response, array $short_code, $module_parameters = [], $options = []): array { |
| 141 |
$photo_objects = []; |
| 142 |
$thumb_size = $short_code['thumb_size']; |
| 143 |
$main_size = $short_code['main_size']; |
| 144 |
$tile_size = !empty($short_code['tile_size']) ? $short_code['tile_size'] : $main_size; |
| 145 |
$sources = []; |
| 146 |
$tiles = []; |
| 147 |
$thumbs = []; |
| 148 |
foreach ($response as $id => $attachment) { |
| 149 |
$wp_details = wp_prepare_attachment_for_js($id); |
| 150 |
$sources[$id] = wp_get_attachment_image_src($id, $main_size, true); |
| 151 |
$tiles[$id] = wp_get_attachment_image_src($id, $tile_size, true); |
| 152 |
$thumbs[$id] = wp_get_attachment_image_src($id, $thumb_size, true); |
| 153 |
|
| 154 |
if (isset($attachment->post_title)) { |
| 155 |
$title = wptexturize($attachment->post_title); |
| 156 |
} |
| 157 |
else { |
| 158 |
$title = ''; |
| 159 |
} |
| 160 |
$title = apply_filters('photonic_modify_title', $title, $attachment); |
| 161 |
|
| 162 |
if (is_array($wp_details)) { |
| 163 |
$photo = new Photo(); |
| 164 |
|
| 165 |
$photo->thumbnail = esc_url($thumbs[$id][0]); |
| 166 |
$photo->thumb_size = [ |
| 167 |
'w' => $thumbs[$id][1], |
| 168 |
'h' => $thumbs[$id][2], |
| 169 |
]; |
| 170 |
|
| 171 |
$photo->main_image = esc_url($sources[$id][0]); |
| 172 |
$photo->main_size = [ |
| 173 |
'w' => $sources[$id][1], |
| 174 |
'h' => $sources[$id][2], |
| 175 |
]; |
| 176 |
|
| 177 |
$photo->tile_image = esc_url($tiles[$id][0]); |
| 178 |
$photo->tile_size = [ |
| 179 |
'w' => $tiles[$id][1], |
| 180 |
'h' => $tiles[$id][2], |
| 181 |
]; |
| 182 |
|
| 183 |
$photo->title = wp_kses_post($title); |
| 184 |
$photo->alt_title = esc_attr(($wp_details['alt']) ?: $title); |
| 185 |
$photo->description = wp_kses_post($wp_details['caption']); |
| 186 |
$photo->main_page = empty($short_code['link']) ? esc_url($wp_details['link']) : esc_url($wp_details['url']); |
| 187 |
$photo->id = $wp_details['id']; |
| 188 |
|
| 189 |
if ('video' === $wp_details['type']) { |
| 190 |
$photo->video = esc_url($wp_details['url']); |
| 191 |
} |
| 192 |
|
| 193 |
$photo_objects[] = $photo; |
| 194 |
} |
| 195 |
} |
| 196 |
|
| 197 |
return $photo_objects; |
| 198 |
} |
| 199 |
|
| 200 |
/** |
| 201 |
* Builds the markup for a gallery when you choose to use a specific gallery style. The following styles are allowed: |
| 202 |
* 1. strip-below: Shows thumbnails for the gallery below a larger image |
| 203 |
* 2. strip-above: Shows thumbnails for the gallery above a larger image |
| 204 |
* 3. no-strip: Doesn't show thumbnails. Useful if you are making it behave like an automatic slideshow. |
| 205 |
* 4. launch: Shows a thumbnail for the gallery, which you can click to launch a slideshow. |
| 206 |
* 5. random: Shows a random justified gallery. |
| 207 |
* |
| 208 |
* @param $attachments |
| 209 |
* @param $short_code |
| 210 |
* @return array |
| 211 |
*/ |
| 212 |
private function process_gallery($attachments, $short_code, $pagination): array { |
| 213 |
global $photonic_wp_thumbnail_title_display; |
| 214 |
if ('default' === $short_code['style']) { |
| 215 |
return []; |
| 216 |
} |
| 217 |
$photos = $this->build_level_1_objects($attachments, $short_code); |
| 218 |
|
| 219 |
$row_constraints = [ |
| 220 |
'constraint-type' => 'auto' === $short_code['columns'] ? 'padding' : 'count', |
| 221 |
'padding' => 0, |
| 222 |
'count' => absint($short_code['columns']) ? absint($short_code['columns']) : 3 |
| 223 |
]; |
| 224 |
|
| 225 |
$photo_list = new Photo_List($short_code); |
| 226 |
$photo_list->photos = $photos; |
| 227 |
$photo_list->title_position = $photonic_wp_thumbnail_title_display; |
| 228 |
$photo_list->row_constraints = $row_constraints; |
| 229 |
$photo_list->parent = 'stream'; |
| 230 |
|
| 231 |
// Pagination does not work for native galleries |
| 232 |
$photo_list->pagination = $pagination; |
| 233 |
|
| 234 |
return [$photo_list]; |
| 235 |
} |
| 236 |
} |
| 237 |
|