<?php // exit if accessed directly if ( ! defined( 'ABSPATH' ) ) exit; /** * Responsive Lightbox Galleries class. * * @class Responsive_Lightbox_Galleries */ class Responsive_Lightbox_Galleries { public $fields; private $tabs; private $sizes; private $gallery_args; private $menu_item; private $revision_id; private $allowed_select_html = [ 'select' => [ 'name' => true, 'id' => true, 'class' => true, 'required' => true, 'tabindex' => true, 'aria-describedby' => true ], 'option' => [ 'value' => true, 'class' => true, 'selected' => true ] ]; /** * Class constructor. * * @param bool $read_only Whether is it read only mode * @return void */ public function __construct( $read_only = false ) { // set instance Responsive_Lightbox()->galleries = $this; if ( $read_only ) return; // actions add_action( 'init', array( $this, 'init' ), 11 ); add_action( 'admin_init', array( $this, 'init_admin' ) ); add_action( 'current_screen', array( $this, 'clear_metaboxes' ) ); add_action( 'edit_form_after_title', array( $this, 'after_title_nav_menu' ) ); add_action( 'admin_footer', array( $this, 'modal_gallery_template' ) ); add_action( 'customize_controls_print_footer_scripts', array( $this, 'modal_gallery_template' ) ); add_action( 'media_buttons', array( $this, 'add_gallery_button' ) ); add_action( 'add_meta_boxes_rl_gallery', array( $this, 'add_meta_boxes' ) ); add_action( 'save_post_rl_gallery', array( $this, 'save_post' ), 10, 3 ); add_action( 'manage_rl_gallery_posts_custom_column', array( $this, 'gallery_columns_content' ), 10, 2 ); add_action( 'admin_action_duplicate_gallery', array( $this, 'duplicate_gallery' ) ); add_action( 'wp_ajax_rl-get-menu-content', array( $this, 'get_menu_content' ) ); add_action( 'wp_ajax_rl-get-preview-content', array( $this, 'get_gallery_preview_content' ) ); add_action( 'wp_ajax_rl-post-get-galleries', array( $this, 'post_get_galleries' ) ); add_action( 'wp_ajax_rl-post-gallery-preview', array( $this, 'post_gallery_preview' ) ); add_action( 'wp_ajax_rl-get-gallery-page-content', array( $this, 'get_gallery_page' ) ); add_action( 'wp_ajax_nopriv_rl-get-gallery-page-content', array( $this, 'get_gallery_page' ) ); add_action( '_wp_put_post_revision', array( $this, 'save_revision' ) ); add_action( 'delete_attachment', array( $this, 'delete_attachment' ) ); add_action( 'shutdown', array( $this, 'shutdown_preview' ) ); add_action( 'wp_loaded', array( $this, 'maybe_change_lightbox' ), 1 ); // filters add_filter( 'manage_rl_gallery_posts_columns', array( $this, 'gallery_columns' ) ); add_filter( 'admin_post_thumbnail_html', array( $this, 'admin_post_thumbnail_html' ), 10, 3 ); add_filter( 'post_thumbnail_html', array( $this, 'post_thumbnail_html' ), 10, 5 ); add_filter( 'preview_post_link', array( $this, 'preview_post_link' ) ); add_filter( 'post_row_actions', array( $this, 'post_row_actions_duplicate' ), 10, 2 ); if ( ! empty( $_POST['rl_active_tab'] ) ) add_filter( 'redirect_post_location', array( $this, 'add_active_tab' ) ); } /** * Get class data. * * @param string $attr * @return mixed */ public function get_data( $attr ) { return property_exists( $this, $attr ) ? $this->{$attr} : null; } /** * Get default gallery single image template. * * @param array $args Template arguments * @return string */ public function get_media_item_template( $args = [] ) { $args = array_merge( array( 'draggable' => false, 'editable' => false, 'removable' => false, 'changeable' => false ), $args ); return ' <li class="rl-gallery-image__MEDIA_STATUS__" data-attachment_id="__MEDIA_ID__" data-type="__MEDIA_TYPE__"' . ( $args['draggable'] ? ' style="cursor: move;"' : '' ) . '> <div class="rl-gallery-inner"> <div class="centered"> __MEDIA_DATA__ </div> </div> <div class="rl-gallery-actions">' . ( $args['changeable'] ? '<a href="#" class="rl-gallery-image-status dashicons dashicons-marker" title="' . esc_attr__( 'Status', 'responsive-lightbox' ) . '"></a>' : '' ) . ( $args['editable'] ? '<a href="#" class="rl-gallery-image-edit dashicons dashicons-edit" title="' . esc_attr__( 'Edit image', 'responsive-lightbox' ) . '"></a>' : '' ) . ( $args['removable'] ? '<a href="#" class="rl-gallery-image-remove dashicons dashicons-no" title="' . esc_attr__( 'Remove image', 'responsive-lightbox' ) . '"></a>' : '' ) . ' </div> </li>'; } /** * Get default gallery embed template. * * @param bool $js * @return string */ public function get_media_embed_template( $js = false ) { $html = ''; if ( $js ) $html .= '<div data-id="__EMBED_ID__" style="display: none;">'; $html .= ' <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][url]" data-type="url" value="__EMBED_URL__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][width]" data-type="width" value="__EMBED_WIDTH__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][height]" data-type="height" value="__EMBED_HEIGHT__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][thumbnail_url]" data-type="thumbnail_url" value="__EMBED_THUMBNAIL_URL__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][thumbnail_width]" data-type="thumbnail_width" value="__EMBED_THUMBNAIL_WIDTH__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][thumbnail_height]" data-type="thumbnail_height" value="__EMBED_THUMBNAIL_HEIGHT__"> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][title]" data-type="title" value="__EMBED_TITLE__"> <textarea class="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][caption]" data-type="caption">__EMBED_DESCRIPTION__</textarea> <input type="hidden" name="rl_gallery[images][media][attachments][embed][__EMBED_ID__][date]" data-type="date" value="__EMBED_DATE__">'; if ( $js ) $html .= '</div>'; return $html; } /** * Get default gallery exclude input template. * * @param string $tab_id * @param string $menu_item * @param string $field_name * @param mixed $excluded_value * @return string */ public function get_media_exclude_input_template( $tab_id = '', $menu_item = '', $field_name = '', $excluded_value = '' ) { $template = '<input type="hidden" class="rl-gallery-exclude" name="rl_gallery[__MEDIA_TAB_ID__][__MEDIA_MENU_ITEM__][__MEDIA_FIELD_NAME__][exclude][]" value="__MEDIA_FIELD_VALUE__" />'; if ( $tab_id === '' && $menu_item === '' && $field_name === '' && $excluded_value === '' ) return str_replace( '__MEDIA_FIELD_VALUE__', '', $template ); return str_replace( [ '__MEDIA_TAB_ID__', '__MEDIA_MENU_ITEM__', '__MEDIA_FIELD_NAME__', '__MEDIA_FIELD_VALUE__' ], [ esc_attr( $tab_id ), esc_attr( $menu_item ), esc_attr( $field_name ), empty( $excluded_value ) ? '' : esc_attr( $excluded_value ) ], $template ); } /** * Load needed data. * * @return void */ public function init() { // register shortcode add_shortcode( 'rl_gallery', array( $this, 'gallery_shortcode' ) ); // get main instance $rl = Responsive_Lightbox(); // set lightbox script for infinite scroll pages if ( isset( $_GET['rl_gallery_no'], $_GET['rl_page'], $_GET['rl_lightbox_script'] ) ) $rl->set_lightbox_script( sanitize_key( $_GET['rl_lightbox_script'] ) ); $config_menu_items = apply_filters( 'rl_gallery_types', $rl->get_data( 'gallery_types' ) ); $config_menu_items['default'] = __( 'Global', 'responsive-lightbox' ); // set tabs $this->tabs = apply_filters( 'rl_gallery_tabs', array( 'images' => array( 'label' => __( 'Images', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust the contents of the gallery.', 'responsive-lightbox' ), 'menu_items' => array( 'media' => __( 'Media Library', 'responsive-lightbox' ), 'featured' => __( 'Featured Content', 'responsive-lightbox' ) ) ), 'config' => array( 'label' => __( 'Config', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust the configuration options for the gallery.', 'responsive-lightbox' ), 'menu_items' => $config_menu_items ), 'design' => array( 'label' => __( 'Design', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust the gallery design options.', 'responsive-lightbox' ) ), 'paging' => array( 'label' => __( 'Paging', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust the gallery pagination options.', 'responsive-lightbox' ) ), 'lightbox' => array( 'label' => __( 'Lightbox', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust the lightbox options.', 'responsive-lightbox' ), ), 'misc' => array( 'label' => __( 'Misc', 'responsive-lightbox' ), 'description' => __( 'The settings below adjust miscellaneous options.', 'responsive-lightbox' ), ) ) ); // add folders if active $this->tabs['images']['menu_items']['folders'] = __( 'Media Folders', 'responsive-lightbox' ); // add remote library if active $this->tabs['images']['menu_items']['remote_library'] = __( 'Remote Library', 'responsive-lightbox' ); // use sizes as keys and values $this->sizes = $this->get_image_sizes(); $sizes = array_combine( array_keys( $this->sizes ), array_keys( $this->sizes ) ); // add default, custom and full image size $sizes['full'] = __( 'Full size', 'responsive-lightbox' ); $sizes['global'] = __( 'Global', 'responsive-lightbox' ); $sizes['rl_custom_size'] = __( 'Custom size', 'responsive-lightbox' ); // positions $positions = array( 'none' => __( 'None', 'responsive-lightbox' ), 'top' => __( 'Top', 'responsive-lightbox' ), 'bottom' => __( 'Bottom', 'responsive-lightbox' ) ); // merge titles $merged_titles = array( 'global' => __( 'Global', 'responsive-lightbox' ) ) + $rl->settings->get_data( 'image_titles' ); // set fields $this->fields = apply_filters( 'rl_gallery_tab_fields', array( 'images' => array( 'media' => array( 'attachments' => array( 'title' => '', 'type' => 'media_library', 'default' => array( 'ids' => [], 'exclude' => [], 'embed' => [] ), 'preview' => array( 'pagination' => true, 'draggable' => true, 'editable' => true, 'removable' => true, 'changeable' => true ) ) ), 'featured' => array( 'attachments' => array( 'title' => '', 'type' => 'media_preview', 'default' => array( 'exclude' => [] ), 'preview' => array( 'pagination' => true, 'draggable' => false, 'editable' => true, 'removable' => false, 'changeable' => false ) ), 'number_of_posts' => array( 'title' => __( 'Number of Posts', 'responsive-lightbox' ), 'type' => 'number', 'description' => __( 'Enter the number of posts.', 'responsive-lightbox' ), 'default' => 10, 'min' => 0 ), 'orderby' => array( 'title' => __( 'Posts Sorting', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select the posts sorting.', 'responsive-lightbox' ), 'default' => 'date', 'options' => array( 'id' => __( 'ID', 'responsive-lightbox' ), 'author' => __( 'Author', 'responsive-lightbox' ), 'title' => __( 'Title', 'responsive-lightbox' ), 'name' => __( 'Slug', 'responsive-lightbox' ), 'date' => __( 'Date', 'responsive-lightbox' ), 'modified' => __( 'Last modified date', 'responsive-lightbox' ), 'parent' => __( 'Parent ID', 'responsive-lightbox' ), 'rand' => __( 'Random', 'responsive-lightbox' ) ) ), 'order' => array( 'title' => __( 'Posts Order', 'responsive-lightbox' ), 'type' => 'radio', 'description' => __( 'Select the posts order.', 'responsive-lightbox' ), 'default' => 'asc', 'options' => array( 'asc' => __( 'Ascending', 'responsive-lightbox' ), 'desc' => __( 'Descending', 'responsive-lightbox' ) ) ), 'offset' => array( 'title' => __( 'Posts Offset', 'responsive-lightbox' ), 'type' => 'number', 'description' => __( 'Enter the posts offset.', 'responsive-lightbox' ), 'default' => 0, 'min' => 0 ), 'image_source' => array( 'title' => __( 'Image Source', 'responsive-lightbox' ), 'type' => 'radio', 'description' => __( 'Select the image source.', 'responsive-lightbox' ), 'default' => 'thumbnails', 'options' => array( 'thumbnails' => __( 'Post Thumbnails', 'responsive-lightbox' ), 'attached_images' => __( 'Post Attached Images', 'responsive-lightbox' ) ) ), 'images_per_post' => array( 'title' => __( 'Images per Post', 'responsive-lightbox' ), 'type' => 'number', 'description' => __( 'Enter maximum number of images for a post.', 'responsive-lightbox' ), 'default' => 1, 'min' => 1 ), 'post_type' => array( 'title' => __( 'Post Type', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post types to query.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'post_status' => array( 'title' => __( 'Post Status', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post status.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'post_format' => array( 'title' => __( 'Post Format', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post format.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'post_term' => array( 'title' => __( 'Post Term', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post taxonomy terms to query.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'post_author' => array( 'title' => __( 'Post Author', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post author.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'page_parent' => array( 'title' => __( 'Page Parent', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the post parent.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ), 'page_template' => array( 'title' => __( 'Page Template', 'responsive-lightbox' ), 'type' => 'multiselect', 'description' => __( 'Select the page template.', 'responsive-lightbox' ), 'options' => [], 'default' => [] ) ), 'folders' => array( 'attachments' => array( 'title' => '', 'type' => 'media_preview', 'default' => array( 'exclude' => [] ), 'preview' => array( 'pagination' => true, 'draggable' => false, 'editable' => true, 'removable' => false, 'changeable' => false ) ), 'folder' => array( 'title' => __( 'Media Folder', 'responsive-lightbox' ), 'type' => 'taxonomy', 'description' => __( 'Select media folder.', 'responsive-lightbox' ), 'default' => array( 'id' => 0, 'children' => false ), 'include_children' => true, 'taxonomy' => $rl->options['folders']['media_taxonomy'] ) ), 'remote_library' => array( 'attachments' => array( 'title' => '', 'type' => 'media_preview', 'default' => array( 'exclude' => [] ), 'preview' => array( 'pagination' => true, 'draggable' => false, 'editable' => false, 'removable' => false, 'changeable' => false ) ), 'media_search' => array( 'title' => __( 'Search string', 'responsive-lightbox' ), 'type' => 'text', 'description' => __( 'Enter the search phrase.', 'responsive-lightbox' ), 'default' => '' ), 'media_provider' => array( 'title' => __( 'Media Providers', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select which remote library should be used.', 'responsive-lightbox' ), 'default' => 'all', 'options' => array( 'all' => __( 'All Media Providers', 'responsive-lightbox' ) ) ), 'response_data' => array( 'title' => '', 'type' => 'hidden', 'description' => '', 'default' => '', 'callback' => array( $rl->remote_library, 'remote_library_response_data' ) ) ) ), 'config' => [], 'design' => array( 'options' => array( 'design_show_title' => array( 'title' => __( 'Thumbnail title', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select title for the gallery thumbnails.', 'responsive-lightbox' ), 'default' => 'global', 'options' => $merged_titles ), 'design_show_caption' => array( 'title' => __( 'Thumbnail caption', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select caption for the gallery thumbnails.', 'responsive-lightbox' ), 'default' => 'global', 'options' => $merged_titles ), 'show_icon' => array( 'title' => __( 'Thumbnail icon', 'responsive-lightbox' ), 'type' => 'radio', 'description' => __( 'Select icon for the gallery thumbnails.', 'responsive-lightbox' ), 'default' => '0', 'options' => array( '0' => __( 'none', 'responsive-lightbox' ), '1' => '', '2' => '', '3' => '', '4' => '', '5' => '', '6' => '', '7' => '', '8' => '', '9' => '', '10' => '' ) ), 'hover_effect' => array( 'title' => __( 'Hover effect', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select thumbnail effect on hover.', 'responsive-lightbox' ), 'default' => '0', 'options' => array( '0' => __( 'none', 'responsive-lightbox' ), '1' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 1 ), '2' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 2 ), '3' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 3 ), '4' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 4 ), '5' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 5 ), '6' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 6 ), '7' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 7 ), '8' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 8 ), '9' => sprintf( __( 'Effect %s', 'responsive-lightbox' ), 9 ) ) ), 'title_color' => array( 'title' => __( 'Title Color', 'responsive-lightbox' ), 'type' => 'color_picker', 'default' => '#ffffff' ), 'caption_color' => array( 'title' => __( 'Caption Color', 'responsive-lightbox' ), 'type' => 'color_picker', 'default' => '#cccccc' ), 'background_color' => array( 'title' => __( 'Background Color', 'responsive-lightbox' ), 'type' => 'color_picker', 'default' => '#000000' ), 'background_opacity' => array( 'title' => __( 'Background Opacity', 'responsive-lightbox' ), 'type' => 'number', 'default' => 80, 'step' => 1, 'min' => 0, 'max' => 100, 'append' => '%' ), 'border_color' => array( 'title' => __( 'Border Color', 'responsive-lightbox' ), 'type' => 'color_picker', 'default' => '#000000' ), 'border_width' => array( 'title' => __( 'Border Width', 'responsive-lightbox' ), 'type' => 'number', 'default' => 0, 'step' => 1, 'min' => 0, 'max' => 100, 'append' => 'px' ) ) ), 'paging' => array( 'options' => array( 'pagination' => array( 'title' => __( 'Use pagination', 'responsive-lightbox' ), 'type' => 'boolean', 'label' => __( 'Enable pagination.', 'responsive-lightbox' ), 'default' => false ), 'pagination_type' => array( 'title' => __( 'Pagination type', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select pagination type.', 'responsive-lightbox' ), 'default' => 'paged', 'options' => array( 'paged' => __( 'standard', 'responsive-lightbox' ), 'ajax' => __( 'AJAX', 'responsive-lightbox' ), 'infinite' => __( 'infinite scroll', 'responsive-lightbox' ) ) ), 'pagination_position' => array( 'title' => __( 'Pagination position', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select pagination position.', 'responsive-lightbox' ), 'default' => 'bottom', 'options' => array( 'bottom' => __( 'bottom', 'responsive-lightbox' ), 'top' => __( 'top', 'responsive-lightbox' ), 'both' => __( 'top & bottom', 'responsive-lightbox' ) ) ), 'images_per_page' => array( 'title' => __( 'Images per page', 'responsive-lightbox' ), 'type' => 'number', 'description' => __( 'Number of images per page.', 'responsive-lightbox' ), 'default' => get_option( 'posts_per_page', 20 ), 'step' => 1, 'min' => 0 ), 'load_more' => array( 'title' => __( 'Load More', 'responsive-lightbox' ), 'type' => 'radio', 'description' => __( 'Select the load more trigger (infinite scroll only).', 'responsive-lightbox' ), 'default' => 'automatically', 'options' => array( 'automatically' => __( 'Automatically', 'responsive-lightbox' ), 'manually' => __( 'On click', 'responsive-lightbox' ) ) ) ) ), 'lightbox' => array( 'options' => array( 'lightbox_enable' => array( 'title' => __( 'Enable Lightbox', 'responsive-lightbox' ), 'type' => 'boolean', 'label' => __( 'Enable lightbox effect for the gallery.', 'responsive-lightbox' ), 'default' => true ), 'lightbox_image_size' => array( 'title' => __( 'Image Size', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select image size for gallery lightbox.', 'responsive-lightbox' ), 'default' => 'global', 'options' => $sizes ), 'lightbox_custom_size' => array( 'title' => __( 'Custom size', 'responsive-lightbox' ), 'type' => 'multiple', 'description' => __( 'Choose the custom image size for gallery lightbox (used if Custom Image size is selected).', 'responsive-lightbox' ), 'fields' => array( 'lightbox_custom_size_width' => array( 'type' => 'number', 'append' => __( 'width in px', 'responsive-lightbox' ), 'default' => (int) get_option( 'large_size_w' ) ), 'lightbox_custom_size_height' => array( 'type' => 'number', 'append' => __( 'height in px', 'responsive-lightbox' ), 'default' => (int) get_option( 'large_size_h' ) ) ) ), 'lightbox_image_title' => array( 'title' => __( 'Image Title', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select image title for gallery lightbox.', 'responsive-lightbox' ), 'default' => 'global', 'options' => $merged_titles ), 'lightbox_image_caption' => array( 'title' => __( 'Image Caption', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select image caption for gallery lightbox (used if supported by selected lightbox effect).', 'responsive-lightbox' ), 'default' => 'global', 'options' => $merged_titles ) ) ), 'misc' => array( 'options' => array( 'gallery_title_position' => array( 'title' => __( 'Title Position', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select where to display the title.', 'responsive-lightbox' ), 'default' => 'none', 'options' => $positions ), 'gallery_description_position' => array( 'title' => __( 'Description Position', 'responsive-lightbox' ), 'type' => 'select', 'description' => __( 'Select where to display the description.', 'responsive-lightbox' ), 'default' => 'none', 'options' => $positions ), 'gallery_description' => array( 'title' => __( 'Gallery Description', 'responsive-lightbox' ), 'type' => 'textarea', 'description' => __( 'Enter the gallery description (optional).', 'responsive-lightbox' ), 'default' => '', 'class' => 'large-text' ), 'gallery_custom_class' => array( 'title' => __( 'Custom Classes', 'responsive-lightbox' ), 'type' => 'class', 'description' => __( 'Add custom, space saparated CSS classes (optional).', 'responsive-lightbox' ), 'default' => '', 'class' => 'large-text' ) ) ) ) ); // is remote library active? if ( $rl->options['remote_library']['active'] ) { // get providers $providers = $rl->remote_library->get_providers(); $active_providers = $rl->remote_library->get_active_providers(); // update active providers foreach ( $active_providers as $provider ) { $this->fields['images']['remote_library']['media_provider']['options'][$provider] = $providers[$provider]['name']; } } } /** * Duplicate gallery action in admin. * * @return void */ public function duplicate_gallery() { if ( ! ( isset( $_GET['post'] ) || isset( $_POST['post'] ) ) || ! isset( $_REQUEST['action'] ) || ! isset( $_REQUEST['rl_gallery_nonce'] ) || ( isset( $_REQUEST['rl_gallery_nonce'] ) && ! wp_verify_nonce( $_REQUEST['rl_gallery_nonce'], 'responsive-lightbox-duplicate-gallery' ) ) ) wp_die( esc_html__( 'No gallery to duplicate has been supplied!', 'responsive-lightbox' ) ); // get the original post $post_id = isset( $_GET['post'] ) ? (int) $_GET['post'] : ( isset( $_POST['post'] ) ? (int) $_POST['post'] : 0 ); if ( empty( $post_id ) ) wp_die( esc_html__( 'No gallery to duplicate has been supplied!', 'responsive-lightbox' ) ); if ( ! current_user_can( 'edit_post', $post_id ) ) wp_die( esc_html__( 'You do not have permission to copy this gallery.', 'responsive-lightbox' ) ); $post = get_post( $post_id ); // copy the post and insert it if ( isset( $post ) && $post !== null ) { $this->create_gallery_duplicate( $post ); // redirect to the post list screen wp_redirect( admin_url( 'edit.php?post_type=' . $post->post_type ) ); exit; } else wp_die( esc_html__( 'Copy creation failed, could not find original gallery:', 'responsive-lightbox' ) . ' ' . (int) $post_id ); } /** * Add duplicate link to gallery listing. * * @global string $pagenow * * @param array $actions Link actions * @param object $post Post object * @return array */ public function post_row_actions_duplicate( $actions, $post ) { global $pagenow; if ( $post->post_type !== 'rl_gallery' ) return $actions; if ( ! current_user_can( 'edit_post', $post->ID ) ) return $actions; // duplicate link $actions['duplicate_gallery'] = '<a class="duplicate-gallery" title="' . esc_attr__( 'Duplicate this item', 'responsive-lightbox' ) . '" href="' . esc_url( wp_nonce_url( admin_url( $pagenow . '?post=' . $post->ID . '&action=duplicate_gallery' ), 'responsive-lightbox-duplicate-gallery', 'rl_gallery_nonce' ) ) . '">' . esc_html__( 'Duplicate', 'responsive-lightbox' ) . '</a>'; return $actions; } /** * Create a gallery duplicate. * * @param $post object Post object * @return void|int */ public function create_gallery_duplicate( $post ) { // skip revisions if ( $post->post_type === 'revision' ) return; $new_post = apply_filters( 'rl_duplicate_gallery_args', [ 'menu_order' => $post->menu_order, 'comment_status' => $post->comment_status, 'ping_status' => $post->ping_status, 'post_author' => $post->post_author, 'post_content' => $post->post_content, 'post_excerpt' => $post->post_excerpt, 'post_mime_type' => $post->post_mime_type, 'post_parent' => $post->post_parent, 'post_password' => $post->post_password, 'post_status' => $post->post_status, 'post_title' => $post->post_title, 'post_type' => $post->post_type, 'post_date' => current_time( 'mysql' ), 'post_date_gmt' => get_gmt_from_date( current_time( 'mysql' ) ) ], $post ); $new_post_id = wp_insert_post( $new_post ); // if the copy is published or scheduled, we have to set a proper slug if ( $new_post['post_status'] === 'publish' || $new_post['post_status'] === 'future' ) { $post_name = wp_unique_post_slug( $post->post_name, $new_post_id, $new_post['post_status'], $post->post_type, $new_post['post_parent'] ); $new_post = []; $new_post['ID'] = $new_post_id; $new_post['post_name'] = $post_name; // update the post into the database wp_update_post( $new_post ); } // create metadata for the duplicated gallery $this->create_gallery_duplicate_metadata( $new_post_id, $post ); // copy taxonomies $this->duplicate_gallery_taxonomies( $new_post_id, $post ); // action hook for developers do_action( 'rl_after_duplicate_gallery', $new_post_id, $post ); return $new_post_id; } /** * Create a gallery duplicate metadata. * * @param int $new_post_id Post ID * @param object $post Post object * @return void */ public function create_gallery_duplicate_metadata( $new_post_id, $post ) { if ( empty( $post ) || $post == null ) return; // meta keys to be copied $meta_keys = apply_filters( 'rl_duplicate_gallery_meta_keys', get_post_custom_keys( $post->ID ) ); if ( empty( $meta_keys ) ) return; foreach ( $meta_keys as $meta_key ) { // meta values to be copied $meta_values = apply_filters( 'rl_duplicate_gallery_meta_values', get_post_custom_values( $meta_key, $post->ID ) ); foreach ( $meta_values as $meta_value ) { $meta_value = maybe_unserialize( $meta_value ); // add metadata to duplicated post add_post_meta( $new_post_id, $meta_key, $meta_value ); } } } /** * Copy the taxonomies of a gallery to another gallery. * * @global object $wpdb * * @param int $new_post_id Post ID * @param object $post Post object * @return void */ function duplicate_gallery_taxonomies( $new_post_id, $post ) { global $wpdb; if ( isset( $wpdb->terms ) ) { // clear default category wp_set_object_terms( $new_post_id, null, 'category' ); // get gallery taxonomies $gallery_taxonomies = get_object_taxonomies( $post->post_type ); if ( ! empty( $gallery_taxonomies ) ) { foreach ( $gallery_taxonomies as $taxonomy ) { $terms = []; // get taxonomy terms $post_terms = wp_get_object_terms( $post->ID, $taxonomy, array( 'orderby' => 'term_order' ) ); if ( ! empty( $post_terms ) ) { foreach ( $post_terms as $term ) { $terms[] = $term->slug; } } // copy taxonomy terms wp_set_object_terms( $new_post_id, $terms, $taxonomy ); } } } } /** * Add a gallery shortcode. * * @param array $args Shortcode arguments * @return string */ public function gallery_shortcode( $args ) { // enable only for frontend previews if ( ! is_admin() && is_preview() ) add_filter( 'get_post_metadata', array( $this, 'filter_preview_metadata' ), 10, 4 ); // prepare defaults $defaults = [ 'id' => 0 ]; // merge defaults with arguments $args = array_merge( $defaults, $args ); // parse id $args['id'] = (int) $args['id']; // is it gallery? if ( get_post_type( $args['id'] ) !== 'rl_gallery' ) return ''; // private gallery? if ( get_post_status( $args['id'] ) === 'private' && ! current_user_can( 'read_private_posts' ) ) return ''; $images_args = [ 'exclude' => true ]; if ( isset( $args['preview'] ) ) $images_args['preview'] = (bool) $args['preview']; elseif( isset( $_GET['rl_gallery_revision_id'], $_GET['preview'] ) && $_GET['preview'] === 'true' ) $images_args['preview'] = true; else $images_args['preview'] = false; // get images $images = $this->get_gallery_images( $args['id'], $images_args ); if ( ! $images ) return ''; $attachments = []; // build config foreach ( $images as $image ) { if ( ! empty( $image['id'] ) ) $attachments[] = $image['id']; } // get config data $config = get_post_meta( $args['id'], '_rl_config', true ); // prepare gallery shortcode parameters $fields = []; // get main instance $rl = Responsive_Lightbox(); // valid menu item? if ( ! empty( $config['menu_item'] ) ) { // assign data from db $data = $config[$config['menu_item']]; foreach ( $rl->frontend->get_default_gallery_fields() as $field_name => $field_args ) { // replace default values if ( array_key_exists( $field_name, $data ) ) $fields[$field_name] = $data[$field_name]; } // is it default gallery type? if ( $config['menu_item'] === 'default' ) { // set new gallery type $gallery_type = $rl->options['settings']['builder_gallery']; // assign gallery settings if ( array_key_exists( $gallery_type . '_gallery', $rl->settings->settings ) ) $gallery_fields = $rl->settings->settings[$gallery_type . '_gallery']['fields']; // assign gallery defaults if ( array_key_exists( $gallery_type . '_gallery', $rl->options ) ) $gallery_defaults = $rl->options[$gallery_type . '_gallery']; } else { $gallery_type = $config['menu_item']; // assign gallery settings if ( array_key_exists( $config['menu_item'] . '_gallery', $rl->settings->settings ) ) $gallery_fields = $rl->settings->settings[$config['menu_item'] . '_gallery']['fields']; // assign gallery defaults if ( array_key_exists( $config['menu_item'] . '_gallery', $rl->defaults ) ) $gallery_defaults = $rl->defaults[$config['menu_item'] . '_gallery']; } if ( isset( $gallery_fields, $gallery_defaults ) ) { // run through all fields foreach ( $gallery_fields as $field_name => $field_args ) { if ( $field_args['type'] === 'multiple' ) { foreach ( $field_args['fields'] as $subfield_name => $subfield_args ) { // field exists in db? if ( array_key_exists( $subfield_name, $data ) ) $fields[$subfield_name] = $data[$subfield_name]; else $fields[$subfield_name] = $gallery_defaults[$subfield_name]; } } else { // field exists in db? if ( array_key_exists( $field_name, $data ) ) $fields[$field_name] = $data[$field_name]; else $fields[$field_name] = $gallery_defaults[$field_name]; } } } // add gallery type $fields['type'] = $gallery_type; } $shortcode = ''; foreach ( $fields as $arg => $value ) { if ( is_array( $value ) ) $shortcode .= ' ' . esc_attr( $arg ) . '="' . esc_attr( (string) implode( ',', $value ) ) . '"'; else $shortcode .= ' ' . esc_attr( $arg ) . '="' . esc_attr( (string) $value ) . '"'; } // get design data $design = get_post_meta( $args['id'], '_rl_design', true ); if ( ! empty( $design['menu_item'] ) ) { $design_data = $design[$design['menu_item']]; // remove show_title to avoid shortcode attribute duplication if ( isset( $design_data['show_title'] ) ) { if ( ! isset( $design_data['design_show_title'] ) ) $design_data['design_show_title'] = $design_data['show_title']; unset( $design_data['show_title'] ); } // remove show_caption to avoid shortcode attribute duplication if ( isset( $design_data['show_caption'] ) ) { if ( ! isset( $design_data['design_show_caption'] ) ) $design_data['design_show_caption'] = $design_data['show_caption']; unset( $design_data['show_caption'] ); } foreach ( $design_data as $arg => $value ) { $shortcode .= ' ' . esc_attr( $arg ) . '="' . esc_attr( (string) $value ) . '"'; } } // get lightbox data $lightbox = get_post_meta( $args['id'], '_rl_lightbox', true ); if ( ! empty( $lightbox['menu_item'] ) ) { foreach ( $lightbox[$lightbox['menu_item']] as $arg => $value ) { $shortcode .= ' ' . esc_attr( $arg ) . '="' . esc_attr( (string) $value ) . '"'; } } $forced_gallery_no = 0; // check forced gallery number if ( isset( $args['gallery_no'] ) ) { $args['gallery_no'] = (int) $args['gallery_no']; if ( $args['gallery_no'] > 0 ) $forced_gallery_no = $args['gallery_no']; } // get content $content = do_shortcode( '[gallery rl_gallery_id="' . esc_attr( $args['id'] ) .'"' . ( $forced_gallery_no > 0 ? ' rl_gallery_no="' . (int) $forced_gallery_no .'"' : '' ) . ' include="' . ( empty( $attachments ) ? '' : esc_attr( implode( ',', $attachments ) ) ) . '"' . $shortcode . ']' ); // make sure every filter is available in frontend ajax if ( wp_doing_ajax() ) $content = $rl->frontend->add_lightbox( $content ); return $content; } /** * Add a gallery button. * * @param string $editor_id Editor ID * @return void */ public function add_gallery_button( $editor_id ) { if ( get_post_type() === 'rl_gallery' ) return; $this->enqueue_gallery_scripts_styles(); echo '<button type="button" id="rl-insert-modal-gallery-button" class="button" data-editor="' . esc_attr( $editor_id ) . '"><span class="wp-media-buttons-icon dashicons dashicons-format-gallery"></span> ' . esc_html__( 'Add Gallery', 'responsive-lightbox' ) . '</button>'; } /** * Enqueue scripts and styles needed for gallery modal. * * @global string $pagenow * * @return void */ public function enqueue_gallery_scripts_styles() { global $pagenow; // count how many times function was executed static $run = 0; // allow this only once if ( $run > 0 ) return; $run++; // get main instance $rl = Responsive_Lightbox(); wp_enqueue_script( 'responsive-lightbox-admin-gallery', RESPONSIVE_LIGHTBOX_URL . '/js/admin-gallery.js', array( 'jquery', 'underscore' ), $rl->defaults['version'], false ); // prepare script data $script_data = [ 'nonce' => wp_create_nonce( 'rl-gallery-post' ), 'post_id' => get_the_ID(), 'page' => esc_url( $pagenow ) ]; wp_add_inline_script( 'responsive-lightbox-admin-gallery', 'var rlArgsGallery = ' . wp_json_encode( $script_data ) . ";\n", 'before' ); wp_enqueue_style( 'responsive-lightbox-admin-gallery', RESPONSIVE_LIGHTBOX_URL . '/css/admin-gallery.css', [], $rl->defaults['version'] ); } /** * Modal gallery HTML template. * * @global string $wp_version * @global string $pagenow * * @return void */ public function modal_gallery_template() { global $wp_version; global $pagenow; // display only for post edit pages if ( ! ( ( ( $pagenow === 'post.php' || $pagenow === 'post-new.php' ) && get_post_type() !== 'rl_gallery' ) || ( version_compare( $wp_version, '5.8', '>=' ) && ( $pagenow === 'widgets.php' || $pagenow === 'customize.php' ) ) ) ) return; // get main instance $rl = Responsive_Lightbox(); $categories = ''; // builder categories? if ( $rl->options['builder']['categories'] ) { $terms = get_terms( array( 'taxonomy' => 'rl_category', 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false, 'fields' => 'id=>name' ) ); // get categories dropdown $categories = wp_dropdown_categories( array( 'orderby' => 'name', 'order' => 'asc', 'show_option_none' => empty( $terms ) ? __( 'All categories', 'responsive-lightbox' ) : '', 'show_option_all' => __( 'All categories', 'responsive-lightbox' ), 'show_count' => false, 'hide_empty' => false, 'option_none_value' => 0, 'hierarchical' => true, 'selected' => 0, 'taxonomy' => 'rl_category', 'hide_if_empty' => false, 'echo' => false, 'id' => 'rl-media-attachment-categories', 'class' => 'attachment-filters', 'name' => '' ) ); } echo ' <div id="rl-modal-gallery" style="display: none;"> <div class="media-modal wp-core-ui"> <button type="button" class="media-modal-close"><span class="media-modal-icon"><span class="screen-reader-text">' . esc_html__( 'Close', 'responsive-lightbox' ) . '</span></span></button> <div class="media-modal-content"> <div class="media-frame mode-select wp-core-ui hide-menu hide-router"> <div class="media-frame-title"> <h1 class="wrap">' . esc_html__( 'Insert Gallery', 'responsive-lightbox' ) . ' <a class="rl-reload-galleries page-title-action" href="#">' . esc_html__( 'Reload', 'responsive-lightbox' ). '</a><span class="rl-gallery-reload-spinner spinner"></span></h1> </div> <div class="media-frame-content" data-columns="0"> <div class="attachments-browser"> <div class="uploader-inline rl-no-galleries" style="display: none;"> <div class="uploader-inline-content has-upload-message"> <h2 class="upload-message">' . esc_html__( 'No items found.', 'responsive-lightbox' ) . '</h2> <div class="upload-ui"> <h2 class="upload-instructions">' . esc_html__( 'No galleries? Create them first or try another search phrase.', 'responsive-lightbox' ) . '</h2> </div> </div> </div> <div class="media-toolbar">' . ( $rl->options['builder']['categories'] ? ' <div class="media-toolbar-secondary"><label for="rl-media-attachment-categories" class="screen-reader-text">' . esc_html__( 'Filter by category', 'responsive-lightbox' ) . '</label>' . ( $categories !== '' ? wp_kses( $categories, $this->allowed_select_html ) : '' ) . '</div>' : '' ) . ' <div class="media-toolbar-primary search-form"> <label for="rl-media-search-input" class="screen-reader-text">' . esc_html__( 'Search galleries', 'responsive-lightbox' ) . '</label><input type="search" placeholder="' . esc_attr__( 'Search galleries', 'responsive-lightbox' ) . '" id="rl-media-search-input" class="search"> </div> </div> <ul class="attachments rl-galleries-list ui-sortable ui-sortable-disabled"> </ul> <div class="media-sidebar visible"> <h2>' . esc_html__( 'Select A Gallery', 'responsive-lightbox' ) . '</h2> <p>' . esc_html__( 'To select a gallery simply click on one of the boxes to the left.', 'responsive-lightbox' ) . '</p> <p>' . esc_html__( 'To insert your gallery into the editor, click on the "Insert Gallery" button below.', 'responsive-lightbox' ) . '</p> </div> </div> </div> <div class="media-frame-toolbar"> <div class="media-toolbar"> <div class="media-toolbar-secondary"> <div class="media-selection empty"> <div class="selection-info"> <span class="rl-gallery-count count">' . esc_html( sprintf( _n( '%s image', '%s images', 0, 'responsive-lightbox' ), 0 ) ) . '</span> <a href="" class="button-link rl-edit-gallery-link">' . esc_html__( 'Edit gallery', 'responsive-lightbox' ) . '</a> </div> <div class="selection-view"> <span class="rl-gallery-images-spinner spinner" style="display: none;"></span> <ul class="attachments rl-attachments-list"> </ul> </div> </div> </div> <div class="media-toolbar-primary search-form"> <button style="display: none;" type="button" class="button media-button button-primary button-large rl-media-button-insert-gallery" disabled="disabled">' . esc_html__( 'Insert gallery into post', 'responsive-lightbox') . '</button> <button style="display: none;" type="button" class="button media-button button-primary button-large rl-media-button-select-gallery" disabled="disabled">' . esc_html__( 'Select gallery', 'responsive-lightbox') . '</button> <button type="button" class="button media-button button-secondary button-large rl-media-button-cancel-gallery">' . esc_html__( 'Cancel', 'responsive-lightbox') . '</button> </div> </div> </div> </div> </div> </div> <div class="media-modal-backdrop"></div> </div>'; } /** * Render gallery field. * * @param string $field Field name * @param string $tab_id Field tab * @param string $menu_item Field parent * @param array $args Field arguments * @param int $gallery_id Gallery ID * @param bool $subfield Is this a subfield * @return string */ public function render_field( $field, $tab_id, $menu_item, $args, $gallery_id, $subfield = false ) { if ( $subfield ) { $template = '%s%s'; $html = ''; $subhtml = ''; } else { $template = $args['type'] === 'section' ? '<th colspan="2"><h3>%s</h3></th>' : '<th><label for="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '">%s</label></th><td>%s</td>'; $html = '<tr class="rl-gallery-field-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . ' rl-gallery-field-' . esc_attr( $args['type'] ) . '" data-field_type="' . esc_attr( $args['type'] ) . '" data-field_name="' . esc_attr( $field ) . '">'; $subhtml = ''; } switch ( $args['type'] ) { case 'range': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<input id="rl_' . esc_attr( $tab_id . '_' . $menu_item . '_' . $field ) . '" type="range" value="' . (int) $args['value'] . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" min="' . ( ! empty( $args['min'] ) ? (int) $args['min'] : 0 ) . '"' . ( ! empty( $args['max'] ) ? ' max="' . (int) $args['max'] . '"' : '' ) . ' step="' . ( ! empty( $args['step'] ) ? (int) $args['step'] : 1 ) . '" oninput="this.form.rl_' . esc_attr( $tab_id ) . '_' . esc_attr( $menu_item ) . '_' . esc_attr( $field ) . '_range.value=this.value" /><output class="rl-gallery-field-output" name="rl_' . esc_attr( $tab_id ) . '_' . esc_attr( $menu_item ) . '_' . esc_attr( $field ) . '_range">' . (int) $args['value'] . '</output>' . ( ! empty( $args['append'] ) ? ' <span>' . esc_html( $args['append'] ) . '</span>' : '' ) . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'radio': $subhtml = ''; foreach ( $args['options'] as $key => $label ) { $subhtml .= '<label class="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" for="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field . '-' . $key ) . '"><input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field . '-' . $key ) . '" type="radio" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" value="' . esc_attr( $key ) . '" ' . checked( $key, $args['value'], false ) . ' />' . esc_html( $label ) . '</label> '; } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'number': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" class="small-text" type="number" value="' . esc_attr( $args['value'] ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" min="' . ( ! empty( $args['min'] ) ? (int) $args['min'] : 0 ) . '"' . ( ! empty( $args['max'] ) ? ' max="' . (int) $args['max'] . '"' : '' ) . ' step="' . ( ! empty( $args['step'] ) ? (int) $args['step'] : 1 ) . '" />' . ( ! empty( $args['append'] ) ? ' <span>' . esc_html( $args['append'] ) . '</span>' : '' ) . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'text': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '"' . ( ! empty( $args['class'] ) ? ' class="' . esc_attr( $args['class'] ) . '"' : '' ) . ' type="text" value="' . esc_attr( $args['value'] ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" />' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'class': case 'textarea': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<textarea id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '"' . ( ! empty( $args['class'] ) ? ' class="' . esc_attr( $args['class'] ) . '"' : '' ) . ' name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']">' . esc_textarea( $args['value'] ) . '</textarea>' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'select': $subhtml = '<select id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']">'; foreach ( $args['options'] as $key => $label ) { $subhtml .= ' <option value="' . esc_attr( $key ) . '" ' . selected( $args['value'], $key, false ) . '>' . esc_html( $label ) . '</option>'; } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . '</select>' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'taxonomy': if ( taxonomy_exists( $args['taxonomy'] ) ) { $subhtml = wp_dropdown_categories( array( 'orderby' => 'name', 'order' => 'asc', 'show_option_none' => __( 'Root Folder', 'responsive-lightbox' ), 'show_option_all' => false, 'show_count' => false, 'hide_empty' => false, 'option_none_value' => 0, 'hierarchical' => true, 'selected' => $args['value']['id'], 'taxonomy' => $args['taxonomy'], 'hide_if_empty' => false, 'echo' => false, 'id' => 'rl-' . $tab_id . '-' . $menu_item . '-' . $field, 'name' => 'rl_gallery[' . $tab_id . '][' . $menu_item . '][' . $field . '][id]' ) ); } else $subhtml = '<select id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . '][]" ><option value="0">' . esc_html__( 'Root Folder', 'responsive-lightbox' ) . '</option></select> '; if ( isset( $args['include_children'] ) && $args['include_children'] ) { $subhtml .= '<label class="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '-include-children" for="rl-' . esc_attr( $tab_id ) . '-' . esc_attr( $menu_item ) . '-' . esc_attr( $field ) . '-include-children"><input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '-include-children" type="checkbox" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . '][children]" value="true" ' . checked( $args['value']['children'], true, false ) . ' />' . esc_html__( 'Include children.', 'responsive-lightbox' ) . '</label>'; } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'multiselect': $subhtml = '<select multiple="multiple" class="select2" id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" data-empty="' . (int) empty( $args['value'] ) . '" data-type="' . esc_attr( $field ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . '][]">'; if ( $field === 'post_term' ) { foreach ( $args['options'] as $taxanomy => $data ) { $subhtml .= '<optgroup label="' . esc_attr( $data['label'] ) . '">'; foreach ( $data['terms'] as $term_id => $name ) { $subhtml .= '<option value="' . esc_attr( $term_id ) . '" ' . selected( in_array( $term_id, $args['value'], false ), true, false ) . '>' . esc_html( $name ) . '</option>'; } $subhtml .= '</optgroup>'; } } else { foreach ( $args['options'] as $key => $label ) { $subhtml .= ' <option value="' . esc_attr( $key ) . '" ' . selected( in_array( $key, $args['value'], false ), true, false ) . '>' . esc_html( $label ) . '</option>'; } } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . '</select>' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'boolean': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<label class="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" for="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '"><input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" type="checkbox" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" value="true" ' . checked( $args['value'], true, false ) . ' />' . esc_html( $args['label'] ) . '</label>' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'checkbox': $subhtml = ''; foreach ( $args['options'] as $key => $label ) { $subhtml .= '<label class="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field . '-' . $key ) . '" for="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field . '-' . $key ) . '"><input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field . '-' . $key ) . '" type="checkbox" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . '][' . esc_attr( $key ) . ']" value="true" ' . checked( in_array( $key, $args['value'], true ), true, false ) . ' />' . esc_html( $label ) . '</label><br />'; } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'multiple': $subhtml = ''; foreach ( $args['fields'] as $sub_field => $sub_args ) { $subhtml .= $this->render_field( $sub_field, $tab_id, $menu_item, $sub_args, $gallery_id, true ) . '<br />'; } $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', $subhtml . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'color_picker': $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', '<input id="rl-' . esc_attr( $tab_id . '-' . $menu_item . '-' . $field ) . '" class="color-picker" type="text" value="' . esc_attr( $args['value'] ) . '" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . ']" data-default-color="' . esc_attr( $args['default'] ) . '" />' . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); break; case 'media_library': $data = get_post_meta( $gallery_id, '_rl_images', true ); // get images if ( ( ! empty( $data['menu_item'] ) && $data['menu_item'] === 'media' ) || ! ( wp_doing_ajax() && isset( $_POST['action'] ) && $_POST['action'] === 'rl-get-menu-content' ) ) $images = $this->get_gallery_images( $gallery_id ); else $images = []; // get media item template $media_item_template = $this->get_media_item_template( $args['preview'] ); // media buttons $buttons_desc = ''; // video support? if ( rl_current_lightbox_supports( 'video' ) ) { $buttons = [ '<a href="#" class="rl-gallery-select button button-secondary">' . __( 'Select images & videos', 'responsive-lightbox' ) . '</a>' ]; } else { $buttons[] = '<a href="#" class="rl-gallery-select button button-secondary">' . __( 'Select images', 'responsive-lightbox' ) . '</a>'; $buttons[] = '<a href="#" class="rl-gallery-select button button-disabled" disabled="true">' . __( 'Select images & videos', 'responsive-lightbox' ) . '</a>'; $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>' ]; $buttons_desc = '<p class="description">' . wp_sprintf( __( 'HTML5 Videos and Embed Videos available only in %l.', 'responsive-lightbox' ), $buttons_desc_args ) . '</p>'; } $html .= ' <td colspan="2" class="rl-colspan"> <input type="hidden" class="rl-gallery-ids" name="rl_gallery[' . esc_attr( $tab_id ) . '][' . esc_attr( $menu_item ) . '][' . esc_attr( $field ) . '][ids]" value="' . esc_attr( ! empty( $args['value']['ids'] ) ? implode( ',', $args['value']['ids'] ) : '' ) . '">'; // embed video support? if ( rl_current_lightbox_supports( [ 'youtube', 'vimeo' ], 'OR' ) ) $buttons[] = '<a href="#" class="rl-gallery-select-videos button button-secondary">' . esc_html__( 'Embed videos', 'responsive-lightbox' ) . '</a>'; else $buttons[] = '<a href="#" class="rl-gallery-select-videos button button-disabled" disabled="true">' . esc_html__( 'Embed videos', 'responsive-lightbox' ) . '</a>'; // add buttons $html .= ' <div class="rl-gallery-buttons">' . implode( '', $buttons ) . $buttons_desc . '</div>'; $html .= ' <div class="rl-gallery-content"> <ul class="rl-gallery-images rl-gallery-images-media">'; if ( ! empty( $images ) ) { foreach ( $images as $image ) { if ( $image['id'] === 0 ) $excluded_item = $image['url']; else $excluded_item = $image['id']; // get image content html $html .= $this->get_gallery_preview_image_content( $image, $tab_id, $menu_item, $field, $media_item_template, $args['value']['exclude'], $excluded_item ); } } $html .= ' </ul> </div> </td>'; break; case 'media_preview': $this->menu_item = $menu_item; // get images $images = $this->get_gallery_images( $gallery_id ); // get media item template $media_item_template = $this->get_media_item_template( $args['preview'] ); $html .= ' <td colspan="2" class="rl-colspan"> <div class="rl-gallery-preview-inside"> <a href="#" class="rl-gallery-update-preview button button-secondary">' . esc_html__( 'Update preview', 'responsive-lightbox' ) . '</a><span class="spinner" style="display: none;"></span> <p class="description">' . esc_html__( 'Use this button after any change of the options below to see updated gallery preview.', 'responsive-lightbox' ) . '</p> </div> <div class="rl-gallery-content"> <ul class="rl-gallery-images rl-gallery-images-' . esc_attr( $menu_item ) . '">'; if ( ! empty( $images ) ) { foreach ( $images as $image ) { if ( empty( $image['id'] ) ) { $excluded_item = $image['url']; $image['id'] = 0; } else $excluded_item = $image['id']; // get image content html $html .= $this->get_gallery_preview_image_content( $image, $tab_id, $menu_item, $field, $media_item_template, $args['value']['exclude'], $excluded_item ); } } $html .= ' </ul> </div>'; if ( ! empty( $args['preview'] ) && isset( $args['preview']['pagination'] )&& $args['preview']['pagination'] ) $html .= $this->get_preview_pagination(); $html .= ' </td>'; break; case 'hidden': // prepare args $args['tab_id'] = $tab_id; $args['menu_item'] = $menu_item; $args['field'] = $field; $html .= sprintf( $template, '', call_user_func( $args['callback'], $args ) ); break; default: $html .= sprintf( $template, ! empty( $args['title'] ) ? esc_html( $args['title'] ) : '', apply_filters( 'rl_render_gallery_field_' . $args['type'], $subhtml, $field, $tab_id, $menu_item, $args, $subfield ) . ( ! empty ( $args['description'] ) ? '<p class="description">' . wp_kses_post( $args['description'] ) . '</p>' : '' ) ); } if ( ! $subfield ) $html .= '</tr>'; return apply_filters( 'rl_render_gallery_field', $html, $field, $tab_id, $menu_item, $args, $subfield, $gallery_id ); } /** * Get preview pagination. * * @param int $current_page * @return string */ public function get_preview_pagination( $current_page = 1 ) { $page_links = []; $total_pages = $current_page + 1; $current = $current_page; $disable_first = $disable_last = $disable_prev = $disable_next = false; $current_url = 'preview_page'; if ( $current == 1 ) { $disable_first = true; $disable_prev = true; } elseif ( $current == 2 ) $disable_first = true; if ( $current == $total_pages ) { $disable_last = true; $disable_next = true; } if ( $current == $total_pages - 1 ) $disable_last = true; if ( $disable_first ) $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>'; else { $page_links[] = sprintf( '<a class="first-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>', $current_url, esc_html__( 'First page', 'responsive-lightbox' ), '«' ); } if ( $disable_prev ) $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">‹</span>'; else { $page_links[] = sprintf( '<a class="prev-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>', $current_url . '/' . max( 1, $current - 1 ), esc_html__( 'Previous page', 'responsive-lightbox' ), '‹' ); } $html_current_page = sprintf( '%s<input disabled="disabled" class="current-page" id="current-page-selector" type="text" name="paged" value="%s" size="%d" aria-describedby="table-paging" /><span class="tablenav-paging-text">', '<label for="current-page-selector" class="screen-reader-text">' . esc_html__( 'Current Page', 'responsive-lightbox' ) . '</label>', $current, strlen( $total_pages ) ); $html_total_pages = sprintf( '<span class="total-pages">%s</span>', number_format_i18n( $total_pages ) ); $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s', 'paging' ), $html_current_page, $html_total_pages ) . '</span></span>'; if ( $disable_next ) $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">›</span>'; else { $page_links[] = sprintf( '<a class="next-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>', $current_url . '/' . min( $total_pages, $current + 1 ), esc_html__( 'Next page', 'responsive-lightbox' ), '›' ); } if ( $disable_last ) $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>'; else { $page_links[] = sprintf( '<a class="last-page button" href="%s"><span class="screen-reader-text">%s</span><span aria-hidden="true">%s</span></a>', $current_url . '/' . $total_pages, esc_html__( 'Last page', 'responsive-lightbox' ), '»' ); } if ( $total_pages ) $page_class = $total_pages < 2 ? 'one-page' : ''; else $page_class = 'no-pages'; return '<div class="rl-gallery-preview-pagination tablenav"><div class="tablenav-pages ' . esc_attr( $page_class ) . '"><span class="pagination-links">' . join( "\n", $page_links ) . '</span></div>'; } /** * Sanitize field based on type. Internal use only. * * @global string $wp_version * * @param string $field Field name * @param mixed $value Field value * @param array $args Field arguments * @return mixed */ public function sanitize_field( $field, $value, $args ) { switch ( $args['type'] ) { case 'radio': case 'select': $value = array_key_exists( $value, $args['options'] ) ? $value : $args['default']; break; case 'taxonomy': if ( is_array( $value ) ) { if ( isset( $value['id'] ) ) $value['id'] = (int) $value['id']; else $value['id'] = 0; $value['children'] = isset( $value['children'] ); } else $value = $args['default']; // get term $term = get_term( $value['id'], $args['taxonomy'] ); // valid term? if ( is_a( $term, 'WP_Term' ) ) $value['id'] = $term->term_id; else $value['id'] = 0; break; case 'multiselect': if ( is_array( $value ) ) { // is it post term field? if ( $field === 'post_term' ) { $terms = []; foreach ( $args['options'] as $data ) { $terms += $data['terms']; } $args['options'] = $terms; } $values = []; foreach ( $value as $subvalue ) { if ( array_key_exists( $subvalue, $args['options'] ) ) $values[] = $subvalue; } $value = $values; } else $value = $args['default']; break; case 'checkbox': if ( is_array( $value ) && ! empty( $value ) ) { $sort = []; foreach ( $value as $sort_key => $bool ) { if ( array_key_exists( $sort_key, $args['options'] ) ) $sort[] = $sort_key; } $value = $sort; } else $value = []; break; case 'boolean': $value = $value === 'true'; break; case 'range': case 'number': $value = (int) $value; // is value lower than? if ( isset( $args['min'] ) && $value < $args['min'] ) $value = $args['min']; // is value greater than? if ( isset( $args['max'] ) && $value > $args['max'] ) $value = $args['max']; break; case 'class': $value = trim( $value ); // more than 1 class? if ( strpos( $value, ' ' ) !== false ) { // get unique valid HTML classes $value = array_unique( array_filter( array_map( 'sanitize_html_class', explode( ' ', $value ) ) ) ); if ( ! empty( $value ) ) $value = implode( ' ', $value ); else $value = ''; // single class } else $value = sanitize_html_class( $value ); break; case 'text': $value = trim( sanitize_text_field( $value ) ); break; case 'textarea': global $wp_version; // WP 4.7+ if ( version_compare( $wp_version, '4.7', '>=' ) ) $value = trim( sanitize_textarea_field( $value ) ); // _sanitize_text_fields else { $value = wp_check_invalid_utf8( $value ); if ( strpos( $value, '<' ) !== false ) { $value = wp_pre_kses_less_than( $value ); // this will strip extra whitespace for us $value = wp_strip_all_tags( $value, false ); // use html entities in a special case to make sure no later newline stripping stage could lead to a functional tag $value = str_replace( "<\n", "<\n", $value ); } $value = trim( $value ); $found = false; while ( preg_match('/%[a-f0-9]{2}/i', $value, $match ) ) { $value = str_replace( $match[0], '', $value ); $found = true; } // strip out the whitespace that may now exist after removing the octets if ( $found ) $value = trim( preg_replace( '/ +/', ' ', $value ) ); } break; case 'color_picker': if ( preg_match( '/^#[a-f0-9]{6}$/i', $value ) !== 1 ) $value = $args['default']; break; case 'media_library': if ( is_array( $value ) ) { $data = $args['default']; if ( rl_current_lightbox_supports( [ 'youtube', 'vimeo' ], 'OR' ) ) { $reindexed_embed = []; // check embed items if ( array_key_exists( 'embed', $value ) && is_array( $value['embed'] ) && ! empty( $value['embed'] ) ) { $copy = $value['embed']; $index = 0; foreach ( $value['embed'] as $embed_id => $embed_data ) { // check url if ( ! array_key_exists( 'url', $embed_data ) ) { unset( $copy[$embed_id] ); continue; } else $copy[$embed_id]['url'] = esc_url_raw( $embed_data['url'] ); // check width if ( ! array_key_exists( 'width', $embed_data ) ) $copy[$embed_id]['width'] = 0; else $copy[$embed_id]['width'] = (int) $embed_data['width']; // check height if ( ! array_key_exists( 'height', $embed_data ) ) $copy[$embed_id]['height'] = 0; else $copy[$embed_id]['height'] = (int) $embed_data['height']; // check thumbnail url if ( empty( $embed_data['thumbnail_url'] ) ) $copy[$embed_id]['thumbnail_url'] = ''; else $copy[$embed_id]['thumbnail_url'] = esc_url_raw( $embed_data['thumbnail_url'] ); // check thumbnail width if ( ! array_key_exists( 'thumbnail_width', $embed_data ) ) $copy[$embed_id]['thumbnail_width'] = 0; else $copy[$embed_id]['thumbnail_width'] = (int) $embed_data['thumbnail_width']; // check thumbnail height if ( ! array_key_exists( 'thumbnail_height', $embed_data ) ) $copy[$embed_id]['thumbnail_height'] = 0; else $copy[$embed_id]['thumbnail_height'] = (int) $embed_data['thumbnail_height']; // check title if ( empty( $embed_data['title'] ) ) $copy[$embed_id]['title'] = ''; else $copy[$embed_id]['title'] = trim( sanitize_text_field( $embed_data['title'] ) ); // check caption if ( empty( $embed_data['caption'] ) ) $copy[$embed_id]['caption'] = ''; else $copy[$embed_id]['caption'] = trim( sanitize_textarea_field( $embed_data['caption'] ) ); // check date if ( empty( $embed_data['date'] ) ) $copy[$embed_id]['date'] = ''; else $copy[$embed_id]['date'] = date( 'Y-m-d H:i:s', strtotime( $embed_data['date'] ) ); // new embed id $new_id = 'e' . $index; // add embed data $data['embed'][$new_id] = $copy[$embed_id]; $data['embed'][$new_id]['id'] = $new_id; // add special id $reindexed_embed[$embed_id] = 'em' . $index++; } // last replacement is 'em' to avoid replacing same embed ids $reindexed_embed['em'] = 'e'; // prepare embed additional data $atts_args = [ 'embed_keys' => array_keys( $data['embed'] ), 'providers' => [ 'youtube', 'vimeo' ] ]; } else $atts_args = []; } else $atts_args = []; // check ids if ( array_key_exists( 'ids', $value ) ) { // prepare ids $ids = (string) trim( $value['ids'] ); if ( $ids !== '' ) { // reindex embed if ( ! empty( $reindexed_embed ) ) $ids = str_replace( array_keys( $reindexed_embed ), array_values( $reindexed_embed ), $ids ); // get unique and non empty attachment ids only $data['ids'] = $this->check_attachments( array_unique( array_filter( explode( ',', $ids ) ) ), $atts_args ); } else $data['ids'] = []; } // check excluded items if ( array_key_exists( 'exclude', $value ) && is_array( $value['exclude'] ) && ! empty( $value['exclude'] ) ) { // reindex embed if ( ! empty( $reindexed_embed ) ) $value['exclude'] = explode( ',', str_replace( array_keys( $reindexed_embed ), array_values( $reindexed_embed ), implode( ',', array_filter( $value['exclude'] ) ) ) ); // get unique and non empty attachment ids only $data['exclude'] = $this->check_attachments( array_unique( array_filter( $value['exclude'] ) ), $atts_args ); } $value = $data; } else $value = $args['default']; break; case 'media_preview': if ( is_array( $value ) ) { $data = $args['default']; // check excluded items if ( array_key_exists( 'exclude', $value ) && is_array( $value['exclude'] ) && ! empty( $value['exclude'] ) ) { $ids = $strings = []; foreach ( $value['exclude'] as $exclude_item ) { $item = trim( $exclude_item ); if ( is_numeric( $item ) ) $ids[] = (int) $item; elseif ( $item !== '' ) $strings[] = $item; } if ( ! empty( $ids ) ) { // get unique and non empty attachment ids only $ids = $this->check_attachments( array_unique( array_filter( $ids ) ) ); } $data['exclude'] = $ids + $strings; } $value = $data; } else $value = $args['default']; } return apply_filters( 'rl_sanitize_gallery_field', $value, $args ); } /** * Sanitize set of fields. * * @param array $items Fields * @param array $data POST data * @param string $tab_id Gallery tab * @param string $menu_item Gallery menu item * @return array */ public function sanitize_fields( $items, $data, $tab_id, $menu_item ) { $safedata = []; foreach ( $items as $field => $item ) { // skip this field if ( isset( $item['save'] ) && ! $item['save'] ) continue; // available field? if ( isset( $data[$tab_id], $data[$tab_id][$menu_item], $data[$tab_id][$menu_item][$field] ) ) $safedata[$tab_id][$menu_item][$field] = $this->sanitize_field( $field, $data[$tab_id][$menu_item][$field], $item ); // boolean field? elseif ( $item['type'] === 'boolean' ) $safedata[$tab_id][$menu_item][$field] = false; // multiple fields? elseif ( $item['type'] === 'multiple' ) { foreach ( $item['fields'] as $subfield => $subitem ) { // available subfield? if ( isset( $data[$tab_id], $data[$tab_id][$menu_item], $data[$tab_id][$menu_item][$subfield] ) ) $safedata[$tab_id][$menu_item][$subfield] = $this->sanitize_field( $subfield, $data[$tab_id][$menu_item][$subfield], $subitem ); // boolean subfield? elseif ( $subitem['type'] === 'boolean' ) $safedata[$tab_id][$menu_item][$subfield] = false; // any other case else $safedata[$tab_id][$menu_item][$subfield] = $subitem['default']; } // any other case } else $safedata[$tab_id][$menu_item][$field] = $item['default']; } return $safedata; } /** * Add menu tabs after the post title. * * @global array $wp_meta_boxes * * @param object $post Post object * @return void */ public function after_title_nav_menu( $post ) { if ( $post->post_type !== 'rl_gallery' ) return; global $wp_meta_boxes; // check active tab $active_tab = isset( $_GET['rl_active_tab'] ) ? sanitize_key( $_GET['rl_active_tab'] ) : ''; $active_tab = ! empty( $active_tab ) && array_key_exists( $active_tab, $this->tabs ) ? $active_tab : 'images'; echo ' <h2 class="nav-tab-wrapper">'; foreach ( $this->tabs as $key => $data ) { echo ' <a id="rl-gallery-tab-' . esc_attr( $key ) . '" class="rl-gallery-tab nav-tab' . ( $key === $active_tab ? ' nav-tab-active' : '' ) . '" href="#' . esc_attr( $key ) . '">' . esc_html( $data['label'] ) . '</a>'; } echo ' </h2>'; do_meta_boxes( $post->post_type, 'responsive_lightbox_metaboxes', $post ); unset( $wp_meta_boxes[$post->post_type]['responsive_lightbox_metaboxes'] ); } /** * Add class to hide metabox. * * @param array $classes * @return array */ public function hide_metabox( $classes ) { $classes[] = 'rl-metabox-content'; $classes[] = 'rl-hide-metabox'; return $classes; } /** * Add class to display the metabox. * * @param array $classes * @return array */ function display_metabox( $classes ) { $classes[] = 'rl-metabox-content'; $classes[] = 'rl-display-metabox'; return $classes; } /** * Add active tab to post redirect destination URL. * * @param string $location Destination URL * @return string */ function add_active_tab( $location ) { // check active tab $active_tab = isset( $_POST['rl_active_tab'] ) ? sanitize_key( $_POST['rl_active_tab'] ) : ''; return add_query_arg( 'rl_active_tab', ! empty( $active_tab ) && array_key_exists( $active_tab, $this->tabs ) ? $active_tab : 'images', $location ); } /** * Add metaboxes. * * @return void */ public function add_meta_boxes() { // check active tab $active_tab = isset( $_GET['rl_active_tab'] ) ? sanitize_key( $_GET['rl_active_tab'] ) : ''; $active_tab = ! empty( $active_tab ) && array_key_exists( $active_tab, $this->tabs ) ? $active_tab : 'images'; // normal metaboxes foreach ( $this->tabs as $key => $args ) { if ( $key === 'images' ) $new_args = $args + array( 'tab_id' => $key, 'active_tab' => $active_tab ); else $new_args = $args + array( 'tab_id' => $key ); // handle metabox class if ( $active_tab === $key ) add_filter( 'postbox_classes_rl_gallery_responsive-gallery-' . $key, array( $this, 'display_metabox' ) ); else add_filter( 'postbox_classes_rl_gallery_responsive-gallery-' . $key, array( $this, 'hide_metabox' ) ); add_meta_box( 'responsive-gallery-' . $key, sprintf( esc_html__( 'Gallery %s', 'responsive-lightbox' ), $args['label'] ), array( $this, 'add_metabox' ), 'rl_gallery', 'responsive_lightbox_metaboxes', 'high', $new_args ); } // side metaboxes add_meta_box( 'responsive-gallery-shortcode', esc_html__( 'Gallery Code', 'responsive-lightbox' ), array( $this, 'shortcode_metabox' ), 'rl_gallery', 'side', 'core' ); } /** * Add single metabox. * * @param object $post Post object * @param array $callback_args Arguments * @return void */ public function add_metabox( $post, $callback_args ) { $html = $callback_args['args']['tab_id'] === 'images' ? '<input type="hidden" name="rl_active_tab" value="' . esc_attr( $callback_args['args']['active_tab'] ) . '" />' : ''; // default menu item $menu_item = 'options'; // get tab data $data = get_post_meta( $post->ID, '_rl_' . $callback_args['args']['tab_id'], true ); if ( ! is_array( $data ) ) $data = []; if ( $callback_args['args']['tab_id'] === 'design' && ! empty( $data['menu_item'] ) && is_array( $data[$data['menu_item']] ) ) { $design_data = $data[$data['menu_item']]; // remove show_title if ( isset( $design_data['show_title'] ) ) { if ( ! isset( $design_data['design_show_title'] ) ) $design_data['design_show_title'] = $design_data['show_title']; unset( $design_data['show_title'] ); } // remove show_caption if ( isset( $design_data['show_caption'] ) ) { if ( ! isset( $design_data['design_show_caption'] ) ) $design_data['design_show_caption'] = $design_data['show_caption']; unset( $design_data['show_caption'] ); } $data[$data['menu_item']] = $design_data; } // maybe add description $html .= ! empty( $callback_args['args']['description'] ) ? '<p class="rl-gallery-tab-description">' . esc_html( $callback_args['args']['description'] ) . '</p>' : ''; // get main instance $rl = Responsive_Lightbox(); // maybe add menu if ( ! empty( $callback_args['args']['menu_items'] ) ) { // get selected menu item $menu_item = ! empty( $data['menu_item'] ) && in_array( $data['menu_item'], array_keys( $callback_args['args']['menu_items'] ) ) ? $data['menu_item'] : key( $callback_args['args']['menu_items'] ); $html .= ' <div class="rl-gallery-tab-menu rl-gallery-tab-menu-' . esc_attr( $callback_args['args']['tab_id'] ) . '">'; foreach ( $callback_args['args']['menu_items'] as $menu_key => $menu_label ) { // disable select for remote library if needed if ( $menu_key === 'remote_library' && ! $rl->options['remote_library']['active'] ) { $title = __( 'Remote Library is disabled. Enable it in the settings.', 'responsive-lightbox' ); $disabled = true; // disable select for media folders if needed } elseif ( $menu_key === 'folders' && ! $rl->options['folders']['active'] ) { $title = __( 'Media Folders are disabled. Enable it in the settings.', 'responsive-lightbox' ); $disabled = true; // other menu items } else { $title = ''; $disabled = false; } $html .= ' <label' . ( $title !== '' ? ' title="' . esc_attr( $title ). '"' : '' ) . '><input type="radio" class="rl-gallery-tab-menu-item" name="rl_gallery[' . esc_attr( $callback_args['args']['tab_id'] ) . '][menu_item]" value="' . esc_attr( $menu_key ) . '" ' . checked( $menu_item, $menu_key, false ) . ' ' . disabled( $disabled, true, false ) . ' />' . esc_html( $menu_label ) . ( $callback_args['args']['tab_id'] === 'config' && $menu_key === 'default' ? ' (' . esc_html( $this->tabs['config']['menu_items'][$rl->options['settings']['builder_gallery']] ) . ')' : '' ) . '</label>'; } $html .= ' <span class="spinner" style="display: none;"></span> </div>'; } $class = ''; // disable gallery images content for remote library or media folders if needed if ( $callback_args['args']['tab_id'] === 'images' && ( ( $menu_item === 'remote_library' && ! $rl->options['remote_library']['active'] ) || ( $menu_item === 'folders' && ! $rl->options['folders']['active'] ) ) ) $class = 'rl-loading-content'; $html .= ' <div class="rl-gallery-tab-content rl-gallery-tab-content-' . esc_attr( $callback_args['args']['tab_id'] ) . ( $class !== '' ? ' ' . esc_attr( $class ) : '' ) . '">'; $html .= ! empty( $callback_args['args']['callback'] ) && is_callable( $callback_args['args']['callback'] ) ? call_user_func( $callback_args['args']['callback'], $callback_args['args']['tab_id'], $data, $menu_item, $post->ID ) : $this->get_metabox_content( $callback_args['args']['tab_id'], $data, $menu_item, $post->ID ); $html .= ' </div>'; // get allowed html $allowed_html = wp_kses_allowed_html( 'post' ); $allowed_html['a']['disabled'] = []; $allowed_html['span']['data-select2-id'] = []; $allowed_html['input'] = [ 'type' => [], 'name' => [], 'value' => [], 'class' => [], 'id' => [], 'size' => [], 'checked' => [], 'disabled' => [], 'aria-describedby' => [], 'min' => [], 'max' => [], 'step' => [], 'data-default-color' => [] ]; $allowed_html['select'] = [ 'name' => [], 'id' => [], 'class' => [], 'multiple' => [], 'data-empty' => [], 'data-type' => [], 'aria-hidden' => [] ]; $allowed_html['option'] = [ 'value' => [], 'selected' => [], 'class' => [] ]; $allowed_html['optgroup'] = [ 'label' => [] ]; add_filter( 'safe_style_css', [ $this, 'allow_style_attributes' ] ); echo wp_kses( $html, $allowed_html ); remove_filter( 'safe_style_css', [ $this, 'allow_style_attributes' ] ); } /** * Add new properties to style safe list. * * @param array $styles * @return array */ public function allow_style_attributes( $styles ) { $styles[] = 'display'; $styles[] = 'visibility'; return $styles; } /** * Get single metabox content. * * @param string $tab_id Tab ID * @param array $data Metabox data * @param string $menu_item Specified menu item * @param int $gallery_id Gallery ID * @return string */ public function get_metabox_content( $tab_id, $data, $menu_item, $gallery_id = 0 ) { $html = ' <div class="rl-gallery-tab-inside rl-gallery-tab-inside-' . esc_attr( $tab_id ) . '-' . esc_attr( $menu_item ) . '"> <table class="form-table">'; switch ( $tab_id ) { case 'config': // get main instance $rl = Responsive_Lightbox(); // get default gallery fields $default_gallery = $rl->frontend->get_default_gallery_fields(); // assign settings and defaults $settings = $rl->settings->settings; $defaults = $rl->defaults; if ( ! array_key_exists( 'default_gallery', $settings ) ) $settings['default_gallery']['fields'] = $default_gallery; // assign default values foreach ( $default_gallery as $field => $field_args ) { $defaults['default_gallery'][$field] = $field_args['default']; } // valid gallery? if ( array_key_exists( $menu_item . '_gallery', $settings ) && array_key_exists( $menu_item . '_gallery', $defaults ) ) { if ( $menu_item === 'default' ) $fields = $settings['default_gallery']['fields']; else { $fields = $rl->frontend->get_unique_fields( $settings['default_gallery']['fields'], $settings[$menu_item . '_gallery']['fields'] ); // add default gallery default values foreach ( $default_gallery as $field => $field_args ) { $defaults[$menu_item . '_gallery'][$field] = $field_args['default']; } } foreach ( $fields as $field => $args ) { if ( $args['type'] === 'multiple' ) { $new_args = $args; foreach ( $args['fields'] as $subfield => $subargs ) { $new_args['fields'][$subfield] = $subargs + array( 'value' => isset( $data[$menu_item], $data[$menu_item][$subfield] ) ? $data[$menu_item][$subfield] : $defaults[$menu_item . '_gallery'][$subfield], 'default' => $defaults[$menu_item . '_gallery'][$subfield] ); } } else { $new_args = $args + array( 'value' => isset( $data[$menu_item], $data[$menu_item][$field] ) ? $data[$menu_item][$field] : $defaults[$menu_item . '_gallery'][$field], 'default' => $defaults[$menu_item . '_gallery'][$field] ); } $html .= $this->render_field( $field, $tab_id, $menu_item, $new_args, $gallery_id ); } // just in case ajax would fail } else $html .= '<p>' . esc_html__( 'No data', 'responsive-lightbox' ) . '</p>'; break; default: foreach ( $this->fields[$tab_id][$menu_item] as $field => $args ) { // was this field stored in a database? if ( isset( $args['save'] ) && ! $args['save'] ) $new_args = $args; elseif ( $args['type'] === 'multiple' ) { $new_args = $args; foreach ( $args['fields'] as $subfield => $subargs ) { $new_args['fields'][$subfield] = $subargs + array( 'value' => isset( $data[$menu_item], $data[$menu_item][$subfield] ) ? $data[$menu_item][$subfield] : $subargs['default'] ); } } else $new_args = $args + array( 'value' => isset( $data[$menu_item], $data[$menu_item][$field] ) ? $data[$menu_item][$field] : $args['default'] ); // media preview? // if ( $tab_id === 'images' && $menu_item === 'featured' && $field === 'attachments' && $args['type'] === 'media_preview' ) // $new_args['subfields'] = $data['featured']; $html .= $this->render_field( $field, $tab_id, $menu_item, $new_args, $gallery_id ); } } $html .= ' </table> </div>'; return apply_filters( 'rl_gallery_tab_content', $html, $tab_id, $data, $menu_item ); } /** * Update number of gallery images when attachment is deleted. * * @param int $attachment_id * @return void */ public function delete_attachment( $attachment_id ) { //@TODO } /** * Get number of gallery images. * * @param int $gallery_id * @return int */ public function get_gallery_images_number( $gallery_id ) { return count( $this->get_gallery_images( $gallery_id, [ 'count_images' => true, 'preview' => false, 'exclude' => true ] ) ); } /** * Get gallery images. * * @global string $pagenow * * @param int $gallery_id Gallery ID * @param array $args Gallery arguments * @return array */ public function get_gallery_images( $gallery_id = 0, $args = [] ) { $images = []; $excluded = []; // get main instance $rl = Responsive_Lightbox(); // get args $defaults = array( 'count_images' => false, 'exclude' => false, 'posts_per_page' => -1, 'images_per_page' => 0, 'page' => 1, 'limit' => 0, 'nopaging' => true, 'image_size' => 'large', 'thumbnail_size' => 'thumbnail', 'pagination_type' => 'paged', 'pagination_position' => 'bottom', 'orderby' => 'menu_order', 'order' => 'asc', 'preview' => is_admin(), 'preview_type' => 'update', 'preview_page' => 1, 'preview_per_page' => 20, 'taxonomy' => $rl->options['folders']['media_taxonomy'], 'folder' => array( 'id' => 0, 'children' => null // do not change! ) ); // parse arguments $args = wp_parse_args( apply_filters( 'rl_get_gallery_images_args', $args, $gallery_id ), $defaults ); // disable counting mode if ( $args['preview'] ) $args['count_images'] = false; // sanitize args $args['exclude'] = (bool) ! empty( $args['exclude'] ); $args['posts_per_page'] = ! empty( $args['posts_per_page'] ) ? (int) $args['posts_per_page'] : -1; $args['nopaging'] = (bool) ! empty( $args['nopaging'] ); // check gallery post type $valid_gallery_type = ( get_post_type( $gallery_id ) === 'rl_gallery' ); // is it rl_gallery? skip when counting mode is enabled if ( $valid_gallery_type && ! $args['count_images'] ) { $paging = get_post_meta( $gallery_id, '_rl_paging', true ); if ( isset( $paging['menu_item'] ) ) { $pagination = $paging[$paging['menu_item']]; if ( $pagination['pagination'] ) { $args['nopaging'] = false; $args['images_per_page'] = $pagination['images_per_page']; $args['pagination_type'] = $pagination['pagination_type']; // infinite type? if ( $args['pagination_type'] === 'infinite' ) $args['pagination_position'] = 'bottom'; else $args['pagination_position'] = $pagination['pagination_position']; } else $args['nopaging'] = true; } } global $pagenow; // is it preview? if ( ( in_array( $pagenow, array( 'post.php', 'post-new.php' ), true ) && $gallery_id ) || ( isset( $_POST['action'] ) && $_POST['action'] === 'rl-get-preview-content' ) || ( wp_doing_ajax() && isset( $_POST['action'] ) && ( $_POST['action'] === 'rl-post-gallery-preview' || $_POST['action'] === 'rl-get-menu-content' ) ) ) $args['images_per_page'] = 0; if ( isset( $_GET['rl_page'] ) ) $args['page'] = (int) $_GET['rl_page']; else $args['page'] = (int) $args['page']; // is it rl_gallery? if ( $valid_gallery_type ) { // no need order in counting mode if ( ! $args['count_images'] ) { // get config metadata $config_meta = get_post_meta( $gallery_id, '_rl_config', true ); // config order if ( isset( $config_meta['menu_item'] ) ) { $config = $config_meta[$config_meta['menu_item']]; $args['orderby'] = $config['orderby']; $args['order'] = $config['order']; } } // get images metadata $data = get_post_meta( $gallery_id, '_rl_images', true ); // array? if ( ! is_array( $data ) ) $data = []; // get menu item if ( ! empty( $this->menu_item ) ) $menu_item = $this->menu_item; elseif ( array_key_exists( 'menu_item', $data ) ) $menu_item = $data['menu_item']; else $menu_item = 'media'; // valid data? if ( ! array_key_exists( $menu_item, $data ) ) $data[$menu_item] = []; if ( $args['preview'] && $this->fields['images'][$menu_item]['attachments']['preview']['pagination'] ) { if ( isset( $args['preview_page'] ) ) $args['preview_page'] = (int) $args['preview_page']; else $args['preview_page'] = 1; $args['preview_per_page'] = (int) $args['preview_per_page']; } switch ( $menu_item ) { case 'media': // check embed data if ( ! empty( $data[$menu_item]['attachments']['embed'] ) ) { $atts_args = [ 'embed_keys' => array_keys( $data[$menu_item]['attachments']['embed'] ), 'providers' => [ 'youtube', 'vimeo' ] ]; } else $atts_args = []; // get attachment ids $attachments = ! empty( $data[$menu_item]['attachments']['ids'] ) ? $this->check_attachments( array_unique( array_filter( $data[$menu_item]['attachments']['ids'] ) ), $atts_args ) : []; // filter attachments $attachments = apply_filters( 'rl_get_gallery_images_attachments', $attachments, $atts_args ); // exclude any attachments? if ( $args['exclude'] && ! empty( $data[$menu_item]['attachments']['exclude'] ) ) $attachments = array_diff( $attachments, $data[$menu_item]['attachments']['exclude'] ); // check filtered attachments $attachments = $this->check_attachments( $attachments, $atts_args ); // any attachments? if ( $attachments ) { if ( $args['limit'] ) $counter = 0; foreach ( $attachments as $attachment_id ) { // for counting mode get attachment id only if ( $args['count_images'] ) $images[] = $attachment_id; else { // embed? if ( preg_match( '/^e\d+$/', $attachment_id ) === 1 ) { $attachment_data = $data[$menu_item]['attachments']['embed'][$attachment_id]; $attachment_data['type'] = 'embed'; } else $attachment_data = $attachment_id; // get attachment image data $images[] = $this->get_gallery_image_src( $attachment_data, $args['image_size'], $args['thumbnail_size'] ); // limit attachments? if ( $args['limit'] ) { $counter++; // limit reached? if ( $counter === $args['limit'] ) break; } } } } break; case 'featured': // only for featured frontend galleries if ( ! is_admin() || wp_doing_ajax() ) { // prepare featured fields $this->fields['images']['featured'] = $this->prepare_featured_fields( $this->fields['images']['featured'] ); } // copy arguments $query_args = $args; // skip order for counting mode if ( ! $args['count_images'] ) { // prevent duplicating images order (config tab) with posts order (images tab), query will handle empty strings if ( array_key_exists( 'post_orderby', $args ) ) $query_args['orderby'] = $args['post_orderby']; elseif ( array_key_exists( 'orderby', $data[$menu_item] ) ) $query_args['orderby'] = $data[$menu_item]['orderby']; else $query_args['orderby'] = ''; if ( array_key_exists( 'post_order', $args ) ) $query_args['order'] = $args['post_order']; elseif ( array_key_exists( 'order', $data[$menu_item] ) ) $query_args['order'] = $data[$menu_item]['order']; else $query_args['order'] = ''; } // get attachment ids $attachments = $this->gallery_query( array_merge( $data[$menu_item], $query_args ) ); // filter attachments $attachments = apply_filters( 'rl_get_gallery_images_attachments', $attachments ); // exclude any attachments? if ( $args['exclude'] && ! empty( $data[$menu_item]['attachments']['exclude'] ) ) $attachments = array_diff( $attachments, $data[$menu_item]['attachments']['exclude'] ); // any attachments? if ( $attachments ) { if ( $args['limit'] ) $counter = 0; foreach ( $attachments as $attachment_id ) { // real attachment? if ( ! wp_attachment_is_image( $attachment_id ) ) continue; // for counting mode get attachment id only if ( $args['count_images'] ) $images[] = $attachment_id; else { // get attachment image data $images[] = $this->get_gallery_image_src( $attachment_id, $args['image_size'], $args['thumbnail_size'] ); // limit attachments? if ( $args['limit'] ) { $counter++; // limit reached? if ( $counter === $args['limit'] ) break; } } } } break; case 'folders': // is folders active? if ( ! $rl->options['folders']['active'] ) break; if ( ! array_key_exists( 'folder', $data[$menu_item] ) ) $data[$menu_item]['folder'] = $defaults['folder']; // ajax requests if ( is_string( $args['folder']['id'] ) ) $args['folder']['id'] = (int) $args['folder']['id']; // not empty folder term id? if ( ! empty( $args['folder']['id'] ) ) { // get term $term = get_term( $args['folder']['id'], $args['taxonomy'] ); // valid term? if ( is_a( $term, 'WP_Term' ) ) $folder_id = (int) $term->term_id; else $folder_id = (int) $data[$menu_item]['folder']['id']; } else { if ( isset( $_POST['action'] ) && $_POST['action'] === 'rl-get-preview-content' ) $folder_id = $args['folder']['id']; else $folder_id = (int) $data[$menu_item]['folder']['id']; } if ( $folder_id >= 0 ) { $include_children = false; // null means folder was not changed if ( $args['folder']['children'] === null ) { if ( array_key_exists( 'children', $data[$menu_item]['folder'] ) && $data[$menu_item]['folder']['children'] === true ) $include_children = true; // overwritten by args } else { if ( is_string( $args['folder']['children'] ) ) { if ( $args['folder']['children'] === 'true' ) $include_children = true; } elseif ( is_bool( $args['folder']['children'] ) ) { if ( $args['folder']['children'] ) $include_children = true; } } if ( $folder_id === 0 ) { if ( $include_children ) { $all_folders = get_terms( array( 'taxonomy' => $args['taxonomy'], 'hide_empty' => false, 'fields' => 'ids', 'hierarchical' => false, 'number' => 0 ) ); $tax_query = array( array( 'relation' => 'OR', array( 'taxonomy' => $args['taxonomy'], 'field' => 'term_id', 'terms' => ( ! is_wp_error( $all_folders ) ) ? $all_folders : $folder_id, 'include_children' => $include_children, 'operator' => 'IN' ), array( 'taxonomy' => $args['taxonomy'], 'field' => 'term_id', 'terms' => $folder_id, 'include_children' => $include_children, 'operator' => 'NOT EXISTS' ) ) ); } else { $tax_query = array( array( 'taxonomy' => $args['taxonomy'], 'field' => 'term_id', 'terms' => $folder_id, 'include_children' => $include_children, 'operator' => 'NOT EXISTS' ) ); } } else { $tax_query = array( array( 'taxonomy' => $args['taxonomy'], 'field' => 'term_id', 'terms' => $folder_id, 'include_children' => $include_children, 'operator' => 'IN' ) ); } // prepare query arguments $wp_query_args = array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => array( 'image/jpeg', 'image/gif', 'image/png' ), 'nopaging' => true, 'posts_per_page' => -1, 'fields' => 'ids', 'tax_query' => $tax_query ); // is it preview? if ( $args['preview'] ) { $wp_query_args['posts_per_page'] = $args['preview_per_page']; $wp_query_args['offset'] = ( $args['preview_page'] - 1 ) * $args['preview_per_page']; $wp_query_args['nopaging'] = false; } // run query $query = new WP_Query( apply_filters( 'rl_folders_query_args', $wp_query_args ) ); // get attachment ids $attachments = $query->get_posts(); // valid attachments? if ( ! is_wp_error( $attachments ) ) { // cast ids to int $attachments = array_map( 'intval', $attachments ); // make sure to skip duplicates $attachments = array_unique( $attachments ); // filter attachments $attachments = apply_filters( 'rl_get_gallery_images_attachments', $attachments ); // exclude any attachments? if ( $args['exclude'] && ! empty( $data[$menu_item]['attachments']['exclude'] ) ) $attachments = array_diff( $attachments, $data[$menu_item]['attachments']['exclude'] ); // any attachments? if ( $attachments ) { if ( $args['limit'] ) $counter = 0; foreach ( $attachments as $attachment_id ) { // real attachment? if ( ! wp_attachment_is_image( $attachment_id ) ) continue; // for counting mode get attachment id only if ( $args['count_images'] ) $images[] = $attachment_id; else { // get attachment image data $images[] = $this->get_gallery_image_src( $attachment_id, $args['image_size'], $args['thumbnail_size'] ); // limit attachments? if ( $args['limit'] ) { $counter++; // limit reached? if ( $counter === $args['limit'] ) break; } } } } } } break; case 'remote_library': // is remote library active? if ( ! $rl->options['remote_library']['active'] ) break; // no media search phrase? if ( ! isset( $args['media_search'] ) ) $args['media_search'] = isset( $data[$menu_item]['media_search'] ) ? $data[$menu_item]['media_search'] : ''; // no media provider? if ( ! isset( $args['media_provider'] ) ) $args['media_provider'] = isset( $data[$menu_item]['media_provider'] ) ? $data[$menu_item]['media_provider'] : 'all'; // get remote images $images = $rl->remote_library->get_remote_library_images( $args ); break; } } // skip order for counting mode if ( ! $args['count_images'] ) { // config sort order switch ( $args['orderby'] ) { case 'id': $sort = []; foreach ( $images as $key => $image ) { // set sorting value $sort[$key] = $image['id']; } // sort array_multisort( $sort, $args['order'] === 'asc' ? SORT_ASC : SORT_DESC, SORT_NUMERIC, $images ); break; case 'title': $sort = []; if ( $valid_gallery_type ) { // get lightbox data $lightbox_meta = get_post_meta( $gallery_id, '_rl_lightbox', true ); // valid data? if ( isset( $lightbox_meta['menu_item'] ) ) $title_arg = $lightbox_meta[$lightbox_meta['menu_item']]['lightbox_image_title']; else $title_arg = $rl->options['settings']['gallery_image_title']; } else $title_arg = $rl->options['settings']['gallery_image_title']; $images_copy = $images; foreach ( $images_copy as $key => $image ) { if ( $title_arg === 'global' ) $images[$key]['title'] = $rl->frontend->get_attachment_title( $image['id'], $rl->options['settings']['gallery_image_title'] ); elseif ( $title_arg === 'default' ) $images[$key]['title'] = ''; else $images[$key]['title'] = $rl->frontend->get_attachment_title( $image['id'], $title_arg ); // set sorting value $sort[$key] = function_exists( 'mb_strtolower' ) ? mb_strtolower( $images[$key]['title'] ) : strtolower( $images[$key]['title'] ); } // sort array_multisort( $sort, $args['order'] === 'asc' ? SORT_ASC : SORT_DESC, SORT_STRING, $images ); break; case 'post_date': $sort = []; foreach ( $images as $key => $image ) { // set sorting value $sort[$key] = $image['date']; } // sort array_multisort( $sort, $args['order'] === 'asc' ? SORT_ASC : SORT_DESC, $images ); break; case 'menu_order': // do nothing break; case 'rand': shuffle( $images ); break; } } // filter images $images = apply_filters( 'rl_get_gallery_images_array', $images, $gallery_id, $args ); // count number of images $images_count = count( $images ); // no preview? if ( ! $args['preview'] && ! $args['count_images'] && $args['limit'] === 0 ) update_post_meta( $gallery_id, '_rl_images_count', $images_count ); // images pagination? if ( $images && ! $args['nopaging'] && $args['images_per_page'] > 0 && ! $args['count_images'] ) { // get part of images $images = array_slice( $images, ( $args['page'] - 1 ) * $args['images_per_page'], $args['images_per_page'], true ); // pass gallery args $this->gallery_args = $args; $this->gallery_args['total'] = (int) ceil( $images_count / $args['images_per_page'] ); // remove actions to avoid issues with multiple galleries on single page remove_action( 'rl_before_gallery', [ $this, 'do_pagination' ], 10 ); remove_action( 'rl_after_gallery', [ $this, 'do_pagination' ], 10 ); // pagination position if ( $args['pagination_position'] === 'top' ) add_action( 'rl_before_gallery', [ $this, 'do_pagination' ], 10, 2 ); elseif ( $args['pagination_position'] === 'bottom' ) add_action( 'rl_after_gallery', [ $this, 'do_pagination' ], 10, 2 ); else { add_action( 'rl_before_gallery', [ $this, 'do_pagination' ], 10, 2 ); add_action( 'rl_after_gallery', [ $this, 'do_pagination' ], 10, 2 ); } } return apply_filters( 'rl_get_gallery_images', array_values( $images ), $gallery_id, $args ); } /** * Create gallery pagination. * * @global object $wp * * @param array $args * @param int $gallery_id * @return void */ public function do_pagination( $args, $gallery_id ) { global $wp; // get main instance $rl = Responsive_Lightbox(); // get current action $current_action = current_action(); if ( $current_action === 'rl_before_gallery' ) $class = 'rl-pagination-top'; elseif ( $current_action === 'rl_after_gallery' ) $class = 'rl-pagination-bottom'; else $class = ''; // set base arguments $base_args = [ 'rl_gallery_no' => $rl->frontend->get_data( 'gallery_no' ), 'rl_page' => '%#%' ]; if ( empty( $args['pagination_type'] ) ) $args['pagination_type'] = 'paged'; // infinite scroll? if ( $args['pagination_type'] === 'infinite' ) $base_args['rl_lightbox_script'] = $rl->get_data( 'current_script' ); echo '<div class="rl-pagination ' . esc_attr( $class ) . '"' . ( $args['pagination_type'] === 'infinite' ? ' data-button="' . esc_attr( $args['load_more'] ) . '"' : '' ) .'>' . paginate_links( [ 'format' => '?rl_page=%#%', 'base' => add_query_arg( $base_args, $args['pagination_type'] !== 'paged' ? get_permalink( $gallery_id ) : home_url( $wp->request ) ), 'total' => $this->gallery_args['total'], 'current' => $this->gallery_args['page'], 'show_all' => false, 'end_size' => 1, 'mid_size' => 2, 'prev_next' => true, 'prev_text' => esc_html__( '« Previous', 'responsive-lightbox' ), 'next_text' => esc_html__( 'Next »', 'responsive-lightbox' ), 'type' => 'plain', 'add_args' => '', 'add_fragment' => '', 'before_page_number' => '', 'after_page_number' => '' ] ) . '</div>' . ( $args['pagination_type'] === 'infinite' && $args['load_more'] === 'manually' ? '<div class="rl-gallery-button"><button class="rl-button rl-load-more">' . esc_html__( 'Load more', 'responsive-lightbox' ) . '</button></div>' : '' ); } /** * Check whether is it valid gallery AJAX request (rl-get-gallery-page-content action). * * @return bool */ public function gallery_ajax_verified() { return ( wp_doing_ajax() && isset( $_POST['action'], $_POST['gallery_id'], $_POST['gallery_no'], $_POST['page'], $_POST['nonce'], $_POST['preview'], $_POST['post_id'], $_POST['lightbox'] ) && $_POST['action'] === 'rl-get-gallery-page-content' && wp_verify_nonce( $_POST['nonce'], 'rl_nonce' ) ); } /** * Try to change lightbox in valid gallery AJAX request (rl-get-gallery-page-content action). * * @return void */ public function maybe_change_lightbox() { // check whether is it valid gallery ajax request if ( $this->gallery_ajax_verified() ) { // set new lightbox script Responsive_Lightbox()->set_lightbox_script( sanitize_key( $_POST['lightbox'] ) ); } } /** * Get gallery page. * * @param array $args * @return void */ public function get_gallery_page( $args ) { // check whether is it valid gallery ajax request if ( $this->gallery_ajax_verified() ) { // cast page number $_GET['rl_page'] = (int) $_POST['page']; // check preview $preview = ( $_POST['preview'] === 'true' ); echo $this->gallery_shortcode( [ 'id' => (int) $_POST['gallery_id'], 'gallery_no' => (int) $_POST['gallery_no'], 'preview' => $preview ] ); } exit; } /** * Generate gallery preview. * * @return void */ public function post_gallery_preview() { // check data if ( ! isset( $_POST['post_id'], $_POST['gallery_id'], $_POST['nonce'], $_POST['page'] ) || ! check_ajax_referer( 'rl-gallery-post', 'nonce', false ) ) wp_send_json_error(); // check page $page = preg_replace( '/[^a-z-.]/i', '', $_POST['page'] ); // check page if ( ! in_array( $page, [ 'widgets.php', 'customize.php', 'post.php', 'post-new.php' ], true ) ) wp_send_json_error(); // check edit_post capability if ( ( $page === 'post.php' || $page === 'post-new.php' ) && ! current_user_can( 'edit_post', (int) $_POST['post_id'] ) ) wp_send_json_error(); // check edit_theme_options capability if ( ( $page === 'widgets.php' || $page === 'customize.php' ) && ! current_user_can( 'edit_theme_options' ) ) wp_send_json_error(); // parse gallery id $gallery_id = (int) $_POST['gallery_id']; // get gallery data $data = get_post_meta( $gallery_id, '_rl_images', true ); // prepare data $attachments = $exclude = []; $html = ''; // get images $images = $this->get_gallery_images( $gallery_id, [ 'exclude' => true, 'limit' => 20 ] ); // get number of images $images_count = (int) get_post_meta( $gallery_id, '_rl_images_count', true ); if ( ! empty( $images ) ) { foreach ( $images as $image ) { $html .= ' <li tabindex="0" role="checkbox" aria-label="' . esc_attr( $image['title'] ) . '" aria-checked="true" data-id="' . esc_attr( $image['id'] ) . '" class="attachment selection selected rl-status-active"> <div class="attachment-preview js--select-attachment type-image ' . esc_attr( $image['thumbnail_orientation'] ). '"> <div class="thumbnail"> <div class="centered"> <img src="' . esc_url( $image['thumbnail_url'] ) . '" draggable="false" alt="" /> </div> </div> </div> </li>'; } } // send attachments content wp_send_json_success( array( 'attachments' => $html, 'count' => esc_html( sprintf( _n( '%s image', '%s images', $images_count, 'responsive-lightbox' ), $images_count ) ), 'edit_url' => current_user_can( 'edit_post', $gallery_id ) ? esc_url_raw( admin_url( 'post.php?post=' . $gallery_id . '&action=edit' ) ) : '' ) ); } /** * Get all galleries. * * @return void */ public function post_get_galleries() { // check data if ( ! isset( $_POST['post_id'], $_POST['search'], $_POST['nonce'], $_POST['page'] ) || ! check_ajax_referer( 'rl-gallery-post', 'nonce', false ) ) wp_send_json_error(); // check page $page = preg_replace( '/[^a-z-.]/i', '', $_POST['page'] ); // check page if ( ! in_array( $page, [ 'widgets.php', 'customize.php', 'post.php', 'post-new.php' ], true ) ) wp_send_json_error(); // check edit_post capability if ( ( $page === 'post.php' || $page === 'post-new.php' ) && ! current_user_can( 'edit_post', (int) $_POST['post_id'] ) ) wp_send_json_error(); // check edit_theme_options capability if ( ( $page === 'widgets.php' || $page === 'customize.php' ) && ! current_user_can( 'edit_theme_options' ) ) wp_send_json_error(); $args = array( 'post_type' => 'rl_gallery', 'post_status' => 'publish', 'nopaging' => true, 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC', 'suppress_filters' => false, 'no_found_rows' => true, 'cache_results' => false ); // check category $category = isset( $_POST['category'] ) ? (int) $_POST['category'] : 0; // specific category? if ( ! empty( $category ) ) { $args['tax_query'] = array( array( 'taxonomy' => 'rl_category', 'field' => 'term_id', 'operator' => 'IN', 'include_children' => false, 'terms' => $category ) ); } $search = wp_unslash( trim( $_POST['search'] ) ); if ( $search !== '' ) $args['s'] = $search; // get galleries $query = new WP_Query( $args ); $html = ''; $ids = []; // any galleries? if ( ! empty( $query->posts ) ) { foreach ( $query->posts as $gallery ) { // save gallery id $ids[] = (int) $gallery->ID; // get featured image $featured = $this->get_featured_image_src( $gallery->ID ); if ( is_array( $featured ) && array_key_exists( 'url', $featured ) ) $featured_image = $featured['url']; else $featured_image = ''; // get title $title = $gallery->post_title !== '' ? $gallery->post_title : esc_html__( '(no title)', 'responsive-gallery' ); $html .= ' <li tabindex="0" role="checkbox" aria-label="' . esc_attr( $title ) . '" aria-checked="true" data-id="' . (int) $gallery->ID . '" class="attachment selection"> <div class="attachment-preview js--select-attachment type-image ' . ( ! empty( $featured['thumbnail_orientation'] ) ? esc_attr( $featured['thumbnail_orientation'] ) : 'landscape' ) . '"> <div class="thumbnail"> <div class="centered" data-full-src="' . esc_url( $featured_image ) . '"> ' . $this->get_featured_image( $gallery->ID, 'thumbnail' ) . ' </div> <div class="filename"> <div>' . esc_html( $title ) . '</div> </div> </div> </div> <button type="button" class="button-link check"><span class="media-modal-icon"></span><span class="screen-reader-text">' . esc_html__( 'Deselect', 'responsive-lightbox' ) . '</span></button> </li>'; } } // send galleries content wp_send_json_success( [ 'galleries' => $ids, 'html' => $html ] ); } /** * Get gallery content based on request. * * @return void */ public function get_menu_content() { if ( ! isset( $_POST['post_id'], $_POST['tab'], $_POST['menu_item'], $_POST['nonce'] ) || ! check_ajax_referer( 'rl-gallery', 'nonce', false ) ) wp_send_json_error(); // check tab $tab = isset( $_POST['tab'] ) ? sanitize_key( $_POST['tab'] ) : ''; if ( ! array_key_exists( $tab, $this->tabs ) ) wp_send_json_error(); // get post id $post_id = (int) $_POST['post_id']; if ( ! current_user_can( 'edit_post', $post_id ) ) wp_send_json_error(); // check menu item $menu_item = sanitize_key( $_POST['menu_item'] ); // get selected menu item $menu_item = ! empty( $menu_item ) && in_array( $menu_item, array_keys( $this->tabs[$tab]['menu_items'] ) ) ? $menu_item : key( $this->tabs[$tab]['menu_items'] ); // get tab content wp_send_json_success( $this->get_metabox_content( $tab, get_post_meta( $post_id, '_rl_' . $tab, true ), $menu_item, $post_id ) ); } /** * Get gallery preview content based on request. * * @return void */ public function get_gallery_preview_content() { // initial checks if ( ! isset( $_POST['post_id'], $_POST['menu_item'], $_POST['nonce'], $_POST['preview_type'] ) || ! check_ajax_referer( 'rl-gallery', 'nonce', false ) ) wp_send_json_error(); // cast gallery ID $post_id = (int) $_POST['post_id']; // check user privileges if ( ! current_user_can( 'edit_post', $post_id ) || ! current_user_can( 'upload_files' ) ) wp_send_json_error(); // get query args $args = ! empty( $_POST['query'] ) ? wp_unslash( $_POST['query'] ) : []; // check orderby if ( array_key_exists( 'orderby', $args ) ) { $args['post_orderby'] = $args['orderby']; unset( $args['orderby'] ); } // check order if ( array_key_exists( 'order', $args ) ) { $args['post_order'] = $args['order']; unset( $args['order'] ); } // check preview type $preview_type = sanitize_key( $_POST['preview_type'] ); // check preview type if ( ! in_array( $preview_type, [ 'page', 'update' ], true ) ) $args['preview_type'] = 'page'; else $args['preview_type'] = $preview_type; // check menu item $menu_item = sanitize_key( $_POST['menu_item'] ); // set images menu item $menu_item = $this->menu_item = ! empty( $menu_item ) && array_key_exists( $menu_item, $this->tabs['images']['menu_items'] ) ? $menu_item : 'media'; if ( $this->fields['images'][$menu_item]['attachments']['preview']['pagination'] ) { if ( isset( $args['preview_page'] ) ) $args['preview_page'] = (int) $args['preview_page']; else $args['preview_page'] = 1; } // get images $images = $this->get_gallery_images( $post_id, $args ); // prepare JSON array $data = []; if ( $menu_item === 'remote_library' ) { // get main instance $rl = Responsive_Lightbox(); $response_data = []; // single provider? if ( $args['media_provider'] !== 'all' ) { // get provider $provider = $rl->providers[$args['media_provider']]; // add response data arguments if needed if ( ! empty( $provider['response_args'] ) ) { $response = $provider['instance']->get_response_data(); foreach ( $provider['response_args'] as $arg ) { if ( array_key_exists( $arg, $response ) ) $response_data[$provider['slug']][$arg] = base64_encode( wp_json_encode( $response[$arg] ) ); } } } else { // get active providers $providers = $rl->remote_library->get_active_providers(); if ( ! empty( $providers ) ) { foreach ( $providers as $provider ) { // get provider $provider = $rl->providers[$provider]; // add response data arguments if needed if ( ! empty( $provider['response_args'] ) ) { $response = $provider['instance']->get_response_data(); foreach ( $provider['response_args'] as $arg ) { if ( array_key_exists( $arg, $response ) ) $response_data[$provider['slug']][$arg] = base64_encode( wp_json_encode( $response[$arg] ) ); } } } } } $data['response_data'] = $response_data; } // parse excluded images $excluded = ! empty( $_POST['excluded'] ) && is_array( $_POST['excluded'] ) ? array_map( 'intval', $_POST['excluded'] ) : []; // get excluded images if ( ! empty( $excluded ) ) $excluded = array_unique( array_filter( $excluded ) ); // get media item template $media_item_template = $this->get_media_item_template( $this->fields['images'][$menu_item]['attachments']['preview'] ); // build html $html = ''; // any images? if ( ! empty( $images ) ) { foreach ( $images as $image ) { // get image content html $html .= $this->get_gallery_preview_image_content( $image, 'images', $menu_item, 'attachments', $media_item_template, $excluded, $image['id'] ); } } $data['images'] = $html; if ( $this->fields['images'][$menu_item]['attachments']['preview']['pagination'] ) $data['pagination'] = $this->get_preview_pagination( $args['preview_page'] ); // send JSON wp_send_json_success( $data ); } /** * Get gallery preview image content HTML. * * @param array $image * @param string $tab_id * @param string $menu_item * @param string $field_name * @param string $template * @param array $excluded * @param string|int $excluded_item * @return string */ public function get_gallery_preview_image_content( $image, $tab_id, $menu_item, $field_name, $template, $excluded, $excluded_item = '' ) { // set flag if ( empty( $excluded_item ) ) $excluded_flag = false; else $excluded_flag = in_array( $excluded_item, $excluded, true ); if ( $image['type'] === 'embed' ) { // replace all embed data $media_html = str_replace( [ '__EMBED_ID__', '__EMBED_URL__', '__EMBED_WIDTH__', '__EMBED_HEIGHT__', '__EMBED_THUMBNAIL_URL__', '__EMBED_THUMBNAIL_WIDTH__', '__EMBED_THUMBNAIL_HEIGHT__', '__EMBED_TITLE__', '__EMBED_DESCRIPTION__', '__EMBED_DATE__' ], [ esc_attr( $image['id'] ), esc_url( $image['url'] ), (int) $image['width'], (int) $image['height'], esc_url( $image['thumbnail_url'] ), (int) $image['thumbnail_width'], (int) $image['thumbnail_height'], esc_attr( $image['title'] ), esc_textarea( $image['caption'] ), esc_attr( $image['date'] ) ], $this->get_media_embed_template( false ) ); } else $media_html = ''; // replace id and url of an image return str_replace( [ '__MEDIA_DATA__', '__MEDIA_ID__', '__MEDIA_STATUS__', '__MEDIA_TYPE__' ], [ $this->get_media_exclude_input_template( $tab_id, $menu_item, $field_name, $excluded_flag ? $excluded_item : '' ) . $media_html . $image['thumbnail_link'], esc_attr( $image['id'] ), $excluded_flag ? ' rl-status-inactive' : ' rl-status-active', esc_attr( $image['type'] ) ], $template ); } /** * Get gallery image link. * * @param array $image Image data * @param mixed $size Image size * @param array $attr Image attributes * @return string */ public function get_gallery_image_link( $image, $size = 'thumbnail', $attr = [] ) { $link = ''; if ( $size === 'thumbnail' ) { $url = $image['thumbnail_url']; $width = $image['thumbnail_width']; $height = $image['thumbnail_height']; } else { $url = $image['url']; $width = $image['width']; $height = $image['height']; } if ( ! empty( $image['url'] ) ) { $size_class = $size; if ( is_array( $size_class ) ) $size_class = join( 'x', $size_class ); // combine attributes $attr = wp_parse_args( $attr, array( 'src' => $url, 'class' => 'attachment-' . $size_class . ' size-' . $size_class . ' format-' . ( $height > $width ? 'portrait' : 'landscape' ), 'alt' => $image['alt'] ) ); // apply filters if any $attr = apply_filters( 'rl_get_gallery_image_attributes', $attr, $image, $size ); // start link output $link = rtrim( '<img ' . image_hwstring( $width, $height ) ); // add attributes foreach ( $attr as $name => $value ) { $link .= ' ' . esc_attr( $name ) . '="' . ( $name === 'src' ? esc_url( $value ) : esc_attr( $value ) ) . '"'; } // end link output $link .= ' />'; } return apply_filters( 'rl_get_gallery_image_link', $link, $image, $size ); } /** * Get attachment image source. * * @param int|string|array $image Attachment ID, image URL or array of image data * @param string $image_size Image size * @param string $thumbnail_size Thumbnail size * @return array */ public function get_gallery_image_src( $image, $image_size = 'large', $thumbnail_size = 'thumbnail' ) { $imagedata = []; // check difference in size between image and thumbnail $diff_sizes = $thumbnail_size !== $image_size; // attachment id? if ( is_int( $image ) ) { if ( $image ) { $type = 'image'; $width = 0; $height = 0; // image src if ( wp_attachment_is_image( $image ) ) { $image_src = wp_get_attachment_image_src( $image, $image_size, false ); // different image and thumbnail sizes? if ( $diff_sizes ) $thumbnail_src = wp_get_attachment_image_src( $image, $thumbnail_size, false ); else $thumbnail_src = $image_src; $file_url = $image_src[0]; $width = $image_src[1]; $height = $image_src[2]; $thumbnail_url = $thumbnail_src[0]; $thumbnail_width = $thumbnail_src[1]; $thumbnail_height = $thumbnail_src[2]; // video, blank thumbnail src } elseif ( rl_current_lightbox_supports( 'video' ) && wp_attachment_is( 'video', $image ) ) { $type = 'video'; $thumbnail_id = $this->get_video_thumbnail_id( $image ); $thumbnail_src = wp_get_attachment_image_src( $thumbnail_id, $image_size, false ); // get video metadata $meta = wp_get_attachment_metadata( $image ); if ( $meta ) { $width = $meta['width']; $height = $meta['height']; } else { $width = $thumbnail_src[1]; $height = $thumbnail_src[2]; } // different image and thumbnail sizes? if ( $diff_sizes ) $thumbnail_src = wp_get_attachment_image_src( $thumbnail_id, $thumbnail_size, false ); // file url $file_url = wp_get_attachment_url( $image ); $thumbnail_url = $thumbnail_src[0]; $thumbnail_width = $thumbnail_src[1]; $thumbnail_height = $thumbnail_src[2]; } // get alternative text $alt = get_post_meta( $image, '_wp_attachment_image_alt', true ); // allow only strings if ( ! is_string( $alt ) ) $alt = ''; $imagedata = array( 'id' => $image, 'title' => get_the_title( $image ), 'date' => get_the_date( 'Y-m-d H:i:s', $image ), 'caption' => '', 'alt' => $alt, 'url' => $file_url, // $image_src[0], 'width' => $width, 'height' => $height, 'orientation' => $height > $width ? 'portrait' : 'landscape', 'thumbnail_url' => $thumbnail_url, 'thumbnail_width' => $thumbnail_width, 'thumbnail_height' => $thumbnail_height, 'type' => $type ); if ( $diff_sizes ) $imagedata['thumbnail_orientation'] = $thumbnail_src[2] > $thumbnail_src[1] ? 'portrait' : 'landscape'; else $imagedata['thumbnail_orientation'] = $imagedata['orientation']; } // image url } elseif ( is_string( $image ) ) { $imagedata['url'] = $image; @list( $imagedata['width'], $imagedata['height'] ) = rl_get_image_size_by_url( $imagedata['url'] ); $imagedata = array( 'id' => 0, 'title' => '', 'date' => '', 'caption' => '', 'alt' => '', 'url' => $imagedata['url'], 'width' => $imagedata['width'], 'height' => $imagedata['height'], 'orientation' => $imagedata['height'] > $imagedata['width'] ? 'portrait' : 'landscape', 'thumbnail_url' => $imagedata['url'], 'thumbnail_width' => $imagedata['width'], 'thumbnail_height' => $imagedata['height'], 'type' => 'image' ); $imagedata['thumbnail_orientation'] = $imagedata['orientation']; // full image array } elseif ( is_array( $image ) ) { // set width and height from url, if not available if ( empty( $image['width'] ) || empty( $image['height'] ) ) @list( $image['width'], $image['height'] ) = rl_get_image_size_by_url( $image['url'] ); // set thumbnail data, if not available if ( empty( $image['thumbnail_url'] ) ) { $image['thumbnail_url'] = $image['url']; $image['thumbnail_width'] = $image['width']; $image['thumbnail_height'] = $image['height']; } else { // set thumbnail width and height from url, if not available if ( empty( $image['thumbnail_width'] ) || empty( $image['thumbnail_height'] ) ) @list( $image['thumbnail_width'], $image['thumbnail_height'] ) = rl_get_image_size_by_url( $image['thumbnail_url'] ); } $imagedata = array( 'id' => ! empty( $image['id'] ) ? ( preg_match( '/^e\d+$/', $image['id'] ) === 1 ? $image['id'] : (int) $image['id'] ) : 0, 'title' => ! empty( $image['title'] ) ? ( $image['title'] ) : '', 'date' => ! empty( $image['date'] ) ? ( $image['date'] ) : '', 'caption' => ! empty( $image['caption'] ) ? ( $image['caption'] ) : '', 'alt' => ! empty( $image['alt'] ) ? ( $image['alt'] ) : '', 'url' => ! empty( $image['url'] ) ? esc_url_raw( $image['url'] ) : '', 'width' => ! empty( $image['width'] ) ? (int) $image['width'] : 0, 'height' => ! empty( $image['height'] ) ? (int) $image['height'] : 0, 'thumbnail_url' => ! empty( $image['thumbnail_url'] ) ? esc_url_raw( $image['thumbnail_url'] ) : '', 'thumbnail_width' => ! empty( $image['thumbnail_width'] ) ? (int) $image['thumbnail_width'] : 0, 'thumbnail_height' => ! empty( $image['thumbnail_height'] ) ? (int) $image['thumbnail_height'] : 0, 'link' => ! empty( $image['link'] ) ? esc_url_raw( $image['link'] ) : '', 'thumbnail_link' => ! empty( $image['thumbnail_link'] ) ? esc_url_raw( $image['thumbnail_link'] ) : '', 'type' => ! empty( $image['type'] ) ? ( $image['type'] ) : 'image' ); $imagedata['orientation'] = $imagedata['height'] > $imagedata['width'] ? 'portrait' : 'landscape'; $imagedata['thumbnail_orientation'] = $imagedata['thumbnail_height'] > $imagedata['thumbnail_width'] ? 'portrait' : 'landscape'; } if ( ! empty( $imagedata ) ) { // link does not exist? if ( empty( $imagedata['link'] ) ) $imagedata['link'] = $this->get_gallery_image_link( $imagedata, $image_size ); // thumbnail link does not exist? if ( empty( $imagedata['thumbnail_link'] ) ) { // different image and thumbnail sizes? if ( $diff_sizes ) $imagedata['thumbnail_link'] = $this->get_gallery_image_link( $imagedata, $thumbnail_size ); else $imagedata['thumbnail_link'] = $imagedata['link']; } } return apply_filters( 'rl_get_gallery_image_src', $imagedata, $image, $image_size, $thumbnail_size ); } /** * Get gallery featured image. * * @param int $gallery_id * @param string $size Image size * @param array $attr Image attributes * @return string */ public function get_featured_image( $gallery_id, $size = 'thumbnail', $attr = [] ) { $image = $this->get_featured_image_src( $gallery_id ); $html = ''; if ( $image ) $html = $this->get_gallery_image_link( $this->get_gallery_image_src( $image, 'large', $size ), $size, $attr ); return apply_filters( 'rl_get_featured_image', $html, $gallery_id, $size ); } /** * Get gallery featured image data. * * @param int $gallery_id * @return array */ public function get_featured_image_src( $gallery_id ) { // get featured image data $featured_image_type = get_post_meta( $gallery_id, '_rl_featured_image_type', true ); $featured_image = get_post_meta( $gallery_id, '_rl_featured_image', true ); switch ( $featured_image_type ) { // custom url case 'url': $image = esc_url( $featured_image ); break; // attachment id case 'id': $featured_image = (int) $featured_image; $image = wp_attachment_is_image( $featured_image ) ? $featured_image : $this->maybe_generate_thumbnail(); break; // first image case 'image': default: // get first gallery image $images = $this->get_gallery_images( $gallery_id, [ 'exclude' => true, 'limit' => 1 ] ); // set image data if ( $images ) $image = reset( $images ); else $image = 0; } return apply_filters( 'rl_get_featured_image_src', $image, $gallery_id, $featured_image_type, $featured_image ); } /** * Get featured gallery attachments. * * @param array $args * @return array */ public function gallery_query( $args ) { $attachments = []; // get fields $fields = $this->fields['images']['featured']; // force these settings $args['fields'] = 'ids'; $args['tax_query'] = []; $args['meta_query'] = []; $args['author__in'] = []; $args['post_parent__in'] = []; // get image source $args['image_source'] = isset( $args['image_source'] ) && array_key_exists( $args['image_source'], $fields['image_source']['options'] ) ? $args['image_source'] : $fields['image_source']['default']; // get images per post $args['images_per_post'] = isset( $args['images_per_post'] ) ? absint( $args['images_per_post'] ) : $fields['images_per_post']['default']; // get number of posts $args['number_of_posts'] = isset( $args['number_of_posts'] ) ? (int) $args['number_of_posts'] : $fields['number_of_posts']['default']; // get all posts? if ( $args['number_of_posts'] <= 0 ) $args['number_of_posts'] = -1; // convert to wp query arg $args['posts_per_page'] = $args['number_of_posts']; $args['order'] = isset( $args['order'] ) && array_key_exists( $args['order'], $fields['order']['options'] ) ? $args['order'] : $fields['order']['default']; $args['orderby'] = isset( $args['orderby'] ) && array_key_exists( $args['orderby'], $fields['orderby']['options'] ) ? $args['orderby'] : $fields['orderby']['default']; $args['offset'] = isset( $args['offset'] ) ? absint( $args['offset'] ) : 0; $tax_queries = array( 'post_format' => [], 'post_term' => [] ); $meta_queries = array( 'page_template' => [], 'image_source' => [] ); // post type if ( ! empty( $args['post_type'] ) ) { // assign post types $post_types = $args['post_type']; // clear post types $args['post_type'] = []; foreach ( $post_types as $post_type ) { if ( array_key_exists( $post_type, $fields['post_type']['options'] ) ) $args['post_type'][] = $post_type; } } else $args['post_type'] = $this->get_post_types( true ); // post status if ( ! empty( $args['post_status'] ) ) { // assign post statuses $post_statuses = $args['post_status']; // clear post statuses $args['post_status'] = []; foreach ( $post_statuses as $post_status ) { if ( array_key_exists( $post_status, $fields['post_status']['options'] ) ) $args['post_status'][] = $post_status; } } // post format if ( ! empty( $args['post_format'] ) ) { // assign post formats $post_formats = $args['post_format']; foreach ( $post_formats as $post_format ) { if ( array_key_exists( $post_format, $fields['post_format']['options'] ) ) { // standard format? if ( $post_format === 'standard' ) { $tax_queries['post_format'][] = array( 'relation' => 'OR', array( 'taxonomy' => 'post_format', 'field' => 'slug', 'terms' => array( 'post-format-standard' ) ), array( 'taxonomy' => 'post_format', 'field' => 'slug', 'operator' => 'NOT EXISTS' ) ); } else { $tax_queries['post_format'][] = array( 'taxonomy' => 'post_format', 'field' => 'slug', 'terms' => array( 'post-format-' . $post_format ) ); } } } unset( $args['post_format'] ); } // page template if ( ! empty( $args['page_template'] ) ) { foreach ( $args['page_template'] as $page_template ) { if ( array_key_exists( $page_template, $fields['page_template']['options'] ) ) { if ( $page_template === 'default' ) { $meta_queries['page_template'][] = array( 'relation' => 'OR', array( 'key' => '_wp_page_template', 'value' => 'default' ), array( 'key' => '_wp_page_template', 'value' => '' ), array( 'key' => '_wp_page_template', 'compare' => 'NOT EXISTS' ) ); } else { $meta_queries['page_template'][] = array( 'key' => '_wp_page_template', 'value' => $page_template ); } } } } // post author if ( ! empty( $args['post_author'] ) ) { foreach ( $args['post_author'] as $post_author ) { if ( array_key_exists( $post_author, $fields['post_author']['options'] ) ) $args['author__in'][] = $post_author; } } // page parent if ( ! empty( $args['page_parent'] ) ) { foreach ( $args['page_parent'] as $page_parent ) { if ( array_key_exists( $page_parent, $fields['page_parent']['options'] ) ) $args['post_parent__in'][] = $page_parent; } } // post term if ( ! empty( $args['post_term'] ) ) { $terms = []; // get all terms if ( ! empty( $fields['post_term']['options'] ) ) { foreach ( $fields['post_term']['options'] as $tax => $data ) { $terms = array_merge( $terms, array_map( 'intval', array_keys( $data['terms'] ) ) ); } } foreach ( $args['post_term'] as $post_term ) { if ( in_array( $post_term, $terms ) ) { $term = get_term( $post_term ); $tax_queries['post_term'][] = array( 'taxonomy' => $term->taxonomy, 'field' => 'term_id', 'terms' => (int) $post_term ); } } } switch ( $args['image_source'] ) { case 'thumbnails': $meta_queries['image_source'][] = array( 'relation' => 'OR', array( 'key' => '_thumbnail_id', 'compare' => 'EXISTS' ) ); } // any tax queries? if ( ! empty( $tax_queries['post_term'] ) || ! empty( $tax_queries['post_format'] ) ) { $args['tax_query'] = array( 'relation' => 'AND' ); if ( ! empty( $tax_queries['post_term'] ) ) $args['tax_query'][] = array( 'relation' => 'OR' ) + $tax_queries['post_term']; if ( ! empty( $tax_queries['post_format'] ) ) $args['tax_query'][] = array( 'relation' => 'OR' ) + $tax_queries['post_format']; } // any tax queries? if ( ! empty( $meta_queries['page_template'] ) || ! empty( $meta_queries['image_source'] ) ) { $args['meta_query'] = array( 'relation' => 'AND' ); if ( ! empty( $meta_queries['page_template'] ) ) $args['meta_query'][] = array( 'relation' => 'OR', $meta_queries['page_template'] ); if ( ! empty( $meta_queries['image_source'] ) ) $args['meta_query'][] = array( 'relation' => 'OR', $meta_queries['image_source'] ); } // get posts $query = new WP_Query( apply_filters( 'rl_gallery_query_args', $args ) ); // get attachments if ( $query->have_posts() ) $attachments = $this->get_gallery_query_attachments( $query->posts, $args ); return $attachments; } /** * Get query attachments. * * @param array $posts Post IDs, array or objects * @param array $args Additional arguments * @return array */ public function get_gallery_query_attachments( $posts, $args ) { $attachments = []; // any posts? if ( ! empty( $posts ) ) { switch ( $args['image_source'] ) { case 'thumbnails': $nop = count( $posts ) - 1; foreach ( $posts as $number => $post_id ) { $attachment_id = (int) get_post_thumbnail_id( $post_id ); // real attachment? if ( wp_attachment_is_image( $attachment_id ) ) $attachments[] = $attachment_id; else continue; if ( $args['preview'] ) { $attachments = array_unique( $attachments ); $noa = count( $attachments ); if ( ( $noa >= ( $args['preview_per_page'] * $args['preview_page'] ) ) || $nop === $number ) { $attachments = array_slice( $attachments, ( $args['preview_page'] - 1 ) * $args['preview_per_page'], $args['preview_per_page'], false ); break; } } } break; case 'attached_images': $nop = count( $posts ) - 1; foreach ( $posts as $number => $post_id ) { // get attached images, do not use get_attached_media here! $attachment_ids = (array) get_children( array( 'post_parent' => $post_id, 'post_status' => 'inherit', 'post_type' => 'attachment', 'post_mime_type' => 'image', 'posts_per_page' => $args['images_per_post'], 'order' => 'ASC', 'orderby' => 'menu_order', 'nopaging' => false, 'page' => 1, 'fields' => 'ids' ) ); if ( $attachment_ids ) { foreach ( $attachment_ids as $attachment_id ) { if ( ! empty( $attachment_id ) ) { $attachments[] = $attachment_id; } } } if ( $args['preview'] ) { $attachments = array_unique( $attachments ); $noa = count( $attachments ); if ( ( $noa >= ( $args['preview_per_page'] * $args['preview_page'] ) ) || $nop === $number ) { $attachments = array_slice( $attachments, ( $args['preview_page'] - 1 ) * $args['preview_per_page'], $args['preview_per_page'], false ); break; } } } } } return apply_filters( 'rl_get_gallery_query_attachments', array_unique( $attachments ), $posts, $args ); } /** * Load featured content query args. * * @global string $pagenow * * @return void */ public function init_admin() { global $pagenow; // check values $post = isset( $_GET['post'] ) ? (int) $_GET['post'] : 0; $post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0; $action = isset( $_POST['action'] ) ? sanitize_key( $_POST['action'] ) : ''; $post_type = isset( $_POST['post_type'] ) ? sanitize_key( $_POST['post_type'] ) : ''; // prepare query arguments if needed if ( ( $pagenow === 'post.php' && ( ( $post && get_post_type( $post ) === 'rl_gallery' ) || ( $post_id && get_post_type( $post_id ) === 'rl_gallery' ) ) ) || ( in_array( $pagenow, array( 'edit.php', 'post-new.php'), true ) && $post_type === 'rl_gallery' ) || ( $pagenow === 'admin-ajax.php' && $action && in_array( $action, array( 'rl-get-preview-content', 'rl-post-gallery-preview', 'rl-get-menu-content' ), true ) ) ) $this->fields['images']['featured'] = $this->prepare_featured_fields( $this->fields['images']['featured'] ); // add default thumbnail image if needed if ( Responsive_Lightbox()->options['builder']['gallery_builder'] && $pagenow === 'edit.php' && $post_type && $post_type === 'rl_gallery' ) $this->maybe_generate_thumbnail(); } /** * Generate post thumbnail replacement. * * @return int */ public function maybe_generate_thumbnail() { // get old attachment $thumbnail_id = get_posts( array( 'name' => 'responsive-lightbox-thumbnail', 'post_type' => 'attachment', 'post_status' => 'inherit', 'numberposts' => 1, 'fields' => 'ids' ) ); // no attachment? if ( empty( $thumbnail_id ) ) { // get new attachment $thumbnail_id = get_posts( array( 'name' => 'responsive-lightbox-thumbnail', 'post_type' => 'attachment', 'post_status' => 'pending', 'numberposts' => 1, 'fields' => 'ids' ) ); // no attachment? if ( empty( $thumbnail_id ) ) { // get upload directory data $wp_upload_dir = wp_upload_dir(); // get file path $filepath = str_replace( '\\', '/', RESPONSIVE_LIGHTBOX_PATH . 'images/responsive-lightbox-thumbnail.png' ); // get file name $filename = basename( $filepath ); // new filepath in upload dir $new_filepath = $wp_upload_dir['path'] . '/' . $filename; // copty file to upload dir copy( $filepath, $new_filepath ); // get type of file $filetype = wp_check_filetype( $filename ); // force pending status for the attachment add_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); // insert attachment $thumbnail_id = wp_insert_attachment( array( 'guid' => $wp_upload_dir['url'] . '/' . $filename, 'post_mime_type' => $filetype['type'], 'post_title' => preg_replace( '/\.[^.]+$/', '', $filename ), 'post_content' => '', 'post_parent' => 0, 'post_status' => 'inherit' ), $new_filepath, 0 ); remove_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); // success? if ( $thumbnail_id ) { // make sure that this file is included require_once( ABSPATH . 'wp-admin/includes/image.php' ); // update database with generated metadata for the attachment wp_update_attachment_metadata( $thumbnail_id, wp_generate_attachment_metadata( $thumbnail_id, $new_filepath ) ); } } else $thumbnail_id = $thumbnail_id[0]; } else { // force pending status for the attachment add_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); $thumbnail_id = wp_update_post( array( 'ID' => $thumbnail_id[0], 'post_status' => 'pending' ) ); remove_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); } return (int) $thumbnail_id; } /** * Get video thumbnail replacement. * * @param int $post_id * @return int */ public function get_video_thumbnail_id( $post_id ) { $thumbnail_id = 0; // try to get video thumbnail $attachment_id = (int) get_post_thumbnail_id( $post_id ); // real attachment? if ( wp_attachment_is_image( $attachment_id ) ) $thumbnail_id = $attachment_id; // try to get default video poster image if ( ! $thumbnail_id ) { $thumbnail_id = get_posts( array( 'name' => 'responsive-lightbox-video-thumbnail', 'post_type' => 'attachment', 'post_status' => 'inherit', 'numberposts' => 1, 'fields' => 'ids' ) ); } // no attachment? if ( ! $thumbnail_id ) { // get new attachment $thumbnail_id = get_posts( array( 'name' => 'responsive-lightbox-video-thumbnail', 'post_type' => 'attachment', 'post_status' => 'pending', 'numberposts' => 1, 'fields' => 'ids' ) ); // no attachment? if ( ! $thumbnail_id ) { // get upload directory data $wp_upload_dir = wp_upload_dir(); // get file path $filepath = str_replace( '\\', '/', RESPONSIVE_LIGHTBOX_PATH . 'images/responsive-lightbox-video-thumbnail.png' ); // get file name $filename = basename( $filepath ); // new filepath in upload dir $new_filepath = $wp_upload_dir['path'] . '/' . $filename; // copty file to upload dir copy( $filepath, $new_filepath ); // get type of file $filetype = wp_check_filetype( $filename ); // force pending status for the attachment add_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); // insert attachment $thumbnail_id = wp_insert_attachment( array( 'guid' => $wp_upload_dir['url'] . '/' . $filename, 'post_mime_type' => $filetype['type'], 'post_title' => preg_replace( '/\.[^.]+$/', '', $filename ), 'post_content' => '', 'post_parent' => 0, 'post_status' => 'inherit' ), $new_filepath, 0 ); remove_filter( 'wp_insert_attachment_data', array( $this, 'set_attachment_post_status' ) ); // success? if ( $thumbnail_id ) { // make sure that this file is included require_once( ABSPATH . 'wp-admin/includes/image.php' ); // update database with generated metadata for the attachment wp_update_attachment_metadata( $thumbnail_id, wp_generate_attachment_metadata( $thumbnail_id, $new_filepath ) ); } } else $thumbnail_id = $thumbnail_id[0]; } return (int) $thumbnail_id; } /** * Change status of new attachment thumbnail replacement. * * @param array $data * @return array */ function set_attachment_post_status( $data ) { $data['post_status'] = 'pending'; return $data; } /** * Prepare featured content fields. * * @param array $fields * @return array */ public function prepare_featured_fields( $fields ) { foreach ( array( 'post_type', 'post_status', 'post_format', 'post_term', 'post_author', 'page_parent', 'page_template' ) as $option ) { $fields[$option]['options'] = $this->prepare_query_args( $option ); } return $fields; } /** * Prepare values option list. * * @param string $type * @return array */ public function prepare_query_args( $type = '' ) { $html = ''; switch( $type ) { case 'post_type': $data = $this->get_post_types(); break; case 'post_status': $data = $this->get_post_statuses(); break; case 'post_format': $data = $this->get_post_formats(); break; case 'post_term': $taxonomies = $this->get_taxonomies(); $new_terms = []; if ( ! empty( $taxonomies ) ) { foreach ( $taxonomies as $tax_id => $label ) { $terms = get_terms( array( 'taxonomy' => $tax_id, 'orderby' => 'name', 'order' => 'ASC', 'hide_empty' => false, 'fields' => 'id=>name' ) ); if ( ! empty( $terms ) ) $new_terms[$tax_id] = array( 'label' => $label, 'terms' => $terms ); } } $data = $new_terms; break; case 'post_author': $data = $this->get_users(); break; case 'page_parent': $parents = []; $hierarchical = get_post_types( array( 'public' => true, 'hierarchical' => true ), 'objects', 'and' ); if ( ! empty( $hierarchical ) ) { foreach ( $hierarchical as $post_type => $object ) { // get top level hierarchical posts $query = new WP_Query( array( 'post_type' => $post_type, 'post_status' => 'publish', 'nopaging' => true, 'posts_per_page' => -1, 'orderby' => 'title', 'order' => 'ASC', 'suppress_filters' => false, 'no_found_rows' => true, 'cache_results' => false, 'post_parent' => 0 ) ); if ( ! empty( $query->posts ) ) { foreach ( $query->posts as $post ) { $parents[$post->ID] = trim( $post->post_title ) === '' ? __( 'Untitled' ) : $post->post_title; } } } } $data = $parents; break; case 'page_template': $data = $this->get_page_templates(); break; default: $data = []; } return apply_filters( 'rl_galleries_prepare_query_args', $data, $type ); } /** * Get public post types. * * @param bool $simple Which data should be returned * @param bool $skip Which post types should be skipped * @return array */ public function get_post_types( $simple = false, $skip = [ 'attachment', 'rl_gallery' ] ) { $post_types = get_post_types( array( 'public' => true ), 'objects', 'and' ); $data = []; if ( ! empty( $post_types ) ) { foreach ( $post_types as $post_type => $cpt ) { // skip unwanted post types if ( in_array( $post_type, $skip, true ) ) continue; if ( $simple ) $data[] = $post_type; else $data[$post_type] = $cpt->labels->singular_name; } } if ( ! $simple ) asort( $data ); return $data; } /** * Get post statuses. * * @return array */ public function get_post_statuses() { $post_statuses = get_post_stati(); asort( $post_statuses ); // remove inherit post status if ( isset( $post_statuses['inherit'] ) ) unset( $post_statuses['inherit'] ); return $post_statuses; } /** * Get post formats. * * @return array */ public function get_post_formats() { $post_formats = array( 'aside' => __( 'Aside' ), 'audio' => __( 'Audio' ), 'chat' => __( 'Chat' ), 'gallery' => __( 'Gallery' ), 'link' => __( 'Link' ), 'photo' => __( 'Photo' ), 'quote' => __( 'Quote' ), 'standard' => __( 'Standard' ), 'status' => __( 'Status' ), 'video' => __( 'Video' ) ); asort( $post_formats ); return $post_formats; } /** * Get taxonomies. * * @return array */ public function get_taxonomies() { $taxonomies = get_taxonomies( array( 'public' => true ), 'objects', 'and' ); // remove post format if ( array_key_exists( 'post_format', $taxonomies ) ) unset( $taxonomies['post_format'] ); // get main instance $rl = Responsive_Lightbox(); // remove gallery categories if ( $rl->options['builder']['categories'] && array_key_exists( 'rl_category', $taxonomies ) ) unset( $taxonomies['rl_category'] ); // remove gallery tags if ( $rl->options['builder']['tags'] && array_key_exists( 'rl_tag', $taxonomies ) ) unset( $taxonomies['rl_tag'] ); if ( $rl->options['folders']['active'] ) { // remove media folders categories unset( $taxonomies['rl_media_folder'] ); // remove custom media folders categories if ( $rl->options['folders']['media_taxonomy'] !== 'rl_media_folder' ) unset( $taxonomies[$rl->options['folders']['media_taxonomy']] ); // remove media folders tags if ( $rl->options['folders']['media_tags'] ) unset( $taxonomies['rl_media_tag'] ); } $data = []; if ( ! empty( $taxonomies ) ) { foreach ( $taxonomies as $tax_id => $taxonomy ) { $data[$tax_id] = $taxonomy->labels->singular_name; } } // sort taxonomies asort( $data ); return $data; } /** * Get users. * * @return array */ public function get_users() { $users = get_users( array( 'fields' => array( 'ID', 'user_login' ) ) ); $data = []; if ( ! empty( $users ) ) { foreach ( $users as $user ) { $data[(int) $user->ID] = $user->user_login; } } asort( $data ); return $data; } /** * Get page templates. * * @return array */ public function get_page_templates() { $data = []; $page_templates = wp_get_theme()->get_page_templates(); if ( ! empty( $page_templates ) ) asort( $page_templates ); $data = array_merge( array( 'default' => apply_filters( 'default_page_template_title', __( 'Default Template' ) ) ), $page_templates ); return $data; } /** * Fix possible misplaced or hidden metaboxes do to old 'after_title' metabox and possibility to move internal metaboxes. * * @return void */ public function clear_metaboxes( $screen ) { global $pagenow; if ( ! ( ( $pagenow === 'post.php' || $pagenow === 'post-new.php' ) && ! empty( $screen->post_type ) && $screen->post_type === 'rl_gallery' && empty( $_POST['rl_gallery'] ) ) ) return; // get user id $user_id = get_current_user_id(); // get rl metaboxes $order = get_user_meta( $user_id, 'meta-box-order_rl_gallery', true ); // any metabox order? fix possible misplaced metaboxes if ( is_array( $order ) && ! empty( $order ) ) { // save metaboxes $_order = $order; // default rl metaboxes $rl_boxes = [ 'responsive-gallery-images', 'responsive-gallery-config', 'responsive-gallery-design', 'responsive-gallery-paging', 'responsive-gallery-lightbox', 'responsive-gallery-misc' ]; foreach ( $_order as $group => $metaboxes ) { if ( $group === 'after_title' ) { // remove deprecated after_title metabox unset( $order['after_title'] ); } elseif ( $metaboxes !== '' ) { $boxes = explode( ',', $metaboxes ); $new_boxes = []; foreach ( $boxes as $box ) { if ( ! in_array( $box, $rl_boxes, true ) ) $new_boxes[] = $box; } if ( ! empty( $new_boxes ) ) $order[$group] = implode( ',', $new_boxes ); else $order[$group] = ''; } } // remove default metaboxes storage if ( array_key_exists( 'responsive_lightbox_metaboxes', $order ) ) unset( $order['responsive_lightbox_metaboxes'] ); // update usermeta to prevent issues with rl metaboxes if ( $order !== $_order ) update_user_meta( $user_id, 'meta-box-order_rl_gallery', $order ); } } /** * Save gallery metadata. * * @param int $post_id * @param object $post * @param bool $update Whether existing post is being updated or not * @return void */ public function save_post( $post_id, $post, $update ) { // check action $action = isset( $_GET['action'] ) ? sanitize_key( $_GET['action'] ) : ''; if ( wp_is_post_revision( $post_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || ! $update || in_array( $post->post_status, array( 'trash', 'auto-draft' ), true ) || ( $action === 'untrash' ) || empty( $_POST['rl_gallery'] ) ) return; // save gallery $this->save_gallery( wp_unslash( $_POST ), $post_id ); } /** * Save gallery preview metadata. * * @param array $post_data Gallery data * @param int $post_id * @param bool $preview Whether is it preview * @return void */ public function save_gallery( $post_data, $post_id, $preview = false ) { // get gallery data $data = $post_data['rl_gallery']; // prepare sanitized data $safedata = []; // sanitize all fields foreach ( $this->fields as $tab_id => $menu_items ) { switch ( $tab_id ) { case 'config': // get main instance $rl = Responsive_Lightbox(); // add menu item $menu_item = isset( $data[$tab_id], $data[$tab_id]['menu_item'] ) && array_key_exists( $data[$tab_id]['menu_item'], $this->tabs[$tab_id]['menu_items'] ) ? $data[$tab_id]['menu_item'] : reset( $this->tabs[$tab_id]['menu_items'] ); // get default gallery fields $default_gallery_fields = $rl->frontend->get_default_gallery_fields(); // prepare fields if ( $menu_item === 'default' ) $items = $default_gallery_fields; else { // assign settings and defaults $fields = $rl->settings->settings[$menu_item . '_gallery']['fields']; $defaults = $rl->defaults[$menu_item . '_gallery']; // make a copy $fields_copy = $fields; foreach ( $fields_copy as $field_id => $field ) { if ( $field['type'] === 'multiple' ) { foreach ( $field['fields'] as $subfield_id => $subfield ) { $fields[$field_id]['fields'][$subfield_id]['default'] = $defaults[$subfield_id]; } } else $fields[$field_id]['default'] = $defaults[$field_id]; } $items = $rl->frontend->get_unique_fields( $default_gallery_fields, $fields ); } // sanitize fields $safedata = $this->sanitize_fields( $items, $data, $tab_id, $menu_item ); // add menu item $safedata[$tab_id]['menu_item'] = $menu_item; break; default: // add menu item $menu_item = isset( $data[$tab_id], $data[$tab_id]['menu_item'] ) && array_key_exists( $data[$tab_id]['menu_item'], $this->tabs[$tab_id]['menu_items'] ) ? $data[$tab_id]['menu_item'] : 'options'; // sanitize fields $safedata = $this->sanitize_fields( $menu_items[$menu_item], $data, $tab_id, $menu_item ); // add menu item $safedata[$tab_id]['menu_item'] = $menu_item; } $safedata[$tab_id] = apply_filters( 'rl_gallery_tab_metadata', $safedata[$tab_id], $tab_id ); // preview? if ( $preview ) update_metadata( 'post', $post_id, '_rl_' . $tab_id, $safedata[$tab_id] ); else update_post_meta( $post_id, '_rl_' . $tab_id, $safedata[$tab_id] ); } $featured_image_type = ! empty( $post_data['rl_gallery_featured_image'] ) && in_array( $post_data['rl_gallery_featured_image'], array( 'id', 'url', 'image' ), true ) ? $post_data['rl_gallery_featured_image'] : 'id'; switch ( $featured_image_type ) { // custom url case 'url': $thumbnail_id = $this->maybe_generate_thumbnail(); $featured_image = isset( $post_data['_rl_thumbnail_url'] ) ? esc_url_raw( $post_data['_rl_thumbnail_url'] ) : ''; break; // first image case 'image': $thumbnail_id = $this->maybe_generate_thumbnail(); $featured_image = ''; break; // attachment id case 'id': default: $featured_image = $thumbnail_id = isset( $post_data['_thumbnail_id'] ) ? (int) $post_data['_thumbnail_id'] : 0; } // preview? if ( $preview ) { update_metadata( 'post', $post_id, '_rl_featured_image_type', $featured_image_type ); update_metadata( 'post', $post_id, '_rl_featured_image', $featured_image ); update_metadata( 'post', $post_id, '_thumbnail_id', $thumbnail_id ); } else { // update featured image update_post_meta( $post_id, '_rl_featured_image_type', $featured_image_type ); update_post_meta( $post_id, '_rl_featured_image', $featured_image ); update_post_meta( $post_id, '_thumbnail_id', $thumbnail_id ); // save number of images update_post_meta( $post_id, '_rl_images_count', $this->get_gallery_images_number( $post_id ) ); } // update post excerpt if ( isset( $safedata['misc']['options']['gallery_description'] ) ) { remove_action( 'save_post_rl_gallery', [ $this, 'save_post' ], 10, 3 ); $postdata = [ 'ID' => $post_id, 'post_excerpt' => sanitize_textarea_field( $safedata['misc']['options']['gallery_description'] ) ]; wp_update_post( $postdata ); add_action( 'save_post_rl_gallery', [ $this, 'save_post' ], 10, 3 ); } } /** * Check attachments IDs. * * @param array $attachments Attachment ID's * @param array $args * @return array */ public function check_attachments( $attachments, $args = [] ) { // no attachments? if ( empty( $attachments ) || ! is_array( $attachments ) ) return []; // check providers support if ( ! empty( $args['providers'] ) ) $embed = rl_current_lightbox_supports( $args['providers'], 'OR' ); else $embed = false; // no embed data? if ( ! $embed ) $copy = array_map( 'intval', $attachments ); else $copy = $attachments; // check attachments foreach ( $attachments as $key => $attachment_id ) { // embed? if ( $embed && preg_match( '/^e\d+$/', $attachment_id ) === 1 ) { if ( ! in_array( $attachment_id, $args['embed_keys'], true ) ) unset( $copy[$key] ); // video support? } elseif ( rl_current_lightbox_supports( 'video' ) ) { // is it an image or video? if ( ! wp_attachment_is( 'video', $attachment_id ) && ! wp_attachment_is( 'image', $attachment_id ) ) unset( $copy[$key] ); // make sure it's integer elseif ( $embed ) $copy[$key] = (int) $copy[$key]; } else { // is it an image? if ( ! wp_attachment_is_image( $attachment_id ) ) unset( $copy[$key] ); // make sure it's integer elseif ( $embed ) $copy[$key] = (int) $copy[$key]; } } return array_values( $copy ); } /** * Display shortcode metabox. * * @param object $post * @return void */ public function shortcode_metabox( $post ) { echo ' <p>' . esc_html__( 'You can place this gallery anywhere into your posts, pages, custom post types or widgets by using the shortcode below', 'responsive-lightbox' ) . ':</p> <code class="rl-shortcode" data-number="0">[rl_gallery id="' . (int) $post->ID . '"]</code> <p>' . esc_html__( 'You can also place this gallery into your template files by using the template tag below', 'responsive-lightbox' ) . ':</p> <code class="rl-shortcode" data-number="1">if ( function_exists( \'rl_gallery\' ) ) { rl_gallery( \'' . (int) $post->ID . '\' ); }</code>'; } /** * Add new gallery listing columns. * * @param array $columns * @return array */ public function gallery_columns( $columns ) { // find title position $offset = array_search( 'title', array_keys( $columns ) ); // put image column before title $columns = array_merge( array_slice( $columns, 0, $offset ), array( 'image' => esc_html__( 'Gallery', 'responsive-lightbox' ) ), array_slice( $columns, $offset ) ); // put new columns after title $columns = array_merge( array_slice( $columns, 0, $offset + 2 ), array( 'shortcode' => esc_html__( 'Shortcode', 'responsive-lightbox' ), 'type' => esc_html__( 'Type', 'responsive-lightbox' ), 'source' => esc_html__( 'Source', 'responsive-lightbox' ) ), array_slice( $columns, $offset + 2 ) ); return $columns; } /** * Add new gallery listing columns content. * * @global string $pagenow * * @param string $column_name * @param int $post_id * @return void */ public function gallery_columns_content( $column_name, $post_id ) { global $pagenow; if ( $pagenow === 'edit.php' ) { switch ( $column_name ) { case 'image': // get image data, based on gallery source type $image = $this->get_featured_image( $post_id, 'thumbnail' ); $images_count = (int) get_post_meta( $post_id, '_rl_images_count', true ); // display count if ( ! empty( $image ) ) echo '<span class="media-icon image-icon">' . wp_kses_post( $image ) . '</span><span>' . esc_html( sprintf( _n( '%s element', '%s elements', $images_count, 'responsive-lightbox' ), $images_count ) ) . '</span>'; else echo '<span class="media-icon image-icon">' . wp_get_attachment_image( 0, array( 60, 60 ), true, array( 'alt' => '' ) ) . '</span>'; break; case 'shortcode': echo '<code>[rl_gallery id="' . (int) $post_id . '"]</code>'; break; case 'type': $config = get_post_meta( $post_id, '_rl_config', true ); if ( ! empty( $config['menu_item'] ) && array_key_exists( $config['menu_item'], $this->tabs['config']['menu_items'] ) ) { echo esc_html( $this->tabs['config']['menu_items'][$config['menu_item']] ); if ( $config['menu_item'] === 'default' ) echo esc_html( ' (' . $this->tabs['config']['menu_items'][Responsive_Lightbox()->options['settings']['builder_gallery']] . ')' ); } else echo '-'; break; case 'source': $images = get_post_meta( $post_id, '_rl_images', true ); if ( ! empty( $images['menu_item'] ) && array_key_exists( $images['menu_item'], $this->tabs['images']['menu_items'] ) ) echo esc_html( $this->tabs['images']['menu_items'][$images['menu_item']] ); else echo '-'; break; } } } /** * Get size information for all currently-registered image sizes. * * @global array $_wp_additional_image_sizes * * @return array */ public function get_image_sizes() { global $_wp_additional_image_sizes; $sizes = []; foreach ( get_intermediate_image_sizes() as $_size ) { if ( in_array( $_size, [ 'thumbnail', 'medium', 'medium_large', 'large' ] ) ) { $sizes[$_size]['width'] = get_option( "{$_size}_size_w" ); $sizes[$_size]['height'] = get_option( "{$_size}_size_h" ); $sizes[$_size]['crop'] = (bool) get_option( "{$_size}_crop" ); } elseif ( isset( $_wp_additional_image_sizes[$_size] ) ) { $sizes[$_size] = [ 'width' => $_wp_additional_image_sizes[$_size]['width'], 'height' => $_wp_additional_image_sizes[$_size]['height'], 'crop' => $_wp_additional_image_sizes[$_size]['crop'], ]; } } return $sizes; } /** * Get size information for a specific image size. * * @param string $size The image size for which to retrieve data. * @return false|array */ public function get_image_size( $size ) { if ( isset( $this->sizes[$size] ) ) return $this->sizes[$size]; else return false; } /** * Filter the admin post thumbnail HTML markup. * * @param string $content * @param int $post_id * @param int $thumbnail_id * @return string */ public function admin_post_thumbnail_html( $content, $post_id, $thumbnail_id ) { if ( get_post_type( $post_id ) === 'rl_gallery' ) { $value = get_post_meta( $post_id, '_rl_featured_image', true ); $type = get_post_meta( $post_id, '_rl_featured_image_type', true ); $type = ! empty( $type ) && in_array( $type, array( 'image', 'id', 'url' ) ) ? $type : 'image'; // force media library image if ( wp_doing_ajax() ) $type = 'id'; // post featured image is post thumbnail replacement? elseif ( $this->maybe_generate_thumbnail() === (int) $thumbnail_id ) { remove_filter( 'admin_post_thumbnail_html', array( $this, 'admin_post_thumbnail_html' ), 10 ); $content = _wp_post_thumbnail_html( 0, $post_id ); } $content = ' <div class="rl-gallery-featured-image-options"> <p class="howto">' . esc_html__( 'Select gallery featured image source:', 'responsive-lightbox' ) . '</p> <label for="rl-gallery-featured-image"><input id="rl-gallery-featured-image" type="radio" name="rl_gallery_featured_image" value="image" ' . checked( $type, 'image', false ) . ' />' . esc_html__( 'First gallery image', 'responsive-lightbox' ) . '</label><br /> <label for="rl-gallery-featured-id"><input id="rl-gallery-featured-id" type="radio" name="rl_gallery_featured_image" value="id" ' . checked( $type, 'id', false ) . ' />' . esc_html__( 'Media Library', 'responsive-lightbox' ) . '</label><br /> <label for="rl-gallery-featured-url"><input id="rl-gallery-featured-url" type="radio" name="rl_gallery_featured_image" value="url" ' . checked( $type, 'url', false ) . ' />' . esc_html__( 'Custom URL', 'responsive-lightbox' ) . '</label> </div> <div class="rl-gallery-featured-image-select"> <div class="rl-gallery-featured-image-select-id"' . ( $type === 'id' ? '' : ' style="display: none;"' ) . '>' . $content . '</div> <div class="rl-gallery-featured-image-select-url"' . ( $type === 'url' ? '' : ' style="display: none;"' ) . '> <p><input id="_rl_thumbnail_url" class="large-text" name="_rl_thumbnail_url" value="' . ( $type === 'url' ? esc_url( $value ) : '' ) . '" type="text" /></p> <p class="howto">' . esc_html__( 'Custom featured image URL', 'responsive-lightbox' ) . '</p> </div> <div class="rl-gallery-featured-image-select-image"' . ( $type === 'image' ? '' : ' style="display: none;"' ) . '><p class="howto">' . esc_html__( 'Dynamically generated first gallery image', 'responsive-lightbox' ) . '</p></div> </div> '; } return $content; } /** * Modify the resulting HTML so that the feature image is set as a background property. * * @param string $html The HTML image tag. * @param int $post_id The post whose featured image is to be printed. * @param int $post_thumbnail_id The post thumbnail ID. * @param array|string $size The size of the featured image. * @param array $attr Additional attributes. * @return string */ public function post_thumbnail_html( $html, $post_id = 0, $post_thumbnail_id = 0, $size = false, $attr = [] ) { if ( get_post_type( $post_id ) === 'rl_gallery' ) { // get featured image type $image_type = get_post_meta( $post_id, '_rl_featured_image_type', true ); // break if featured image type is media library if ( ! $image_type || $image_type == 'id' ) return $html; // get image source $image_src = $this->get_gallery_image_src( $this->get_featured_image_src( $post_id ) ); // no image? if ( empty( $image_src ) ) return $html; // add featured image as background in style tag $style = 'style="background:url( ' . esc_url( $image_src['url'] ) . ' ) no-repeat center center;-webkit-background-size:cover;-moz-background-size:cover;-o-background-size:cover;background-size: cover;"'; $html = str_replace( 'src=', $style . ' src=', $html ); // fix the alt tag (if possible) $alt = $image_src['alt']; if ( isset( $attr['alt'] ) ) $alt = $attr['alt']; if ( $alt ) { $html = str_replace( '/(alt=\'[^\']+\'\|alt="[^"]+")/', '', $html ); $html = str_replace( 'src=', ' alt="' . esc_attr( $alt ) . '" src=', $html ); } } return $html; } /** * Save the revision meta data. For example, used when saving a preview. * * @param int $revision_id * @return void */ public function save_revision( $revision_id ) { // get revision $revision = get_post( $revision_id ); // get gallery ID $post_id = $revision->post_parent; // is it rl gallery? if ( get_post_type( $post_id ) !== 'rl_gallery' ) return; $this->revision_id = $revision_id; if ( ! wp_is_post_revision( $revision_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) || empty( $_POST['rl_gallery'] ) ) return; // save revisioned meta data $this->save_gallery( wp_unslash( $_POST ), $revision_id, true ); } /** * Update preview link. * * @param string $link Preview link * @return string */ public function preview_post_link( $link ) { // add gallery revision id if ( property_exists( $this, 'revision_id' ) && ! is_null( $this->revision_id ) ) { $post_id = wp_get_post_parent_id( $this->revision_id ); // is it valid rl_gallery post? if ( $post_id && get_post_type( $post_id ) === 'rl_gallery' ) return add_query_arg( 'rl_gallery_revision_id', $this->revision_id, $link ); } return $link; } /** * Delete gallery revision at shutdown. * * @global object $post * * @return void */ public function shutdown_preview() { // is it a frontend preview? if ( is_preview() && isset( $_GET['rl_gallery_revision_id'] ) ) { global $post; // cast revision ID $revision_id = (int) $_GET['rl_gallery_revision_id']; // is it a valid revision? if ( get_post_type( $post->ID ) === 'rl_gallery' && wp_is_post_revision( $revision_id ) === (int) $post->ID ) wp_delete_post_revision( $revision_id ); } } /** * Filter gallery meta data needed for frontend gallery preview. * * @param mixed $value Meta value to filter * @param int $object_id * @param string $meta_key Meta key to filter a value for * @param bool $single Whether to return a single value * @return mixed */ public function filter_preview_metadata( $value, $object_id, $meta_key, $single ) { // ignore other post types if ( get_post_type( $object_id ) !== 'rl_gallery' ) return $value; // get current post $post = get_post(); // prepare keys $keys = array( '_rl_featured_image_type', '_rl_featured_image', '_rl_images_count', '_thumbnail_id' ); // add other metakeys foreach ( array_keys( $this->tabs ) as $key ) { $keys[] = '_rl_' . $key; } // restrict only to specified data if ( empty( $post ) || (int) $post->ID !== (int) $object_id || ! in_array( $meta_key, $keys, true ) || $post->post_type === 'revision' ) return $value; // grab the last autosave $preview = wp_get_post_autosave( $post->ID ); // invalid revision? if ( ! is_object( $preview ) ) return $value; // finally replace metadata return array( get_post_meta( $preview->ID, $meta_key, $single ) ); } }