class-gallery-api.php
4 months ago
class-gallery-base.php
4 months ago
class-gallery-config.php
4 months ago
class-gallery-design.php
4 months ago
class-gallery-field-provider.php
4 months ago
class-gallery-images.php
4 months ago
class-gallery-lightbox.php
4 months ago
class-gallery-misc.php
4 months ago
class-gallery-paging.php
4 months ago
trait-gallery-ajax.php
4 months ago
trait-gallery-duplicate.php
4 months ago
trait-gallery-image-methods.php
2 weeks ago
trait-gallery-preview.php
4 months ago
trait-gallery-sanitize.php
4 months ago
class-gallery-base.php
720 lines
| 1 | <?php |
| 2 | /** |
| 3 | * Responsive Lightbox Gallery Settings Base Class |
| 4 | * |
| 5 | * Abstract base class for gallery post meta settings tabs. |
| 6 | * Adapts Settings API patterns for post meta storage instead of options. |
| 7 | * |
| 8 | * @package Responsive_Lightbox |
| 9 | */ |
| 10 | |
| 11 | // exit if accessed directly |
| 12 | if ( ! defined( 'ABSPATH' ) ) |
| 13 | exit; |
| 14 | |
| 15 | /** |
| 16 | * Responsive_Lightbox_Gallery_Base class. |
| 17 | * |
| 18 | * Base class for gallery settings tabs using post meta storage. |
| 19 | * Extends Settings_Base but overrides storage methods for post meta. |
| 20 | * |
| 21 | * @abstract |
| 22 | * @class Responsive_Lightbox_Gallery_Base |
| 23 | */ |
| 24 | abstract class Responsive_Lightbox_Gallery_Base extends Responsive_Lightbox_Settings_Base { |
| 25 | |
| 26 | /** |
| 27 | * Tab key identifier. |
| 28 | * |
| 29 | * Must be defined in child class. |
| 30 | * |
| 31 | * @var string |
| 32 | */ |
| 33 | const TAB_KEY = ''; |
| 34 | |
| 35 | /** |
| 36 | * Class constructor. |
| 37 | * |
| 38 | * Registers filters for gallery settings integration. |
| 39 | * |
| 40 | * @return void |
| 41 | */ |
| 42 | public function __construct() { |
| 43 | // provide settings data for this tab |
| 44 | add_filter( 'rl_gallery_settings_tabs', [ $this, 'register_tab' ] ); |
| 45 | } |
| 46 | |
| 47 | /** |
| 48 | * Register this tab with the gallery settings system. |
| 49 | * |
| 50 | * @param array $tabs Existing tabs. |
| 51 | * @return array Modified tabs. |
| 52 | */ |
| 53 | public function register_tab( $tabs ) { |
| 54 | $tabs[static::TAB_KEY] = $this; |
| 55 | return $tabs; |
| 56 | } |
| 57 | |
| 58 | /** |
| 59 | * Get tab data for rendering. |
| 60 | * |
| 61 | * Must be implemented by child class. |
| 62 | * Should return array with structure compatible with gallery fields. |
| 63 | * |
| 64 | * @param string $menu_item Optional menu item for tabs with sub-navigation. |
| 65 | * @return array Tab data. |
| 66 | */ |
| 67 | abstract public function get_tab_data( $menu_item = '' ); |
| 68 | |
| 69 | /** |
| 70 | * Provide settings data for Settings API. |
| 71 | * |
| 72 | * Required by base class but not used in gallery context. |
| 73 | * Gallery tabs don't contribute to global settings. |
| 74 | * |
| 75 | * @param array $data Settings data. |
| 76 | * @return array Modified settings data. |
| 77 | */ |
| 78 | public function settings_data( $data ) { |
| 79 | return $data; |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * Get field name for form input. |
| 84 | * |
| 85 | * Adapts Settings API field names to gallery post meta structure. |
| 86 | * |
| 87 | * @param string $tab_id Tab identifier. |
| 88 | * @param string $menu_item Menu item identifier (optional). |
| 89 | * @param string $field_key Field key. |
| 90 | * @return string Form field name. |
| 91 | */ |
| 92 | protected function get_field_name( $tab_id, $menu_item, $field_key ) { |
| 93 | if ( $menu_item ) { |
| 94 | return sprintf( 'rl_gallery[%s][%s][%s]', $tab_id, $menu_item, $field_key ); |
| 95 | } |
| 96 | return sprintf( 'rl_gallery[%s][%s]', $tab_id, $field_key ); |
| 97 | } |
| 98 | |
| 99 | /** |
| 100 | * Render field HTML. |
| 101 | * |
| 102 | * Adapts Settings API field rendering for gallery context. |
| 103 | * |
| 104 | * @param string $field_key Field key. |
| 105 | * @param array $field Field configuration. |
| 106 | * @param mixed $value Current value. |
| 107 | * @param int $post_id Post ID. |
| 108 | * @param string $tab_id Tab ID. |
| 109 | * @param string $menu_item Menu item ID. |
| 110 | * @return string HTML output. |
| 111 | */ |
| 112 | public function render_field_html( $field_key, $field, $value, $post_id, $tab_id, $menu_item ) { |
| 113 | $name = $this->get_field_name( $tab_id, $menu_item, $field_key ); |
| 114 | // Keep legacy ID contract for Images tab (admin-galleries.js relies on #rl-{tab}-{menu}-{field} selectors). |
| 115 | if ( $tab_id === 'images' ) { |
| 116 | $id = sanitize_html_class( 'rl-' . $tab_id . '-' . $menu_item . '-' . $field_key ); |
| 117 | } else { |
| 118 | $id = sanitize_key( $name ); |
| 119 | } |
| 120 | $disabled = ! empty( $field['disabled'] ) ? ' disabled="disabled"' : ''; |
| 121 | |
| 122 | // Handle field types |
| 123 | switch ( $field['type'] ) { |
| 124 | case 'text': |
| 125 | case 'color': |
| 126 | $input_html = sprintf( |
| 127 | '<input type="%s" id="%s" name="%s" value="%s" class="regular-text"%s />', |
| 128 | esc_attr( $field['type'] ), |
| 129 | esc_attr( $id ), |
| 130 | esc_attr( $name ), |
| 131 | esc_attr( $value ), |
| 132 | $disabled |
| 133 | ); |
| 134 | |
| 135 | // Add append text if specified |
| 136 | if ( isset( $field['append'] ) ) { |
| 137 | $input_html .= '<span class="rl-field-append">' . esc_html( $field['append'] ) . '</span>'; |
| 138 | } |
| 139 | |
| 140 | return $input_html; |
| 141 | |
| 142 | case 'number': |
| 143 | $attrs = ''; |
| 144 | if ( isset( $field['min'] ) ) { |
| 145 | $attrs .= ' min="' . esc_attr( $field['min'] ) . '"'; |
| 146 | } |
| 147 | if ( isset( $field['max'] ) ) { |
| 148 | $attrs .= ' max="' . esc_attr( $field['max'] ) . '"'; |
| 149 | } |
| 150 | if ( isset( $field['step'] ) ) { |
| 151 | $attrs .= ' step="' . esc_attr( $field['step'] ) . '"'; |
| 152 | } |
| 153 | |
| 154 | $input_html = sprintf( |
| 155 | '<input type="number" id="%s" name="%s" value="%s" class="small-text"%s%s />', |
| 156 | esc_attr( $id ), |
| 157 | esc_attr( $name ), |
| 158 | esc_attr( $value ), |
| 159 | $attrs, |
| 160 | $disabled |
| 161 | ); |
| 162 | |
| 163 | if ( isset( $field['append'] ) ) { |
| 164 | $input_html .= '<span class="rl-field-append">' . esc_html( $field['append'] ) . '</span>'; |
| 165 | } |
| 166 | |
| 167 | return $input_html; |
| 168 | |
| 169 | case 'textarea': |
| 170 | $class = isset( $field['class'] ) ? $field['class'] : 'large-text'; |
| 171 | return sprintf( |
| 172 | '<textarea id="%s" name="%s" class="%s"%s>%s</textarea>', |
| 173 | esc_attr( $id ), |
| 174 | esc_attr( $name ), |
| 175 | esc_attr( $class ), |
| 176 | $disabled, |
| 177 | esc_textarea( $value ) |
| 178 | ); |
| 179 | |
| 180 | case 'select': |
| 181 | $options = ''; |
| 182 | if ( isset( $field['options'] ) && is_array( $field['options'] ) ) { |
| 183 | foreach ( $field['options'] as $option_value => $option_label ) { |
| 184 | $options .= sprintf( |
| 185 | '<option value="%s" %s>%s</option>', |
| 186 | esc_attr( $option_value ), |
| 187 | selected( $value, $option_value, false ), |
| 188 | esc_html( $option_label ) |
| 189 | ); |
| 190 | } |
| 191 | } |
| 192 | return sprintf( |
| 193 | '<select id="%s" name="%s"%s>%s</select>', |
| 194 | esc_attr( $id ), |
| 195 | esc_attr( $name ), |
| 196 | $disabled, |
| 197 | $options |
| 198 | ); |
| 199 | |
| 200 | case 'checkbox': |
| 201 | $checked_value = false; |
| 202 | if ( is_array( $value ) ) { |
| 203 | $checked_value = in_array( 1, $value, true ) || in_array( '1', $value, true ) || in_array( true, $value, true ); |
| 204 | } else { |
| 205 | $checked_value = ( $value === 1 || $value === '1' || $value === true ); |
| 206 | } |
| 207 | |
| 208 | return sprintf( |
| 209 | '<input type="checkbox" id="%s" name="%s" value="1" %s%s />', |
| 210 | esc_attr( $id ), |
| 211 | esc_attr( $name ), |
| 212 | checked( $checked_value, true, false ), |
| 213 | $disabled |
| 214 | ); |
| 215 | |
| 216 | case 'boolean': |
| 217 | $label = ! empty( $field['label'] ) ? wp_kses_post( $field['label'] ) : ''; |
| 218 | |
| 219 | $html = ''; |
| 220 | if ( empty( $field['disabled'] ) ) { |
| 221 | $html .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="false" />'; |
| 222 | } |
| 223 | |
| 224 | $html .= '<label><input type="checkbox" role="switch" id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '" value="true" ' . checked( (bool) $value, true, false ) . $disabled . ' />' . $label . '</label>'; |
| 225 | |
| 226 | return $html; |
| 227 | |
| 228 | case 'color_picker': |
| 229 | $color_value = is_string( $value ) && $value !== '' ? $value : ( $field['default'] ?? '#000000' ); |
| 230 | $color_value = esc_attr( $color_value ); |
| 231 | $color_name = esc_attr( $name ); |
| 232 | $input_id = esc_attr( $id ); |
| 233 | $input_class = 'small-text rl-color-input'; |
| 234 | $swatch_style = ' style="background-color: ' . $color_value . ';"'; |
| 235 | |
| 236 | return '<div class="rl-color-control">' |
| 237 | . '<input id="' . $input_id . '" type="text" name="' . $color_name . '" value="' . $color_value . '" class="' . esc_attr( $input_class ) . '"' . $disabled . ' />' |
| 238 | . '<button type="button" class="rl-color-swatch"' . $swatch_style . ' aria-label="' . esc_attr__( 'Open color picker', 'responsive-lightbox' ) . '" aria-expanded="false"' . $disabled . '></button>' |
| 239 | . '<div class="rl-color-popover" aria-hidden="true"><hex-color-picker class="rl-hex-color-picker" color="' . $color_value . '"></hex-color-picker></div>' |
| 240 | . '</div>'; |
| 241 | |
| 242 | case 'radio': |
| 243 | $radios = ''; |
| 244 | if ( isset( $field['options'] ) && is_array( $field['options'] ) ) { |
| 245 | $display_type = ! empty( $field['display_type'] ) && in_array( $field['display_type'], [ 'horizontal', 'vertical' ], true ) |
| 246 | ? $field['display_type'] |
| 247 | : 'horizontal'; |
| 248 | $group_classes = 'rl-field-group rl-radio-group ' . $display_type; |
| 249 | $label_class = 'rl-' . sanitize_html_class( $tab_id . '-' . $menu_item . '-' . $field_key ); |
| 250 | $radios .= '<div class="' . esc_attr( $group_classes ) . '">'; |
| 251 | |
| 252 | foreach ( $field['options'] as $option_value => $option_label ) { |
| 253 | $option_id = 'rl-' . $tab_id . '-' . $menu_item . '-' . $field_key . '-' . $option_value; |
| 254 | $option_id = sanitize_html_class( $option_id ); |
| 255 | $radios .= sprintf( |
| 256 | '<label class="%s" for="%s"><input id="%s" type="radio" name="%s" value="%s" %s%s /> %s</label> ', |
| 257 | esc_attr( $label_class ), |
| 258 | esc_attr( $option_id ), |
| 259 | esc_attr( $option_id ), |
| 260 | esc_attr( $name ), |
| 261 | esc_attr( $option_value ), |
| 262 | checked( $value, $option_value, false ), |
| 263 | $disabled, |
| 264 | esc_html( $option_label ) |
| 265 | ); |
| 266 | } |
| 267 | |
| 268 | $radios .= '</div>'; |
| 269 | } |
| 270 | return $radios; |
| 271 | |
| 272 | case 'multiselect': |
| 273 | $options = ''; |
| 274 | $selected_values = is_array( $value ) ? array_map( 'strval', $value ) : []; |
| 275 | |
| 276 | if ( isset( $field['options'] ) && is_array( $field['options'] ) ) { |
| 277 | foreach ( $field['options'] as $option_value => $option_label ) { |
| 278 | // Support grouped options format used by Featured -> Post Term: |
| 279 | // [taxonomy] => [ 'label' => 'Taxonomy Name', 'terms' => [ term_id => term_name ] ]. |
| 280 | if ( is_array( $option_label ) && isset( $option_label['terms'] ) && is_array( $option_label['terms'] ) ) { |
| 281 | $group_label = isset( $option_label['label'] ) && is_scalar( $option_label['label'] ) |
| 282 | ? (string) $option_label['label'] |
| 283 | : (string) $option_value; |
| 284 | $group_options = ''; |
| 285 | |
| 286 | foreach ( $option_label['terms'] as $term_value => $term_label ) { |
| 287 | if ( ! is_scalar( $term_label ) ) |
| 288 | continue; |
| 289 | |
| 290 | $selected = in_array( (string) $term_value, $selected_values, true ) ? 'selected="selected"' : ''; |
| 291 | $group_options .= sprintf( |
| 292 | '<option value="%s" %s>%s</option>', |
| 293 | esc_attr( $term_value ), |
| 294 | $selected, |
| 295 | esc_html( (string) $term_label ) |
| 296 | ); |
| 297 | } |
| 298 | |
| 299 | if ( $group_options !== '' ) { |
| 300 | $options .= sprintf( |
| 301 | '<optgroup label="%s">%s</optgroup>', |
| 302 | esc_attr( $group_label ), |
| 303 | $group_options |
| 304 | ); |
| 305 | } |
| 306 | |
| 307 | continue; |
| 308 | } |
| 309 | |
| 310 | if ( ! is_scalar( $option_label ) ) { |
| 311 | if ( is_array( $option_label ) && isset( $option_label['label'] ) && is_scalar( $option_label['label'] ) ) |
| 312 | $option_label = (string) $option_label['label']; |
| 313 | else |
| 314 | continue; |
| 315 | } |
| 316 | |
| 317 | $selected = in_array( (string) $option_value, $selected_values, true ) ? 'selected="selected"' : ''; |
| 318 | $options .= sprintf( |
| 319 | '<option value="%s" %s>%s</option>', |
| 320 | esc_attr( $option_value ), |
| 321 | $selected, |
| 322 | esc_html( (string) $option_label ) |
| 323 | ); |
| 324 | } |
| 325 | } |
| 326 | return sprintf( |
| 327 | '<select class="select2" id="%s" name="%s[]" multiple="multiple" style="height: 100px;"%s>%s</select>', |
| 328 | esc_attr( $id ), |
| 329 | esc_attr( $name ), |
| 330 | $disabled, |
| 331 | $options |
| 332 | ); |
| 333 | |
| 334 | case 'taxonomy': |
| 335 | return $this->render_taxonomy_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item, $name, $id, $disabled ); |
| 336 | |
| 337 | case 'media_preview': |
| 338 | return $this->render_media_preview_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item ); |
| 339 | |
| 340 | case 'media_library': |
| 341 | return $this->render_media_library_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item, $name ); |
| 342 | |
| 343 | case 'custom': |
| 344 | if ( ! empty( $field['callback'] ) && is_callable( $field['callback'] ) ) { |
| 345 | $callback_args = [ |
| 346 | 'name' => $name, |
| 347 | 'html_id' => $id, |
| 348 | 'value' => $value, |
| 349 | 'field' => $field, |
| 350 | 'field_id' => $field_key, |
| 351 | 'tab_id' => $tab_id, |
| 352 | 'menu_item' => $menu_item, |
| 353 | 'post_id' => $post_id |
| 354 | ]; |
| 355 | |
| 356 | if ( ! empty( $field['callback_args'] ) && is_array( $field['callback_args'] ) ) |
| 357 | $callback_args = array_merge( $callback_args, $field['callback_args'] ); |
| 358 | |
| 359 | return call_user_func( $field['callback'], $callback_args ); |
| 360 | } |
| 361 | |
| 362 | return ''; |
| 363 | |
| 364 | case 'hidden': |
| 365 | $hidden_input = sprintf( |
| 366 | '<input type="hidden" id="%s" name="%s" value="%s" />', |
| 367 | esc_attr( $id ), |
| 368 | esc_attr( $name ), |
| 369 | esc_attr( $value ) |
| 370 | ); |
| 371 | |
| 372 | if ( ! empty( $field['callback'] ) && is_callable( $field['callback'] ) ) { |
| 373 | $callback_args = [ |
| 374 | 'field' => $field_key, |
| 375 | 'tab_id' => $tab_id, |
| 376 | 'menu_item' => $menu_item, |
| 377 | 'value' => $value, |
| 378 | 'post_id' => $post_id |
| 379 | ]; |
| 380 | |
| 381 | $callback_output = ''; |
| 382 | try { |
| 383 | if ( is_array( $field['callback'] ) ) { |
| 384 | $reflection = new ReflectionMethod( $field['callback'][0], $field['callback'][1] ); |
| 385 | } else { |
| 386 | $reflection = new ReflectionFunction( $field['callback'] ); |
| 387 | } |
| 388 | |
| 389 | $callback_output = $reflection->getNumberOfParameters() <= 1 |
| 390 | ? call_user_func( $field['callback'], $callback_args ) |
| 391 | : call_user_func( $field['callback'], $field_key, $field, $value, $post_id, $tab_id, $menu_item ); |
| 392 | } catch ( Exception $e ) { |
| 393 | $callback_output = call_user_func( $field['callback'], $field_key, $field, $value, $post_id, $tab_id, $menu_item ); |
| 394 | } |
| 395 | |
| 396 | $allowed_html = [ |
| 397 | 'span' => [ |
| 398 | 'id' => true, |
| 399 | 'class' => true, |
| 400 | 'data-provider' => true, |
| 401 | 'data-name' => true, |
| 402 | 'data-value' => true |
| 403 | ] |
| 404 | ]; |
| 405 | |
| 406 | return $hidden_input . wp_kses( (string) $callback_output, $allowed_html ); |
| 407 | } |
| 408 | |
| 409 | return $hidden_input; |
| 410 | |
| 411 | case 'notice': |
| 412 | $content = ! empty( $field['content'] ) ? wp_kses_post( $field['content'] ) : ''; |
| 413 | $class = ! empty( $field['class'] ) ? ' ' . esc_attr( $field['class'] ) : ''; |
| 414 | return '<div class="rl-field-notice' . $class . '">' . $content . '</div>'; |
| 415 | |
| 416 | default: |
| 417 | // Allow add-ons to provide custom rendering for unrecognized field types. |
| 418 | // Returns empty string by default; non-empty return replaces text input fallback. |
| 419 | $custom_output = apply_filters( 'rl_gallery_render_field', '', $field_key, $field, $value, $post_id, $tab_id, $menu_item, $name, $id ); |
| 420 | |
| 421 | if ( $custom_output !== '' ) { |
| 422 | return $custom_output; |
| 423 | } |
| 424 | |
| 425 | // Unknown field types: render as text input. |
| 426 | return sprintf( |
| 427 | '<input type="text" id="%s" name="%s" value="%s" class="regular-text" />', |
| 428 | esc_attr( $id ), |
| 429 | esc_attr( $name ), |
| 430 | esc_attr( $value ) |
| 431 | ); |
| 432 | } |
| 433 | } |
| 434 | |
| 435 | /** |
| 436 | * Render a taxonomy dropdown field. |
| 437 | * |
| 438 | * Used by the Images tab 'folders' menu item for media folder selection. |
| 439 | * |
| 440 | * @param string $field_key Field key. |
| 441 | * @param array $field Field configuration. |
| 442 | * @param mixed $value Current value (array with 'id' and 'children' keys). |
| 443 | * @param int $post_id Post ID. |
| 444 | * @param string $tab_id Tab ID. |
| 445 | * @param string $menu_item Menu item ID. |
| 446 | * @param string $name Input name. |
| 447 | * @param string $id Input id. |
| 448 | * @param string $disabled Disabled attribute string. |
| 449 | * @return string HTML output. |
| 450 | */ |
| 451 | private function render_taxonomy_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item, $name, $id, $disabled ) { |
| 452 | $html = ''; |
| 453 | $taxonomy = isset( $field['taxonomy'] ) ? $field['taxonomy'] : ''; |
| 454 | $value_id = is_array( $value ) && isset( $value['id'] ) ? $value['id'] : 0; |
| 455 | $value_children = is_array( $value ) && isset( $value['children'] ) ? $value['children'] : false; |
| 456 | |
| 457 | if ( $taxonomy && taxonomy_exists( $taxonomy ) ) { |
| 458 | $html = wp_dropdown_categories( [ |
| 459 | 'orderby' => 'name', |
| 460 | 'order' => 'asc', |
| 461 | 'show_option_none' => __( 'Root Folder', 'responsive-lightbox' ), |
| 462 | 'show_option_all' => false, |
| 463 | 'show_count' => false, |
| 464 | 'hide_empty' => false, |
| 465 | 'option_none_value' => 0, |
| 466 | 'hierarchical' => true, |
| 467 | 'selected' => $value_id, |
| 468 | 'taxonomy' => $taxonomy, |
| 469 | 'hide_if_empty' => false, |
| 470 | 'echo' => false, |
| 471 | 'id' => $id, |
| 472 | 'name' => $name . '[id]' |
| 473 | ] ); |
| 474 | } else { |
| 475 | $html = '<select id="' . esc_attr( $id ) . '" name="' . esc_attr( $name ) . '[]"><option value="0">' . esc_html__( 'Root Folder', 'responsive-lightbox' ) . '</option></select> '; |
| 476 | } |
| 477 | |
| 478 | if ( $disabled ) { |
| 479 | $html = preg_replace( '/<select /', '<select disabled="disabled" ', $html, 1 ); |
| 480 | } |
| 481 | |
| 482 | if ( ! empty( $field['include_children'] ) ) { |
| 483 | $children_id = esc_attr( $id . '-include-children' ); |
| 484 | |
| 485 | $html .= '<label class="' . esc_attr( $id ) . '-include-children" for="' . $children_id . '"><input id="' . $children_id . '" type="checkbox" name="' . esc_attr( $name ) . '[children]" value="true" ' . checked( $value_children, true, false ) . $disabled . ' />' . esc_html__( 'Include children.', 'responsive-lightbox' ) . '</label>'; |
| 486 | } |
| 487 | |
| 488 | return $html; |
| 489 | } |
| 490 | |
| 491 | /** |
| 492 | * Render a media preview field. |
| 493 | * |
| 494 | * Used by Images tab menu items (featured, posts, folders, remote_library) |
| 495 | * to display a gallery preview with update button and pagination. |
| 496 | * |
| 497 | * @param string $field_key Field key. |
| 498 | * @param array $field Field configuration. |
| 499 | * @param mixed $value Current value (array with 'exclude' key). |
| 500 | * @param int $post_id Post ID. |
| 501 | * @param string $tab_id Tab ID. |
| 502 | * @param string $menu_item Menu item ID. |
| 503 | * @return string HTML output. |
| 504 | */ |
| 505 | private function render_media_preview_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item ) { |
| 506 | $rl = Responsive_Lightbox(); |
| 507 | |
| 508 | if ( ! isset( $rl->galleries ) ) |
| 509 | return ''; |
| 510 | |
| 511 | $galleries = $rl->galleries; |
| 512 | |
| 513 | // set menu_item so get_gallery_images() uses the correct image source |
| 514 | $galleries->set_menu_item( $menu_item ); |
| 515 | |
| 516 | // get images |
| 517 | $images = $galleries->get_gallery_images( $post_id ); |
| 518 | |
| 519 | // get media item template |
| 520 | $preview = isset( $field['preview'] ) ? $field['preview'] : []; |
| 521 | $media_item_template = $galleries->get_media_item_template( $preview ); |
| 522 | |
| 523 | $html = ' |
| 524 | <div class="rl-gallery-preview-inside"> |
| 525 | <a href="#" class="rl-gallery-update-preview button button-secondary">' . esc_html__( 'Update preview', 'responsive-lightbox' ) . '</a><span class="spinner" style="display: none;"></span> |
| 526 | <p class="description">' . esc_html__( 'Use this button after any change of the options below to see updated gallery preview.', 'responsive-lightbox' ) . '</p> |
| 527 | </div> |
| 528 | <div class="rl-gallery-content"> |
| 529 | <ul class="rl-gallery-images rl-gallery-images-' . esc_attr( $menu_item ) . '">'; |
| 530 | |
| 531 | $exclude = []; |
| 532 | if ( is_array( $value ) && isset( $value['exclude'] ) ) { |
| 533 | if ( is_array( $value['exclude'] ) ) { |
| 534 | $exclude = $value['exclude']; |
| 535 | } elseif ( is_string( $value['exclude'] ) && $value['exclude'] !== '' ) { |
| 536 | $exclude = array_filter( array_map( 'trim', explode( ',', $value['exclude'] ) ), 'strlen' ); |
| 537 | } |
| 538 | } |
| 539 | |
| 540 | if ( ! empty( $images ) ) { |
| 541 | foreach ( $images as $image ) { |
| 542 | if ( empty( $image['id'] ) ) { |
| 543 | $excluded_item = $image['url']; |
| 544 | $image['id'] = 0; |
| 545 | } else |
| 546 | $excluded_item = $image['id']; |
| 547 | |
| 548 | // get image content html |
| 549 | $html .= $galleries->get_gallery_preview_image_content( $image, $tab_id, $menu_item, $field_key, $media_item_template, $exclude, $excluded_item ); |
| 550 | } |
| 551 | } |
| 552 | |
| 553 | $html .= ' |
| 554 | </ul> |
| 555 | </div>'; |
| 556 | |
| 557 | if ( ! empty( $preview ) && isset( $preview['pagination'] ) && $preview['pagination'] ) |
| 558 | $html .= $galleries->get_preview_pagination(); |
| 559 | |
| 560 | return $html; |
| 561 | } |
| 562 | |
| 563 | /** |
| 564 | * Render a media library field. |
| 565 | * |
| 566 | * Used by the Images tab 'media' menu item for image/video selection, |
| 567 | * drag-and-drop reordering, and embed video management. |
| 568 | * |
| 569 | * @param string $field_key Field key. |
| 570 | * @param array $field Field configuration. |
| 571 | * @param mixed $value Current value (array with 'ids', 'exclude', 'embed' keys). |
| 572 | * @param int $post_id Post ID. |
| 573 | * @param string $tab_id Tab ID. |
| 574 | * @param string $menu_item Menu item ID. |
| 575 | * @param string $name Input name. |
| 576 | * @return string HTML output. |
| 577 | */ |
| 578 | private function render_media_library_field( $field_key, $field, $value, $post_id, $tab_id, $menu_item, $name ) { |
| 579 | $rl = Responsive_Lightbox(); |
| 580 | |
| 581 | if ( ! isset( $rl->galleries ) ) |
| 582 | return ''; |
| 583 | |
| 584 | $galleries = $rl->galleries; |
| 585 | $data = get_post_meta( $post_id, '_rl_images', true ); |
| 586 | $data = is_array( $data ) ? $data : []; |
| 587 | |
| 588 | // load images only when saved menu_item is 'media' or we're not doing an AJAX menu switch |
| 589 | if ( ( ! empty( $data['menu_item'] ) && $data['menu_item'] === 'media' ) || ! ( wp_doing_ajax() && isset( $_POST['action'] ) && $_POST['action'] === 'rl-get-menu-content' ) ) |
| 590 | $images = $galleries->get_gallery_images( $post_id ); |
| 591 | else |
| 592 | $images = []; |
| 593 | |
| 594 | // get media item template |
| 595 | $preview = isset( $field['preview'] ) ? $field['preview'] : []; |
| 596 | $media_item_template = $galleries->get_media_item_template( $preview ); |
| 597 | |
| 598 | // build buttons |
| 599 | $buttons = []; |
| 600 | $buttons_desc = ''; |
| 601 | |
| 602 | // video support? |
| 603 | if ( rl_current_lightbox_supports( 'video' ) ) { |
| 604 | $buttons[] = '<a href="#" class="rl-gallery-select button button-secondary">' . __( 'Select images & videos', 'responsive-lightbox' ) . '</a>'; |
| 605 | } else { |
| 606 | $buttons[] = '<a href="#" class="rl-gallery-select button button-secondary">' . __( 'Select images', 'responsive-lightbox' ) . '</a>'; |
| 607 | $buttons[] = '<a href="#" class="rl-gallery-select button button-disabled" disabled="true">' . __( 'Select images & videos', 'responsive-lightbox' ) . '</a>'; |
| 608 | $buttons_desc_args = [ '<a href="http://www.dfactory.co/products/fancybox-pro/" target="_blank">Fancybox Pro</a>', '<a href="http://www.dfactory.co/products/lightgallery-lightbox/" target="_blank">Lightgallery Lightbox</a>', '<a href="http://www.dfactory.co/products/lightcase-lightbox/" target="_blank">Lightcase Lightbox</a>' ]; |
| 609 | $buttons_desc = '<p class="description">' . wp_sprintf( __( 'HTML5 Videos and Embed Videos available only in %l.', 'responsive-lightbox' ), $buttons_desc_args ) . '</p>'; |
| 610 | } |
| 611 | |
| 612 | // hidden IDs input |
| 613 | $ids = []; |
| 614 | if ( is_array( $value ) && isset( $value['ids'] ) ) { |
| 615 | if ( is_array( $value['ids'] ) ) { |
| 616 | $ids = $value['ids']; |
| 617 | } elseif ( is_string( $value['ids'] ) && $value['ids'] !== '' ) { |
| 618 | $ids = array_filter( array_map( 'trim', explode( ',', $value['ids'] ) ), 'strlen' ); |
| 619 | } |
| 620 | } |
| 621 | $ids_value = implode( ',', $ids ); |
| 622 | |
| 623 | $html = ' |
| 624 | <input type="hidden" class="rl-gallery-ids" name="' . esc_attr( $name ) . '[ids]" value="' . esc_attr( $ids_value ) . '">'; |
| 625 | |
| 626 | // embed video support? |
| 627 | if ( rl_current_lightbox_supports( [ 'youtube', 'vimeo' ], 'OR' ) ) |
| 628 | $buttons[] = '<a href="#" class="rl-gallery-select-videos button button-secondary">' . esc_html__( 'Embed videos', 'responsive-lightbox' ) . '</a>'; |
| 629 | else |
| 630 | $buttons[] = '<a href="#" class="rl-gallery-select-videos button button-disabled" disabled="true">' . esc_html__( 'Embed videos', 'responsive-lightbox' ) . '</a>'; |
| 631 | |
| 632 | // buttons container |
| 633 | $html .= ' |
| 634 | <div class="rl-gallery-buttons">' |
| 635 | . implode( '', $buttons ) |
| 636 | . $buttons_desc . |
| 637 | '</div>'; |
| 638 | |
| 639 | // gallery content |
| 640 | $html .= ' |
| 641 | <div class="rl-gallery-content"> |
| 642 | <ul class="rl-gallery-images rl-gallery-images-media">'; |
| 643 | |
| 644 | $exclude = []; |
| 645 | if ( is_array( $value ) && isset( $value['exclude'] ) ) { |
| 646 | if ( is_array( $value['exclude'] ) ) { |
| 647 | $exclude = $value['exclude']; |
| 648 | } elseif ( is_string( $value['exclude'] ) && $value['exclude'] !== '' ) { |
| 649 | $exclude = array_filter( array_map( 'trim', explode( ',', $value['exclude'] ) ), 'strlen' ); |
| 650 | } |
| 651 | } |
| 652 | |
| 653 | if ( ! empty( $images ) ) { |
| 654 | foreach ( $images as $image ) { |
| 655 | if ( $image['id'] === 0 ) |
| 656 | $excluded_item = $image['url']; |
| 657 | else |
| 658 | $excluded_item = $image['id']; |
| 659 | |
| 660 | // get image content html |
| 661 | $html .= $galleries->get_gallery_preview_image_content( $image, $tab_id, $menu_item, $field_key, $media_item_template, $exclude, $excluded_item ); |
| 662 | } |
| 663 | } |
| 664 | |
| 665 | $html .= ' |
| 666 | </ul> |
| 667 | </div>'; |
| 668 | |
| 669 | return $html; |
| 670 | } |
| 671 | |
| 672 | /** |
| 673 | * Check whether a field type self-manages its description output. |
| 674 | * |
| 675 | |
| 676 | * Sanitize fields for this tab. |
| 677 | * |
| 678 | * Uses base class sanitization but adapted for post meta context. |
| 679 | * |
| 680 | * @param array $input Input data. |
| 681 | * @param string $tab_id Tab identifier. |
| 682 | * @param string $menu_item Menu item identifier. |
| 683 | * @return array Sanitized data. |
| 684 | */ |
| 685 | public function sanitize_tab_fields( $input, $tab_id, $menu_item = '' ) { |
| 686 | $fields = $this->get_tab_data(); |
| 687 | |
| 688 | if ( $menu_item && isset( $fields[$menu_item] ) ) { |
| 689 | $fields = $fields[$menu_item]; |
| 690 | } |
| 691 | |
| 692 | return $this->sanitize_fields( $input, $tab_id, $fields ); |
| 693 | } |
| 694 | |
| 695 | /** |
| 696 | * Validate settings for this tab (base signature compatibility). |
| 697 | * |
| 698 | * @param array $input Sanitized data. |
| 699 | * @return array Validated data. |
| 700 | */ |
| 701 | public function validate( $input ) { |
| 702 | return is_array( $input ) ? $input : []; |
| 703 | } |
| 704 | |
| 705 | /** |
| 706 | * Validate tab data after sanitization for gallery context. |
| 707 | * |
| 708 | * Child classes can override to enforce tab-specific validation rules. |
| 709 | * |
| 710 | * @param array $input Sanitized data for the current tab/menu item. |
| 711 | * @param string $tab_id Tab identifier. |
| 712 | * @param string $menu_item Menu item identifier. |
| 713 | * @param int $post_id Post ID. |
| 714 | * @return array Validated data. |
| 715 | */ |
| 716 | public function validate_tab( $input, $tab_id, $menu_item = '', $post_id = 0 ) { |
| 717 | return is_array( $input ) ? $input : []; |
| 718 | } |
| 719 | } |
| 720 |