<?php
// Register the shortcode
add_shortcode('tea_image_collection', 'tea_images_collections_shortcode');
function tea_images_collections_shortcode($atts) {
// Extract and set default attributes
$atts = shortcode_atts(array(
'per_page' => 12,
'title' => 'Company Images',
'desc' => 'Explore the moments that define our brand. Click any image to view it in full detail.',
'class' => 'certificate',
), $atts, 'tea_image_collection');
// Start output buffering
ob_start();
// Query all image collection posts
$images_query = new WP_Query(array(
'post_type' => 'image_collection',
'posts_per_page' => -1,
'orderby' => 'date',
'order' => 'ASC'
));
$collections_data = array();
?>
<section class="main-content image-collection-wrapper section" data-per-page="<?php echo esc_attr($atts['per_page']); ?>">
<div class="header-section">
<h1><?php echo esc_html($atts['title']); ?></h1>
<p><?php echo esc_html($atts['desc']); ?></p>
</div>
<div class="tabs-container">
<button class="tab-btn active" data-collection="all">View All</button>
<?php
while ($images_query->have_posts()) {
$images_query->the_post();
$post_id = get_the_ID();
$post_slug = get_post_field('post_name', $post_id);
$post_title = get_the_title();
// Get all images for this collection
$collection_images = get_image_collection($post_id);
if (!empty($collection_images)) {
$collections_data[$post_slug] = array(
'title' => $post_title,
'images' => $collection_images
);
?>
<button class="tab-btn" data-collection="<?php echo esc_attr($post_slug); ?>">
<?php echo esc_html($post_title); ?>
</button>
<?php }
}
wp_reset_postdata();
?>
</div>
<div class="gallery-grid" id="gallery-grid">
<!-- Images will be loaded here via JavaScript -->
</div>
<div class="pagination-container" id="pagination-container">
<!-- Pagination will be loaded here via JavaScript -->
</div>
</section>
<div class="lightbox" id="lightbox">
<span class="lightbox-close" id="lightbox-close">×</span>
<div class="lightbox-counter" id="lightbox-counter"></div>
<img src="" alt="" class="lightbox-content" id="lightbox-img">
<div class="lightbox-nav">
<button class="lightbox-prev" id="lightbox-prev">‹</button>
<button class="lightbox-next" id="lightbox-next">›</button>
</div>
<div class="lightbox-info" id="lightbox-info">
<h3 id="lightbox-title"></h3>
<p id="lightbox-caption"></p>
</div>
</div>
<script>
var imageCollectionsData = <?php echo json_encode($collections_data); ?>;
jQuery(document).ready(function($) {
var currentCollection = 'all';
var currentPage = 1;
var perPage = parseInt($('.image-collection-wrapper').data('per-page'));
var allImages = [];
var currentImages = [];
var lightboxIndex = 0;
// Combine all images for "View All"
$.each(imageCollectionsData, function(slug, data) {
$.each(data.images, function(index, image) {
var imageWithCollection = $.extend({}, image, {
collection_slug: slug,
collection_title: data.title
});
allImages.push(imageWithCollection);
});
});
// Initialize
renderGallery('all', 1);
// Tab click handler
$('.tab-btn').on('click', function() {
$('.tab-btn').removeClass('active');
$(this).addClass('active');
currentCollection = $(this).data('collection');
currentPage = 1;
renderGallery(currentCollection, currentPage);
});
// Pagination click handler (delegated)
$('#pagination-container').on('click', '.page-link', function(e) {
e.preventDefault();
var page = parseInt($(this).data('page'));
if (page && !$(this).parent().hasClass('disabled') && !$(this).parent().hasClass('active')) {
currentPage = page;
renderGallery(currentCollection, currentPage);
// Smooth scroll to top of gallery
$('html, body').animate({
scrollTop: $('.gallery-grid').offset().top - 100
}, 300);
}
});
// Render gallery function
function renderGallery(collection, page) {
var imagesToShow = [];
// Get images based on collection
if (collection === 'all') {
imagesToShow = allImages;
} else if (imageCollectionsData[collection]) {
imagesToShow = imageCollectionsData[collection].images.map(function(img) {
return $.extend({}, img, {
collection_slug: collection,
collection_title: imageCollectionsData[collection].title
});
});
}
currentImages = imagesToShow;
// Calculate pagination
var totalImages = imagesToShow.length;
var totalPages = Math.ceil(totalImages / perPage);
var startIndex = (page - 1) * perPage;
var endIndex = Math.min(startIndex + perPage, totalImages);
var pageImages = imagesToShow.slice(startIndex, endIndex);
// Render images
var galleryHtml = '';
if (pageImages.length > 0) {
$.each(pageImages, function(index, image) {
var globalIndex = startIndex + index;
galleryHtml += '<div class="gallery-item" data-index="' + globalIndex + '" data-category="' + escapeHtml(image.collection_slug) + '">';
galleryHtml += '<img src="' + escapeHtml(image.url) + '" alt="' + escapeHtml(image.alt || '') + '">';
galleryHtml += '<div class="item-info">';
galleryHtml += '<span>' + escapeHtml(image.caption || '') + '</span>';
galleryHtml += '<h3>' + escapeHtml(image.alt || 'Image') + '</h3>';
galleryHtml += '</div>';
galleryHtml += '</div>';
});
} else {
galleryHtml = '<p class="no-images">No images found in this collection.</p>';
}
$('#gallery-grid').html(galleryHtml);
// Render pagination
renderPagination(totalPages, page);
// Update info text
if (totalImages > 0) {
var infoText = 'Showing ' + (startIndex + 1) + '-' + endIndex + ' of ' + totalImages + ' images';
if ($('.gallery-info').length) {
$('.gallery-info').text(infoText);
} else {
$('#pagination-container').prepend('<p class="gallery-info">' + infoText + '</p>');
}
}
}
// Render pagination
function renderPagination(totalPages, currentPage) {
if (totalPages <= 1) {
$('#pagination-container').html('');
return;
}
var paginationHtml = '<ul class="pagination">';
// Previous button
if (currentPage > 1) {
paginationHtml += '<li class="page-item"><a href="#" class="page-link" data-page="' + (currentPage - 1) + '">«</a></li>';
} else {
paginationHtml += '<li class="page-item disabled"><span class="page-link">«</span></li>';
}
// Page numbers with smart display
var range = 2;
for (var i = 1; i <= totalPages; i++) {
if (i === 1 || i === totalPages || (i >= currentPage - range && i <= currentPage + range)) {
if (i === currentPage) {
paginationHtml += '<li class="page-item active"><span class="page-link">' + i + '</span></li>';
} else {
paginationHtml += '<li class="page-item"><a href="#" class="page-link" data-page="' + i + '">' + i + '</a></li>';
}
} else if (i === currentPage - range - 1 || i === currentPage + range + 1) {
paginationHtml += '<li class="page-item disabled"><span class="page-link">...</span></li>';
}
}
// Next button
if (currentPage < totalPages) {
paginationHtml += '<li class="page-item"><a href="#" class="page-link" data-page="' + (currentPage + 1) + '">»</a></li>';
} else {
paginationHtml += '<li class="page-item disabled"><span class="page-link">»</span></li>';
}
paginationHtml += '</ul>';
// Update or create pagination
if ($('.pagination').length) {
$('.pagination').parent().html(paginationHtml);
} else {
$('#pagination-container').append(paginationHtml);
}
}
// Lightbox functionality
$('#gallery-grid').on('click', '.gallery-item', function() {
lightboxIndex = parseInt($(this).data('index'));
showLightbox(lightboxIndex);
});
function showLightbox(index) {
if (index >= 0 && index < currentImages.length) {
var image = currentImages[index];
var $lightbox = $('#lightbox');
var $img = $('#lightbox-img');
// Update image
$img.attr('src', image.url).attr('alt', image.alt || '');
// Update info
$('#lightbox-title').text(image.alt || 'Image');
$('#lightbox-caption').text(image.caption || '');
// Update counter
$('#lightbox-counter').text((index + 1) + ' / ' + currentImages.length);
// Show lightbox
$lightbox.fadeIn(300).addClass('active');
// Prevent body scroll
$('body').css('overflow', 'hidden');
lightboxIndex = index;
// Update navigation buttons
$('#lightbox-prev').prop('disabled', index === 0);
$('#lightbox-next').prop('disabled', index === currentImages.length - 1);
}
}
function closeLightbox() {
$('#lightbox').fadeOut(300, function() {
$(this).removeClass('active');
});
$('body').css('overflow', '');
}
$('#lightbox-prev').on('click', function(e) {
e.stopPropagation();
if (lightboxIndex > 0) {
showLightbox(lightboxIndex - 1);
}
});
$('#lightbox-next').on('click', function(e) {
e.stopPropagation();
if (lightboxIndex < currentImages.length - 1) {
showLightbox(lightboxIndex + 1);
}
});
$('#lightbox-close').on('click', function(e) {
e.stopPropagation();
closeLightbox();
});
$('#lightbox').on('click', function(e) {
if (e.target === this) {
closeLightbox();
}
});
// Keyboard navigation
$(document).on('keyup', function(e) {
if ($('#lightbox').is(':visible')) {
if (e.key === 'Escape') {
closeLightbox();
} else if (e.key === 'ArrowLeft' && lightboxIndex > 0) {
showLightbox(lightboxIndex - 1);
} else if (e.key === 'ArrowRight' && lightboxIndex < currentImages.length - 1) {
showLightbox(lightboxIndex + 1);
}
}
});
// Helper function to escape HTML
function escapeHtml(text) {
if (!text) return '';
var map = {
'&': '&',
'<': '<',
'>': '>',
'"': '"',
"'": '''
};
return String(text).replace(/[&<>"']/g, function(m) { return map[m]; });
}
});
</script>
<style>
.image-collection-wrapper {
max-width: 1200px;
margin: 8rem auto;
padding: 20px;
}
.header-section {
text-align: center;
margin-bottom: 40px;
}
.header-section h1 {
font-size: 36px;
margin-bottom: 10px;
color: #333;
}
.header-section p {
font-size: 16px;
color: #666;
}
.tabs-container {
display: flex;
gap: 10px;
flex-wrap: wrap;
margin-bottom: 30px;
justify-content: center;
}
.tab-btn {
padding: 10px 20px;
border: 2px solid #ddd;
background: white;
cursor: pointer;
text-decoration: none;
color: #333;
transition: all 0.3s;
border-radius: 5px;
font-size: 14px;
font-weight: 500;
}
.tab-btn:hover {
border-color: #666;
background: #f5f5f5;
}
.tab-btn.active {
background: #333;
color: white;
border-color: #333;
}
.gallery-info {
text-align: center;
color: #666;
margin-bottom: 15px;
font-size: 14px;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
margin-bottom: 30px;
min-height: 200px;
}
.gallery-item {
position: relative;
overflow: hidden;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
cursor: pointer;
transition: transform 0.3s, box-shadow 0.3s;
background: white;
}
.gallery-item:hover {
transform: translateY(-5px);
box-shadow: 0 4px 12px rgba(0,0,0,0.2);
}
.gallery-item:hover::before {
content: '🔍';
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
z-index: 10;
opacity: 0.9;
text-shadow: 0 0 10px rgba(0,0,0,0.5);
}
.gallery-item img {
width: 100%;
height: 250px;
object-fit: cover;
display: block;
transition: transform 0.3s, filter 0.3s;
}
.gallery-item:hover img {
transform: scale(1.05);
filter: brightness(0.8);
}
.item-info {
padding: 15px;
background: white;
}
.item-info span {
color: #999;
font-size: 12px;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.item-info h3 {
margin: 5px 0 0 0;
font-size: 16px;
color: #333;
font-weight: 600;
}
.pagination-container {
margin-top: 30px;
}
.pagination {
display: flex;
list-style: none;
gap: 5px;
padding: 0;
justify-content: center;
margin: 0;
}
.page-item {
list-style: none;
}
.page-link {
padding: 8px 12px;
border: 1px solid #ddd;
text-decoration: none;
color: #333;
border-radius: 4px;
display: block;
transition: all 0.3s;
min-width: 40px;
text-align: center;
}
.page-link:hover {
background: #f5f5f5;
border-color: #666;
}
.page-item.active .page-link {
background: #333;
color: white;
border-color: #333;
cursor: default;
}
.page-item.disabled .page-link {
color: #999;
pointer-events: none;
cursor: not-allowed;
}
/* Enhanced Lightbox Styles */
.lightbox {
display: none;
position: fixed;
z-index: 9999;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.95);
animation: fadeIn 0.3s ease;
}
.lightbox.active {
display: block;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fadeOut {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes zoomIn {
from {
transform: translate(-50%, -50%) scale(0.8);
opacity: 0;
}
to {
transform: translate(-50%, -50%) scale(1);
opacity: 1;
}
}
.lightbox-content {
margin: auto;
display: block;
max-width: 90vw;
max-height: 90vh;
position: absolute;
/*top: 50%;
left: 50%;*/
transform: translate(-50%, -50%);
border-radius: 4px;
box-shadow: 0 0 50px rgba(0,0,0,0.8);
animation: zoomIn 0.3s ease;
object-fit: contain;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 35px;
color: #f1f1f1;
font-size: 50px;
font-weight: 300;
cursor: pointer;
z-index: 10000;
transition: all 0.3s;
width: 50px;
height: 50px;
line-height: 50px;
text-align: center;
background: rgba(0,0,0,0.5);
border-radius: 50%;
}
.lightbox-close:hover {
background: rgba(255,255,255,0.2);
transform: rotate(90deg);
}
.lightbox-nav {
position: absolute;
top: 50%;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
transform: translateY(-50%);
pointer-events: none;
z-index: 10000;
}
.lightbox-nav button {
pointer-events: all;
background: rgba(0,0,0,0.5);
border: 2px solid rgba(255,255,255,0.3);
color: white;
font-size: 40px;
width: 60px;
height: 60px;
cursor: pointer;
border-radius: 50%;
transition: all 0.3s;
display: flex;
align-items: center;
justify-content: center;
line-height: 1;
}
.lightbox-nav button:hover {
background: rgba(255,255,255,0.3);
border-color: rgba(255,255,255,0.6);
transform: scale(1.1);
}
.lightbox-nav button:active {
transform: scale(0.95);
}
.lightbox-nav button:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.lightbox-nav button:disabled:hover {
background: rgba(0,0,0,0.5);
transform: scale(1);
}
.lightbox-info {
position: absolute;
bottom: 0;
left: 0;
right: 0;
background: linear-gradient(to top, rgba(0,0,0,0.8), transparent);
color: white;
padding: 40px 20px 20px;
z-index: 10000;
}
.lightbox-info h3 {
margin: 0 0 5px 0;
font-size: 20px;
font-weight: 600;
}
.lightbox-info p {
margin: 0;
font-size: 14px;
color: rgba(255,255,255,0.8);
}
.lightbox-counter {
position: absolute;
top: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.6);
color: white;
padding: 10px 20px;
border-radius: 20px;
font-size: 14px;
z-index: 10000;
}
.lightbox-loading {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 18px;
}
.no-images {
text-align: center;
padding: 60px 20px;
color: #666;
font-size: 18px;
grid-column: 1 / -1;
}
/* Responsive adjustments */
@media (max-width: 768px) {
.gallery-grid {
grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
gap: 15px;
}
.gallery-item img {
height: 180px;
}
.tabs-container {
gap: 8px;
}
.tab-btn {
padding: 8px 15px;
font-size: 13px;
}
.lightbox-nav button {
font-size: 30px;
width: 50px;
height: 50px;
}
.lightbox-close {
font-size: 40px;
width: 40px;
height: 40px;
line-height: 40px;
top: 15px;
right: 15px;
}
.lightbox-content {
max-width: 95vw;
max-height: 85vh;
}
.lightbox-info h3 {
font-size: 16px;
}
.lightbox-info p {
font-size: 12px;
}
}
</style>
<?php
return ob_get_clean();
}
// AJAX handler for loading more images (optional - for infinite scroll)
add_action('wp_ajax_load_collection_images', 'load_collection_images_ajax');
add_action('wp_ajax_nopriv_load_collection_images', 'load_collection_images_ajax');
function load_collection_images_ajax() {
check_ajax_referer('collection_nonce', 'nonce');
$collection_slug = sanitize_key($_POST['collection']);
$page = absint($_POST['page']);
$per_page = absint($_POST['per_page']);
// Find the post by slug
$post = get_page_by_path($collection_slug, OBJECT, 'image_collection');
if (!$post) {
wp_send_json_error('Collection not found');
return;
}
$image_collection = get_image_collection_paginated($post->ID, $per_page, $page);
wp_send_json_success($image_collection);
}