| @@ -49,8 +49,9 @@ | ||
| 49 | 49 | |
| 50 | 50 | public function get_script_depends() |
| 51 | 51 | { |
| 52 | 52 | return [ |
| 53 | + 'jquery', | |
| 53 | 54 | KING_ADDONS_ASSETS_UNIQUE_KEY . '-grid-media', |
| 54 | 55 | KING_ADDONS_ASSETS_UNIQUE_KEY . '-isotope-kng', |
| 55 | 56 | KING_ADDONS_ASSETS_UNIQUE_KEY . '-slick-slick', |
| 56 | 57 | KING_ADDONS_ASSETS_UNIQUE_KEY . '-lightgallery-lightgallery' |
| @@ -799,10 +800,11 @@ | ||
| 799 | 800 | |
| 800 | 801 | $this->add_control( |
| 801 | 802 | 'query_manual_attachment', |
| 802 | 803 | [ |
| 803 | - 'label' => esc_html__('Add Images', 'king-addons'), | |
| 804 | + 'label' => esc_html__('Add Images (Legacy)', 'king-addons'), | |
| 804 | 805 | 'type' => Controls_Manager::GALLERY, |
| 806 | + 'description' => esc_html__('Used only when "Add Images & Videos" is empty. Prefer the repeater below for images and videos together.', 'king-addons'), | |
| 805 | 807 | 'separator' => 'before', |
| 806 | 808 | 'dynamic' => [ |
| 807 | 809 | 'active' => true, |
| 808 | 810 | ], |
| @@ -811,9 +813,79 @@ | ||
| 811 | 813 | ], |
| 812 | 814 | ] |
| 813 | 815 | ); |
| 814 | 816 | |
| 817 | + $media_repeater = new Repeater(); | |
| 818 | + | |
| 819 | + $media_repeater->add_control( | |
| 820 | + 'item_type', | |
| 821 | + [ | |
| 822 | + 'label' => esc_html__('Media Type', 'king-addons'), | |
| 823 | + 'type' => Controls_Manager::SELECT, | |
| 824 | + 'default' => 'image', | |
| 825 | + 'options' => [ | |
| 826 | + 'image' => esc_html__('Image', 'king-addons'), | |
| 827 | + 'video' => esc_html__('Video', 'king-addons'), | |
| 828 | + ], | |
| 829 | + ] | |
| 830 | + ); | |
| 831 | + | |
| 832 | + $media_repeater->add_control( | |
| 833 | + 'item_image', | |
| 834 | + [ | |
| 835 | + 'label' => esc_html__('Image', 'king-addons'), | |
| 836 | + 'type' => Controls_Manager::MEDIA, | |
| 837 | + 'dynamic' => [ | |
| 838 | + 'active' => true, | |
| 839 | + ], | |
| 840 | + 'description' => esc_html__('For videos, this image is used as the cover/poster in the gallery.', 'king-addons'), | |
| 841 | + ] | |
| 842 | + ); | |
| 843 | + | |
| 844 | + $media_repeater->add_control( | |
| 845 | + 'item_video', | |
| 846 | + [ | |
| 847 | + 'label' => esc_html__('Video File', 'king-addons'), | |
| 848 | + 'type' => Controls_Manager::MEDIA, | |
| 849 | + 'media_types' => [ | |
| 850 | + 'video', | |
| 851 | + ], | |
| 852 | + 'condition' => [ | |
| 853 | + 'item_type' => 'video', | |
| 854 | + ], | |
| 855 | + ] | |
| 856 | + ); | |
| 857 | + | |
| 815 | 858 | $this->add_control( |
| 859 | + 'query_manual_media', | |
| 860 | + [ | |
| 861 | + 'label' => esc_html__('Add Images & Videos', 'king-addons'), | |
| 862 | + 'type' => Controls_Manager::REPEATER, | |
| 863 | + 'fields' => $media_repeater->get_controls(), | |
| 864 | + 'default' => [], | |
| 865 | + 'title_field' => '{{{ item_type.charAt(0).toUpperCase() + item_type.slice(1) }}}', | |
| 866 | + 'separator' => 'before', | |
| 867 | + 'condition' => [ | |
| 868 | + 'query_selection' => 'manual', | |
| 869 | + ], | |
| 870 | + ] | |
| 871 | + ); | |
| 872 | + | |
| 873 | + $this->add_control( | |
| 874 | + 'query_include_videos', | |
| 875 | + [ | |
| 876 | + 'label' => esc_html__('Include Videos', 'king-addons'), | |
| 877 | + 'type' => Controls_Manager::SWITCHER, | |
| 878 | + 'default' => '', | |
| 879 | + 'description' => esc_html__('Include video files from the Media Library in the Auto selection.', 'king-addons'), | |
| 880 | + 'condition' => [ | |
| 881 | + 'query_selection' => 'dynamic', | |
| 882 | + ], | |
| 883 | + 'separator' => 'before', | |
| 884 | + ] | |
| 885 | + ); | |
| 886 | + | |
| 887 | + $this->add_control( | |
| 816 | 888 | 'query_posts_per_page', |
| 817 | 889 | [ |
| 818 | 890 | 'label' => esc_html__('Items Per Page', 'king-addons'), |
| 819 | 891 | 'type' => Controls_Manager::NUMBER, |
| @@ -879,8 +951,79 @@ | ||
| 879 | 951 | 'label_block' => true |
| 880 | 952 | ] |
| 881 | 953 | ); |
| 882 | 954 | |
| 955 | + $this->add_responsive_control( | |
| 956 | + 'layout_fitrows_media_height', | |
| 957 | + [ | |
| 958 | + 'label' => esc_html__('Media Height', 'king-addons'), | |
| 959 | + 'type' => Controls_Manager::SLIDER, | |
| 960 | + 'size_units' => ['px', 'vh'], | |
| 961 | + 'range' => [ | |
| 962 | + 'px' => [ | |
| 963 | + 'min' => 50, | |
| 964 | + 'max' => 800, | |
| 965 | + ], | |
| 966 | + 'vh' => [ | |
| 967 | + 'min' => 10, | |
| 968 | + 'max' => 100, | |
| 969 | + ], | |
| 970 | + ], | |
| 971 | + 'default' => [ | |
| 972 | + 'unit' => 'px', | |
| 973 | + 'size' => 280, | |
| 974 | + ], | |
| 975 | + 'selectors' => [ | |
| 976 | + '{{WRAPPER}} .king-addons-grid[data-settings*="fitRows"] .king-addons-grid-media-wrap' => 'height: {{SIZE}}{{UNIT}};', | |
| 977 | + ], | |
| 978 | + 'condition' => [ | |
| 979 | + 'layout_select' => 'fitRows', | |
| 980 | + ], | |
| 981 | + 'separator' => 'before', | |
| 982 | + ] | |
| 983 | + ); | |
| 984 | + | |
| 985 | + $this->add_responsive_control( | |
| 986 | + 'layout_fitrows_image_fit', | |
| 987 | + [ | |
| 988 | + 'label' => esc_html__('Image Fit', 'king-addons'), | |
| 989 | + 'type' => Controls_Manager::SELECT, | |
| 990 | + 'options' => [ | |
| 991 | + 'cover' => esc_html__('Cover', 'king-addons'), | |
| 992 | + 'contain' => esc_html__('Contain', 'king-addons'), | |
| 993 | + ], | |
| 994 | + 'default' => 'cover', | |
| 995 | + 'selectors' => [ | |
| 996 | + '{{WRAPPER}} .king-addons-grid[data-settings*="fitRows"] .king-addons-grid-image-wrap img' => 'object-fit: {{VALUE}};', | |
| 997 | + ], | |
| 998 | + 'condition' => [ | |
| 999 | + 'layout_select' => 'fitRows', | |
| 1000 | + ], | |
| 1001 | + ] | |
| 1002 | + ); | |
| 1003 | + | |
| 1004 | + $this->add_responsive_control( | |
| 1005 | + 'layout_fitrows_image_fit_position', | |
| 1006 | + [ | |
| 1007 | + 'label' => esc_html__('Image Fit Position', 'king-addons'), | |
| 1008 | + 'type' => Controls_Manager::SELECT, | |
| 1009 | + 'options' => [ | |
| 1010 | + 'center center' => esc_html__('Center', 'king-addons'), | |
| 1011 | + 'top center' => esc_html__('Top', 'king-addons'), | |
| 1012 | + 'bottom center' => esc_html__('Bottom', 'king-addons'), | |
| 1013 | + 'center left' => esc_html__('Left', 'king-addons'), | |
| 1014 | + 'center right' => esc_html__('Right', 'king-addons'), | |
| 1015 | + ], | |
| 1016 | + 'default' => 'center center', | |
| 1017 | + 'selectors' => [ | |
| 1018 | + '{{WRAPPER}} .king-addons-grid[data-settings*="fitRows"] .king-addons-grid-image-wrap img' => 'object-position: {{VALUE}};', | |
| 1019 | + ], | |
| 1020 | + 'condition' => [ | |
| 1021 | + 'layout_select' => 'fitRows', | |
| 1022 | + ], | |
| 1023 | + ] | |
| 1024 | + ); | |
| 1025 | + | |
| 883 | 1026 | $this->add_group_control( |
| 884 | 1027 | Group_Control_Image_Size::get_type(), |
| 885 | 1028 | [ |
| 886 | 1029 | 'name' => 'layout_image_crop', |
| @@ -1831,9 +1974,9 @@ | ||
| 1831 | 1974 | 'element_animation_size' => 'large', |
| 1832 | 1975 | 'element_sharing_trigger_icon' => 'fas fa-share', |
| 1833 | 1976 | ], |
| 1834 | 1977 | ], |
| 1835 | - 'title_field' => '{{{ element_select.charAt(0).toUpperCase() + element_select.slice(1) }}}', | |
| 1978 | + 'title_field' => '{{ element_select.charAt(0).toUpperCase() + element_select.slice(1) }}', | |
| 1836 | 1979 | ] |
| 1837 | 1980 | ); |
| 1838 | 1981 | |
| 1839 | 1982 | $this->end_controls_section(); |
| @@ -2190,8 +2333,23 @@ | ||
| 2190 | 2333 | 'return_value' => 'true', |
| 2191 | 2334 | ] |
| 2192 | 2335 | ); |
| 2193 | 2336 | |
| 2337 | + $this->add_control( | |
| 2338 | + 'video_play_icon', | |
| 2339 | + [ | |
| 2340 | + 'label' => esc_html__('Video Play Icon', 'king-addons'), | |
| 2341 | + 'type' => Controls_Manager::ICONS, | |
| 2342 | + 'skin' => 'inline', | |
| 2343 | + 'label_block' => false, | |
| 2344 | + 'default' => [ | |
| 2345 | + 'value' => 'fas fa-play', | |
| 2346 | + 'library' => 'fa-solid', | |
| 2347 | + ], | |
| 2348 | + 'separator' => 'before', | |
| 2349 | + ] | |
| 2350 | + ); | |
| 2351 | + | |
| 2194 | 2352 | $this->add_control_lightbox_popup_thumbnails(); |
| 2195 | 2353 | |
| 2196 | 2354 | $this->add_control_lightbox_popup_thumbnails_default(); |
| 2197 | 2355 | |
| @@ -6705,20 +6863,314 @@ | ||
| 6705 | 6863 | } |
| 6706 | 6864 | |
| 6707 | 6865 | public function get_max_num_pages() |
| 6708 | 6866 | { |
| 6867 | + $settings = $this->get_settings_for_display(); | |
| 6868 | + | |
| 6869 | + if ('manual' === ($settings['query_selection'] ?? '')) { | |
| 6870 | + return $this->get_manual_media_max_num_pages($settings); | |
| 6871 | + } | |
| 6872 | + | |
| 6709 | 6873 | $query = new WP_Query($this->get_main_query_args()); |
| 6710 | - $pages = (int)ceil($query->max_num_pages); | |
| 6874 | + $pages = (int) ceil($query->max_num_pages); | |
| 6711 | 6875 | wp_reset_postdata(); |
| 6876 | + | |
| 6712 | 6877 | return $pages; |
| 6713 | 6878 | } |
| 6714 | 6879 | |
| 6880 | + /** | |
| 6881 | + * Returns the total page count for manual media items. | |
| 6882 | + * | |
| 6883 | + * @param array|null $settings Widget settings. | |
| 6884 | + * @return int Total number of pages. | |
| 6885 | + */ | |
| 6886 | + public function get_manual_media_max_num_pages($settings = null) | |
| 6887 | + { | |
| 6888 | + $settings = $settings ?? $this->get_settings_for_display(); | |
| 6889 | + $items = $this->get_manual_media_items($settings); | |
| 6890 | + $total = count($items); | |
| 6891 | + $per_page = (int) ($settings['query_posts_per_page'] ?? 10); | |
| 6892 | + | |
| 6893 | + if ($per_page <= 0 || 0 === $total) { | |
| 6894 | + return 1; | |
| 6895 | + } | |
| 6896 | + | |
| 6897 | + $offset = empty($settings['query_offset']) ? 0 : (int) $settings['query_offset']; | |
| 6898 | + $remaining = max(0, $total - $offset); | |
| 6899 | + | |
| 6900 | + return max(1, (int) ceil($remaining / $per_page)); | |
| 6901 | + } | |
| 6902 | + | |
| 6903 | + /** | |
| 6904 | + * Returns manual media items for the current pagination page. | |
| 6905 | + * | |
| 6906 | + * @param array $settings Widget settings. | |
| 6907 | + * @return array<int, array<string, mixed>> Paginated manual media items. | |
| 6908 | + */ | |
| 6909 | + public function get_paginated_manual_media_items($settings) | |
| 6910 | + { | |
| 6911 | + $items = $this->get_manual_media_items($settings); | |
| 6912 | + $per_page = (int) ($settings['query_posts_per_page'] ?? 10); | |
| 6913 | + | |
| 6914 | + if ($per_page <= 0) { | |
| 6915 | + return $items; | |
| 6916 | + } | |
| 6917 | + | |
| 6918 | + $paged = get_query_var('paged') ? (int) get_query_var('paged') : ((int) get_query_var('page') ?: 1); | |
| 6919 | + $offset = empty($settings['query_offset']) ? 0 : (int) $settings['query_offset']; | |
| 6920 | + $slice_offset = $offset + ($paged - 1) * $per_page; | |
| 6921 | + | |
| 6922 | + return array_slice($items, $slice_offset, $per_page); | |
| 6923 | + } | |
| 6924 | + | |
| 6925 | + /** | |
| 6926 | + * Checks whether an attachment is a video file. | |
| 6927 | + * | |
| 6928 | + * @param int $attachment_id Attachment post ID. | |
| 6929 | + * @return bool True when the attachment mime type is video. | |
| 6930 | + */ | |
| 6931 | + public function is_video_attachment($attachment_id) | |
| 6932 | + { | |
| 6933 | + $mime_type = get_post_mime_type($attachment_id); | |
| 6934 | + | |
| 6935 | + return is_string($mime_type) && 0 === strpos($mime_type, 'video/'); | |
| 6936 | + } | |
| 6937 | + | |
| 6938 | + /** | |
| 6939 | + * Returns a video mime type based on the file extension. | |
| 6940 | + * | |
| 6941 | + * @param string $url Video file URL. | |
| 6942 | + * @return string Video mime type. | |
| 6943 | + */ | |
| 6944 | + public function get_video_mime_from_url($url) | |
| 6945 | + { | |
| 6946 | + $extension = strtolower((string) pathinfo((string) wp_parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION)); | |
| 6947 | + $map = [ | |
| 6948 | + 'mp4' => 'video/mp4', | |
| 6949 | + 'webm' => 'video/webm', | |
| 6950 | + 'ogg' => 'video/ogg', | |
| 6951 | + 'ogv' => 'video/ogg', | |
| 6952 | + ]; | |
| 6953 | + | |
| 6954 | + return $map[$extension] ?? 'video/mp4'; | |
| 6955 | + } | |
| 6956 | + | |
| 6957 | + /** | |
| 6958 | + * Returns a poster image URL for a video attachment when available. | |
| 6959 | + * | |
| 6960 | + * @param int $attachment_id Video attachment ID. | |
| 6961 | + * @return string Poster image URL or an empty string. | |
| 6962 | + */ | |
| 6963 | + public function get_attachment_video_poster_url($attachment_id) | |
| 6964 | + { | |
| 6965 | + $image_src = wp_get_attachment_image_src($attachment_id, 'large'); | |
| 6966 | + if (!empty($image_src[0])) { | |
| 6967 | + return $image_src[0]; | |
| 6968 | + } | |
| 6969 | + | |
| 6970 | + $metadata = wp_get_attachment_metadata($attachment_id); | |
| 6971 | + if (!empty($metadata['image']['file']) && !empty($metadata['file'])) { | |
| 6972 | + $upload_dir = wp_upload_dir(); | |
| 6973 | + | |
| 6974 | + return trailingslashit($upload_dir['baseurl']) . trailingslashit(dirname($metadata['file'])) . $metadata['image']['file']; | |
| 6975 | + } | |
| 6976 | + | |
| 6977 | + return ''; | |
| 6978 | + } | |
| 6979 | + | |
| 6980 | + /** | |
| 6981 | + * Builds manual media items from the repeater or legacy gallery control. | |
| 6982 | + * | |
| 6983 | + * @param array $settings Widget settings. | |
| 6984 | + * @return array<int, array<string, mixed>> Manual media items. | |
| 6985 | + */ | |
| 6986 | + public function get_manual_media_items($settings) | |
| 6987 | + { | |
| 6988 | + $items = []; | |
| 6989 | + | |
| 6990 | + if (!empty($settings['query_manual_media'])) { | |
| 6991 | + foreach ($settings['query_manual_media'] as $index => $row) { | |
| 6992 | + $item_type = $row['item_type'] ?? 'image'; | |
| 6993 | + $item_image = $row['item_image'] ?? []; | |
| 6994 | + $item_video = $row['item_video'] ?? []; | |
| 6995 | + | |
| 6996 | + if ('video' === $item_type) { | |
| 6997 | + if (empty($item_video['url'])) { | |
| 6998 | + continue; | |
| 6999 | + } | |
| 7000 | + if (empty($item_image['id']) && empty($item_image['url'])) { | |
| 7001 | + continue; | |
| 7002 | + } | |
| 7003 | + } elseif (empty($item_image['id']) && empty($item_image['url'])) { | |
| 7004 | + continue; | |
| 7005 | + } | |
| 7006 | + | |
| 7007 | + $items[] = [ | |
| 7008 | + 'key' => 'manual-' . $index, | |
| 7009 | + 'type' => $item_type, | |
| 7010 | + 'image' => $item_image, | |
| 7011 | + 'video' => $item_video, | |
| 7012 | + ]; | |
| 7013 | + } | |
| 7014 | + | |
| 7015 | + return $items; | |
| 7016 | + } | |
| 7017 | + | |
| 7018 | + if (empty($settings['query_manual_attachment'])) { | |
| 7019 | + return $items; | |
| 7020 | + } | |
| 7021 | + | |
| 7022 | + foreach ($settings['query_manual_attachment'] as $index => $attachment) { | |
| 7023 | + if (empty($attachment['id'])) { | |
| 7024 | + continue; | |
| 7025 | + } | |
| 7026 | + | |
| 7027 | + $items[] = [ | |
| 7028 | + 'key' => 'legacy-' . $index, | |
| 7029 | + 'type' => 'image', | |
| 7030 | + 'image' => $attachment, | |
| 7031 | + 'video' => [], | |
| 7032 | + ]; | |
| 7033 | + } | |
| 7034 | + | |
| 7035 | + return $items; | |
| 7036 | + } | |
| 7037 | + | |
| 7038 | + /** | |
| 7039 | + * Renders the play icon overlay for video gallery items. | |
| 7040 | + * | |
| 7041 | + * @param array $settings Widget settings. | |
| 7042 | + * @return void | |
| 7043 | + */ | |
| 7044 | + public function render_video_play_icon($settings) | |
| 7045 | + { | |
| 7046 | + echo '<span class="king-addons-grid-video-play-icon" aria-hidden="true">'; | |
| 7047 | + Icons_Manager::render_icon($settings['video_play_icon'], ['aria-hidden' => 'true']); | |
| 7048 | + echo '</span>'; | |
| 7049 | + } | |
| 7050 | + | |
| 7051 | + /** | |
| 7052 | + * Renders a hidden HTML5 video element referenced by the lightbox. | |
| 7053 | + * | |
| 7054 | + * @param string $video_url Video file URL. | |
| 7055 | + * @param string $element_id Hidden container element ID. | |
| 7056 | + * @return void | |
| 7057 | + */ | |
| 7058 | + public function render_video_html_element($video_url, $element_id) | |
| 7059 | + { | |
| 7060 | + if ('' === $video_url) { | |
| 7061 | + return; | |
| 7062 | + } | |
| 7063 | + | |
| 7064 | + echo '<div class="king-addons-grid-video-html" id="' . esc_attr($element_id) . '" style="display:none;">'; | |
| 7065 | + echo '<video class="lg-video-object lg-html5" controls preload="none" playsinline>'; | |
| 7066 | + echo '<source src="' . esc_url($video_url) . '" type="' . esc_attr($this->get_video_mime_from_url($video_url)) . '">'; | |
| 7067 | + echo '</video>'; | |
| 7068 | + echo '</div>'; | |
| 7069 | + } | |
| 7070 | + | |
| 7071 | + /** | |
| 7072 | + * Renders a gallery media thumbnail for image or video items. | |
| 7073 | + * | |
| 7074 | + * @param array $settings Widget settings. | |
| 7075 | + * @param string $item_key Unique item key for lightbox video references. | |
| 7076 | + * @param string $media_type Media type: image or video. | |
| 7077 | + * @param array $image_data Image or cover attachment data. | |
| 7078 | + * @param string $video_url Video file URL for video items. | |
| 7079 | + * @return void | |
| 7080 | + */ | |
| 7081 | + public function render_media_thumbnail($settings, $item_key, $media_type, $image_data, $video_url = '') | |
| 7082 | + { | |
| 7083 | + $image_id = !empty($image_data['id']) ? (int) $image_data['id'] : 0; | |
| 7084 | + $is_video = ('video' === $media_type && '' !== $video_url); | |
| 7085 | + $video_html_id = 'king-addons-grid-video-' . $this->get_id() . '-' . $item_key; | |
| 7086 | + | |
| 7087 | + if ($image_id) { | |
| 7088 | + $src = Group_Control_Image_Size::get_attachment_image_src($image_id, 'layout_image_crop', $settings); | |
| 7089 | + $alt = ('' === wp_get_attachment_caption($image_id)) ? get_the_title($image_id) : wp_get_attachment_caption($image_id); | |
| 7090 | + $lightbox_src = $is_video ? $src : wp_get_attachment_url($image_id); | |
| 7091 | + } else { | |
| 7092 | + $src = $image_data['url'] ?? ''; | |
| 7093 | + $alt = ''; | |
| 7094 | + $lightbox_src = $src; | |
| 7095 | + } | |
| 7096 | + | |
| 7097 | + if ($is_video && '' === $src && $image_id) { | |
| 7098 | + $src = $this->get_attachment_video_poster_url($image_id); | |
| 7099 | + } | |
| 7100 | + | |
| 7101 | + if ($is_video) { | |
| 7102 | + $lightbox_src = '' !== $src ? $src : $video_url; | |
| 7103 | + } | |
| 7104 | + | |
| 7105 | + $wrap_classes = 'king-addons-grid-image-wrap'; | |
| 7106 | + if ($is_video) { | |
| 7107 | + $wrap_classes .= ' king-addons-grid-video-lightbox-item'; | |
| 7108 | + } | |
| 7109 | + | |
| 7110 | + echo '<div class="' . esc_attr($wrap_classes) . '" data-src="' . esc_url($lightbox_src) . '"'; | |
| 7111 | + if ($is_video) { | |
| 7112 | + echo ' data-poster="' . esc_url($lightbox_src) . '"'; | |
| 7113 | + echo ' data-html="#' . esc_attr($video_html_id) . '"'; | |
| 7114 | + echo ' data-kng-video-url="' . esc_url($video_url) . '"'; | |
| 7115 | + } | |
| 7116 | + echo '>'; | |
| 7117 | + | |
| 7118 | + if ('' !== $src) { | |
| 7119 | + echo '<img src="' . esc_url($src) . '" alt="' . esc_attr($alt) . '" class="king-addons-animation-timing-' . esc_attr($settings['image_effects_animation_timing']) . '">'; | |
| 7120 | + } elseif ($is_video) { | |
| 7121 | + echo '<span class="king-addons-grid-video-cover-placeholder" aria-hidden="true"></span>'; | |
| 7122 | + } | |
| 7123 | + | |
| 7124 | + if ($is_video) { | |
| 7125 | + $this->render_video_play_icon($settings); | |
| 7126 | + } | |
| 7127 | + | |
| 7128 | + echo '</div>'; | |
| 7129 | + | |
| 7130 | + if ($is_video) { | |
| 7131 | + $this->render_video_html_element($video_url, $video_html_id); | |
| 7132 | + } | |
| 7133 | + } | |
| 7134 | + | |
| 7135 | + /** | |
| 7136 | + * Renders one gallery article for manual media items. | |
| 7137 | + * | |
| 7138 | + * @param array $settings Widget settings. | |
| 7139 | + * @param array $item Manual media item data. | |
| 7140 | + * @return void | |
| 7141 | + */ | |
| 7142 | + public function render_manual_grid_item($settings, $item) | |
| 7143 | + { | |
| 7144 | + $item_type = $item['type'] ?? 'image'; | |
| 7145 | + $video_url = ('video' === $item_type && !empty($item['video']['url'])) ? $item['video']['url'] : ''; | |
| 7146 | + $post_id = !empty($item['image']['id']) ? (int) $item['image']['id'] : 0; | |
| 7147 | + $item_classes = ['king-addons-grid-item', 'elementor-clearfix']; | |
| 7148 | + | |
| 7149 | + if ('video' === $item_type) { | |
| 7150 | + $item_classes[] = 'king-addons-grid-item-video'; | |
| 7151 | + } | |
| 7152 | + | |
| 7153 | + echo '<article class="' . esc_attr(implode(' ', $item_classes)) . '">'; | |
| 7154 | + echo '<div class="king-addons-grid-item-inner">'; | |
| 7155 | + $this->get_elements_by_location('above', $settings, $post_id); | |
| 7156 | + echo '<div class="king-addons-grid-media-wrap' . esc_attr($this->get_image_effect_class($settings)) . '">'; | |
| 7157 | + $this->render_media_thumbnail($settings, $item['key'], $item_type, $item['image'] ?? [], $video_url); | |
| 7158 | + echo '<div class="king-addons-grid-media-hover king-addons-animation-wrap">'; | |
| 7159 | + $this->render_media_overlay($settings, $post_id); | |
| 7160 | + $this->get_elements_by_location('over', $settings, $post_id); | |
| 7161 | + echo '</div></div>'; | |
| 7162 | + $this->get_elements_by_location('below', $settings, $post_id); | |
| 7163 | + echo '</div></article>'; | |
| 7164 | + } | |
| 7165 | + | |
| 6715 | 7166 | public function get_main_query_args() |
| 6716 | 7167 | { |
| 6717 | 7168 | $s = $this->get_settings_for_display(); |
| 6718 | 7169 | $author = !empty($s['query_author']) ? implode(',', $s['query_author']) : ''; |
| 6719 | 7170 | $paged = get_query_var('paged') ? get_query_var('paged') : (get_query_var('page') ? get_query_var('page') : 1); |
| 6720 | - $offset = ($paged - 1) * $s['query_posts_per_page'] + (empty($s['query_offset']) ? 0 : $s['query_offset']); | |
| 7171 | + $offset = ($paged - 1) * Core::jsNumber($s, 'query_posts_per_page', 10) | |
| 7172 | + + (empty($s['query_offset']) ? 0 : Core::jsNumber($s, 'query_offset', 0)); | |
| 6721 | 7173 | |
| 6722 | 7174 | // Remove premium-only randomize if not available |
| 6723 | 7175 | if (!king_addons_freemius()->can_use_premium_code__premium_only()) { |
| 6724 | 7176 | $s['query_randomize'] = ''; |
| @@ -6724,13 +7176,18 @@ | ||
| 6724 | 7176 | $s['query_randomize'] = ''; |
| 6725 | 7177 | $s['order_posts'] = 'date'; |
| 6726 | 7178 | } |
| 6727 | 7179 | $order_by = $s['query_randomize'] !== '' ? $s['query_randomize'] : $s['order_posts']; |
| 6728 | - if ('manual' === $s['query_selection']) $order_by = 'post__in'; | |
| 7180 | + if ('manual' === $s['query_selection']) { | |
| 7181 | + $order_by = 'post__in'; | |
| 7182 | + } | |
| 6729 | 7183 | |
| 7184 | + $include_videos = !empty($s['query_include_videos']); | |
| 7185 | + $post_mime_type = $include_videos ? ['image', 'video'] : 'image'; | |
| 7186 | + | |
| 6730 | 7187 | $args = [ |
| 6731 | 7188 | 'post_type' => 'attachment', |
| 6732 | - 'post_mime_type' => 'image', // <-- Only images | |
| 7189 | + 'post_mime_type' => $post_mime_type, | |
| 6733 | 7190 | 'post_status' => 'inherit', |
| 6734 | 7191 | 'tax_query' => $this->get_tax_query_args(), |
| 6735 | 7192 | 'post__not_in' => $s['query_exclude_attachment'], |
| 6736 | 7193 | 'posts_per_page' => $s['query_posts_per_page'], |
| @@ -6741,17 +7198,29 @@ | ||
| 6741 | 7198 | ]; |
| 6742 | 7199 | |
| 6743 | 7200 | if ('manual' === $s['query_selection']) { |
| 6744 | 7201 | $post_ids = []; |
| 6745 | - if (!empty($s['query_manual_attachment'])) { | |
| 7202 | + | |
| 7203 | + if (!empty($s['query_manual_media'])) { | |
| 7204 | + foreach ($this->get_manual_media_items($s) as $item) { | |
| 7205 | + if (!empty($item['image']['id'])) { | |
| 7206 | + $post_ids[] = (int) $item['image']['id']; | |
| 7207 | + } | |
| 7208 | + } | |
| 7209 | + } elseif (!empty($s['query_manual_attachment'])) { | |
| 6746 | 7210 | foreach ($s['query_manual_attachment'] as $attachment) { |
| 6747 | 7211 | $post_ids[] = $attachment['id']; |
| 6748 | 7212 | } |
| 6749 | 7213 | } |
| 7214 | + | |
| 7215 | + if (empty($post_ids)) { | |
| 7216 | + $post_ids = [0]; | |
| 7217 | + } | |
| 7218 | + | |
| 6750 | 7219 | $orderby = ('' === $s['query_randomize']) ? 'post__in' : 'rand'; |
| 6751 | 7220 | $args = [ |
| 6752 | 7221 | 'post_type' => 'attachment', |
| 6753 | - 'post_mime_type' => 'image', // <-- Only images | |
| 7222 | + 'post_mime_type' => $post_mime_type, | |
| 6754 | 7223 | 'post_status' => 'inherit', |
| 6755 | 7224 | 'post__in' => $post_ids, |
| 6756 | 7225 | 'orderby' => $orderby, |
| 6757 | 7226 | 'posts_per_page' => $s['query_posts_per_page'], |
| @@ -6813,18 +7282,28 @@ | ||
| 6813 | 7282 | |
| 6814 | 7283 | public function render_post_thumbnail($settings) |
| 6815 | 7284 | { |
| 6816 | 7285 | $id = get_the_ID(); |
| 6817 | - $src = Group_Control_Image_Size::get_attachment_image_src($id, 'layout_image_crop', $settings); | |
| 6818 | - $alt = ('' === wp_get_attachment_caption($id)) ? get_the_title() : wp_get_attachment_caption($id); | |
| 6819 | - echo '<div class="king-addons-grid-image-wrap" data-src="' . esc_url(wp_get_attachment_url($id)) . '">'; | |
| 6820 | - echo '<img src="' . esc_url($src) . '" alt="' . wp_kses_post($alt) . '" class="king-addons-animation-timing-' . esc_html($settings['image_effects_animation_timing']) . '">'; | |
| 6821 | - echo '</div>'; | |
| 7286 | + $is_video = $this->is_video_attachment($id); | |
| 7287 | + $video_url = $is_video ? (string) wp_get_attachment_url($id) : ''; | |
| 7288 | + | |
| 7289 | + $this->render_media_thumbnail( | |
| 7290 | + $settings, | |
| 7291 | + 'attachment-' . $id, | |
| 7292 | + $is_video ? 'video' : 'image', | |
| 7293 | + ['id' => $id], | |
| 7294 | + $video_url | |
| 7295 | + ); | |
| 6822 | 7296 | } |
| 6823 | 7297 | |
| 6824 | - public function render_media_overlay($s) | |
| 7298 | + public function render_media_overlay($s, $post_id = 0) | |
| 6825 | 7299 | { |
| 6826 | - echo '<div class="king-addons-grid-media-hover-bg ' . $this->get_animation_class($s, 'overlay') . '" data-url="' . esc_url(get_the_permalink(get_the_ID())) . '">'; | |
| 7300 | + if (!$post_id) { | |
| 7301 | + $post_id = get_the_ID(); | |
| 7302 | + } | |
| 7303 | + | |
| 7304 | + $overlay_url = $post_id ? get_the_permalink($post_id) : '#'; | |
| 7305 | + echo '<div class="king-addons-grid-media-hover-bg ' . $this->get_animation_class($s, 'overlay') . '" data-url="' . esc_url($overlay_url) . '">'; | |
| 6827 | 7306 | if (king_addons_freemius()->can_use_premium_code__premium_only()) { |
| 6828 | 7307 | if ('' !== $s['overlay_image']['url']) { |
| 6829 | 7308 | echo '<img src="' . esc_url($s['overlay_image']['url']) . '">'; |
| 6830 | 7309 | } |
| @@ -6959,9 +7438,12 @@ | ||
| 6959 | 7438 | public function render_post_lightbox($s, $class, $post_id) |
| 6960 | 7439 | { |
| 6961 | 7440 | echo '<div class="' . esc_attr($class) . '"><div class="inner-block">'; |
| 6962 | 7441 | $lightbox_source = get_the_post_thumbnail_url($post_id); |
| 6963 | - if ('audio' === get_post_format()) { | |
| 7442 | + | |
| 7443 | + if ($this->is_video_attachment($post_id)) { | |
| 7444 | + $lightbox_source = $this->get_attachment_video_poster_url($post_id); | |
| 7445 | + } elseif ('audio' === get_post_format()) { | |
| 6964 | 7446 | if ('meta' === $s['element_lightbox_pfa_select']) { |
| 6965 | 7447 | $meta_value = get_post_meta($post_id, $s['element_lightbox_pfa_meta'], true); |
| 6966 | 7448 | if (false === strpos($meta_value, '<iframe ')) { |
| 6967 | 7449 | add_filter('oembed_result', $media_grid_filter = function ($html) { |
| @@ -6990,9 +7472,11 @@ | ||
| 6990 | 7472 | } |
| 6991 | 7473 | if (isset($video_url)) $lightbox_source = $video_url; |
| 6992 | 7474 | } |
| 6993 | 7475 | } |
| 6994 | - if (!$lightbox_source) $lightbox_source = wp_get_attachment_url($post_id); | |
| 7476 | + if (!$lightbox_source && !$this->is_video_attachment($post_id)) { | |
| 7477 | + $lightbox_source = wp_get_attachment_url($post_id); | |
| 7478 | + } | |
| 6995 | 7479 | echo '<span data-src="' . esc_url($lightbox_source) . '">'; |
| 6996 | 7480 | if ('before' === $s['element_extra_text_pos']) { |
| 6997 | 7481 | echo '<span class="king-addons-grid-extra-text-left">' . esc_html($s['element_extra_text']) . '</span>'; |
| 6998 | 7482 | } |
| @@ -7406,13 +7890,13 @@ | ||
| 7406 | 7890 | 'selector' => '.king-addons-grid-image-wrap', |
| 7407 | 7891 | 'iframeMaxWidth' => '60%', |
| 7408 | 7892 | 'hash' => false, |
| 7409 | 7893 | 'autoplay' => $s['lightbox_popup_autoplay'], |
| 7410 | - 'pause' => $s['lightbox_popup_pause'] * 1000, | |
| 7894 | + 'pause' => Core::jsNumber($s, 'lightbox_popup_pause', 5) * 1000, | |
| 7411 | 7895 | 'progressBar' => $s['lightbox_popup_progressbar'], |
| 7412 | 7896 | 'counter' => $s['lightbox_popup_counter'], |
| 7413 | 7897 | 'controls' => $s['lightbox_popup_arrows'], |
| 7414 | - 'getCaptionFromTitleOrAlt' => $s['lightbox_popup_captions'], | |
| 7898 | + 'getCaptionFromTitleOrAlt' => false, | |
| 7415 | 7899 | 'thumbnail' => $s['lightbox_popup_thumbnails'], |
| 7416 | 7900 | 'showThumbByDefault' => $s['lightbox_popup_thumbnails_default'], |
| 7417 | 7901 | 'share' => $s['lightbox_popup_sharing'], |
| 7418 | 7902 | 'zoom' => $s['lightbox_popup_zoom'], |
| @@ -7456,9 +7940,9 @@ | ||
| 7456 | 7940 | 'pause' => $s['lightbox_popup_pause'] * 1000, |
| 7457 | 7941 | 'progressBar' => $s['lightbox_popup_progressbar'], |
| 7458 | 7942 | 'counter' => $s['lightbox_popup_counter'], |
| 7459 | 7943 | 'controls' => $s['lightbox_popup_arrows'], |
| 7460 | - 'getCaptionFromTitleOrAlt' => $s['lightbox_popup_captions'], | |
| 7944 | + 'getCaptionFromTitleOrAlt' => false, | |
| 7461 | 7945 | 'thumbnail' => $s['lightbox_popup_thumbnails'], |
| 7462 | 7946 | 'showThumbByDefault' => $s['lightbox_popup_thumbnails_default'], |
| 7463 | 7947 | 'share' => $s['lightbox_popup_sharing'], |
| 7464 | 7948 | 'zoom' => $s['lightbox_popup_zoom'], |
| @@ -7477,8 +7961,43 @@ | ||
| 7477 | 7961 | |
| 7478 | 7962 | protected function render() |
| 7479 | 7963 | { |
| 7480 | 7964 | $s = $this->get_settings(); |
| 7965 | + | |
| 7966 | + if ('manual' === $s['query_selection']) { | |
| 7967 | + $manual_items = $this->get_paginated_manual_media_items($s); | |
| 7968 | + | |
| 7969 | + if (empty($manual_items)) { | |
| 7970 | + echo '<h2>' . esc_html($s['query_not_found_text']) . '</h2>'; | |
| 7971 | + return; | |
| 7972 | + } | |
| 7973 | + | |
| 7974 | + if ('slider' !== $s['layout_select']) { | |
| 7975 | + $this->render_grid_filters($s); | |
| 7976 | + $this->add_grid_settings($s); | |
| 7977 | + $render_attribute = $this->get_render_attribute_string('grid-settings'); | |
| 7978 | + } else { | |
| 7979 | + $this->add_slider_settings($s); | |
| 7980 | + $render_attribute = $this->get_render_attribute_string('slider-settings'); | |
| 7981 | + } | |
| 7982 | + | |
| 7983 | + echo '<section class="king-addons-grid king-addons-media-grid elementor-clearfix" ' . $render_attribute . '>'; | |
| 7984 | + foreach ($manual_items as $item) { | |
| 7985 | + $this->render_manual_grid_item($s, $item); | |
| 7986 | + } | |
| 7987 | + echo '</section>'; | |
| 7988 | + | |
| 7989 | + if ('slider' === $s['layout_select']) { | |
| 7990 | + echo '<div class="king-addons-grid-slider-arrow-container">'; | |
| 7991 | + echo '<div class="king-addons-grid-slider-prev-arrow king-addons-grid-slider-arrow" id="king-addons-grid-slider-prev-' . esc_attr($this->get_id()) . '">' . Core::getIcon($s['layout_slider_nav_icon'], '') . '</div>'; | |
| 7992 | + echo '<div class="king-addons-grid-slider-next-arrow king-addons-grid-slider-arrow" id="king-addons-grid-slider-next-' . esc_attr($this->get_id()) . '">' . Core::getIcon($s['layout_slider_nav_icon'], '') . '</div>'; | |
| 7993 | + echo '</div><div class="king-addons-grid-slider-dots"></div>'; | |
| 7994 | + } | |
| 7995 | + | |
| 7996 | + $this->render_grid_pagination($s); | |
| 7997 | + return; | |
| 7998 | + } | |
| 7999 | + | |
| 7481 | 8000 | $posts = new WP_Query($this->get_main_query_args()); |
| 7482 | 8001 | if ($posts->have_posts()) { |
| 7483 | 8002 | if ('slider' !== $s['layout_select']) { |
| 7484 | 8003 | $this->render_grid_filters($s); |
| @@ -7490,12 +8009,19 @@ | ||
| 7490 | 8009 | } |
| 7491 | 8010 | echo '<section class="king-addons-grid king-addons-media-grid elementor-clearfix" ' . $render_attribute . '>'; |
| 7492 | 8011 | while ($posts->have_posts()) { |
| 7493 | 8012 | $posts->the_post(); |
| 7494 | - // Skip non-image attachments (in case) | |
| 7495 | - if (!wp_attachment_is_image(get_the_ID())) continue; | |
| 8013 | + $attachment_id = get_the_ID(); | |
| 7496 | 8014 | |
| 7497 | - $post_class = implode(' ', get_post_class('king-addons-grid-item elementor-clearfix', get_the_ID())); | |
| 8015 | + if (!wp_attachment_is_image($attachment_id) && !$this->is_video_attachment($attachment_id)) { | |
| 8016 | + continue; | |
| 8017 | + } | |
| 8018 | + | |
| 8019 | + $post_class = implode(' ', get_post_class('king-addons-grid-item elementor-clearfix', $attachment_id)); | |
| 8020 | + if ($this->is_video_attachment($attachment_id)) { | |
| 8021 | + $post_class .= ' king-addons-grid-item-video'; | |
| 8022 | + } | |
| 8023 | + | |
| 7498 | 8024 | echo '<article class="' . esc_attr($post_class) . '">'; |
| 7499 | 8025 | echo '<div class="king-addons-grid-item-inner">'; |
| 7500 | 8026 | $this->get_elements_by_location('above', $s, get_the_ID()); |
| 7501 | 8027 | echo '<div class="king-addons-grid-media-wrap' . $this->get_image_effect_class($s) . ' ">'; |