feat(gallery): tambah CPT Galeri, template page-galeri, filter interaktif, dan native lightbox zoom
This commit is contained in:
@@ -904,3 +904,11 @@ function edukarsa_about_page_html() {
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// Menyuntikkan sub-menu Galeri ke dalam menu utama EduKarsa
|
||||
add_action('admin_menu', function() {
|
||||
// Deteksi parent slug (edukarsa_main_menu atau edukarsa_settings)
|
||||
$parent = menu_page_url('edukarsa_main_menu', false) ? 'edukarsa_main_menu' : 'edukarsa_settings';
|
||||
add_submenu_page( $parent, 'Semua Galeri', '📸 Galeri Fasilitas', 'manage_options', 'edit.php?post_type=galeri' );
|
||||
add_submenu_page( $parent, 'Kategori Galeri', '📂 Kategori Galeri', 'manage_options', 'edit-tags.php?taxonomy=kategori_galeri&post_type=galeri' );
|
||||
}, 100);
|
||||
|
||||
@@ -46,3 +46,30 @@ function edukarsa_slider_save_meta( $post_id ) {
|
||||
if ( isset( $_POST['slider_link'] ) ) { update_post_meta( $post_id, '_slider_link', sanitize_text_field( $_POST['slider_link'] ) ); }
|
||||
}
|
||||
add_action( 'save_post', 'edukarsa_slider_save_meta' );
|
||||
|
||||
// --- REGISTRASI CPT GALERI & TAXONOMY ---
|
||||
function edukarsa_register_galeri_cpt() {
|
||||
register_post_type( 'galeri', array(
|
||||
'labels' => array(
|
||||
'name' => 'Galeri Fasilitas',
|
||||
'singular_name' => 'Galeri',
|
||||
'add_new_item' => 'Tambah Foto Galeri',
|
||||
'all_items' => 'Semua Foto Galeri'
|
||||
),
|
||||
'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'menu_icon' => 'dashicons-format-gallery'
|
||||
));
|
||||
|
||||
register_taxonomy( 'kategori_galeri', 'galeri', array(
|
||||
'labels' => array('name' => 'Kategori Galeri', 'singular_name' => 'Kategori', 'add_new_item' => 'Tambah Kategori'),
|
||||
'hierarchical' => true,
|
||||
'public' => true,
|
||||
'show_ui' => true,
|
||||
'show_admin_column' => true,
|
||||
'show_in_menu' => false
|
||||
));
|
||||
}
|
||||
add_action( 'init', 'edukarsa_register_galeri_cpt', 0 );
|
||||
|
||||
+234
@@ -0,0 +1,234 @@
|
||||
<?php
|
||||
/**
|
||||
* Template Name: Galeri & Fasilitas
|
||||
* Deskripsi: Menampilkan grid foto galeri dengan filter kategori dan efek Zoom/Lightbox interaktif.
|
||||
*/
|
||||
get_header();
|
||||
?>
|
||||
|
||||
<main id="primary" class="site-main edukarsa-gallery-page" style="padding: 60px 0 80px; background-color: var(--bg-light-blue); min-height: 75vh;">
|
||||
<div class="container">
|
||||
|
||||
<!-- Header Seksi Galeri -->
|
||||
<div class="section-header text-center" style="margin-bottom: 40px;">
|
||||
<span class="badge-title">FASILITAS & DOKUMENTASI KAMI</span>
|
||||
<h1 class="section-title">Galeri Kampus</h1>
|
||||
<hr class="title-underline">
|
||||
<p style="color: #64748b; max-width: 600px; margin: 0 auto; line-height: 1.7; font-size: 15px;">
|
||||
Jelajahi berbagai fasilitas pendukung belajar, laboratorium, sarana olahraga, dan lingkungan inspiratif di institusi kami.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<!-- Tombol Filter Kategori -->
|
||||
<div class="gallery-filters text-center" style="margin-bottom: 40px;">
|
||||
<button class="gallery-filter-btn active" data-filter="all">Semua Foto</button>
|
||||
<?php
|
||||
$terms = get_terms( array( 'taxonomy' => 'kategori_galeri', 'hide_empty' => true ) );
|
||||
foreach ( $terms as $term ) {
|
||||
echo '<button class="gallery-filter-btn" data-filter="' . esc_attr( $term->slug ) . '">' . esc_html( $term->name ) . '</button>';
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
|
||||
<!-- Grid Foto Galeri -->
|
||||
<div class="gallery-grid" id="edukarsa-gallery-grid">
|
||||
<?php
|
||||
$query_galeri = new WP_Query( array( 'post_type' => 'galeri', 'posts_per_page' => -1 ) );
|
||||
if ( $query_galeri->have_posts() ) :
|
||||
$idx = 0;
|
||||
while ( $query_galeri->have_posts() ) : $query_galeri->the_post();
|
||||
// Ambil kategori untuk filter class
|
||||
$terms = get_the_terms( get_the_ID(), 'kategori_galeri' );
|
||||
$term_slugs = '';
|
||||
$term_names = '';
|
||||
if ( $terms && ! is_wp_error( $terms ) ) {
|
||||
$slugs = array();
|
||||
$names = array();
|
||||
foreach ( $terms as $term ) {
|
||||
$slugs[] = $term->slug;
|
||||
$names[] = $term->name;
|
||||
}
|
||||
$term_slugs = implode( ' ', $slugs );
|
||||
$term_names = implode( ', ', $names );
|
||||
}
|
||||
|
||||
// Ambil URL gambar dan deskripsi
|
||||
$img_full = has_post_thumbnail() ? get_the_post_thumbnail_url( get_the_ID(), 'full' ) : '';
|
||||
$img_thumb = has_post_thumbnail() ? get_the_post_thumbnail_url( get_the_ID(), 'large' ) : '';
|
||||
|
||||
// Prioritaskan Excerpt, jika kosong ambil paragraf pertama dari Content
|
||||
$desc = wp_strip_all_tags( get_the_excerpt() );
|
||||
if ( empty($desc) ) {
|
||||
$desc = wp_trim_words( wp_strip_all_tags( get_the_content() ), 25, '...' );
|
||||
}
|
||||
?>
|
||||
|
||||
<div class="gallery-item-card <?php echo esc_attr( $term_slugs ); ?>"
|
||||
data-src="<?php echo esc_url( $img_full ); ?>"
|
||||
data-title="<?php echo esc_attr( get_the_title() ); ?>"
|
||||
data-desc="<?php echo esc_attr( $desc ); ?>"
|
||||
data-cat="<?php echo esc_attr( $term_names ); ?>">
|
||||
|
||||
<div class="gallery-img-wrapper">
|
||||
<?php if ( $img_thumb ) : ?>
|
||||
<img src="<?php echo esc_url( $img_thumb ); ?>" alt="<?php the_title(); ?>" loading="lazy">
|
||||
<?php else: ?>
|
||||
<div class="img-placeholder" style="height: 100%;"><i>📸</i></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="gallery-overlay">
|
||||
<span class="gallery-zoom-icon">🔍</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gallery-item-info">
|
||||
<h4><?php the_title(); ?></h4>
|
||||
<?php if($term_names): ?>
|
||||
<span class="gallery-cat-badge"><?php echo esc_html( $term_names ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
$idx++;
|
||||
endwhile;
|
||||
wp_reset_postdata();
|
||||
else :
|
||||
echo '<div style="grid-column: 1 / -1; text-align: center; padding: 40px; background: #fff; border-radius: 12px; border: 1px dashed #cbd5e1; color: #64748b;">Belum ada foto galeri yang dipublikasikan.</div>';
|
||||
endif;
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<!-- VANILLA JS LIGHTBOX (ZOOM EFFECT OVERLAY) -->
|
||||
<div id="ek-lightbox" class="ek-lightbox">
|
||||
<span class="ek-lb-close" id="ek-lb-close" title="Tutup">×</span>
|
||||
<div class="ek-lb-content">
|
||||
<div class="ek-lb-img-container">
|
||||
<img id="ek-lb-img" src="" alt="">
|
||||
</div>
|
||||
<div class="ek-lb-caption">
|
||||
<span id="ek-lb-cat" class="ek-lb-cat"></span>
|
||||
<h3 id="ek-lb-title"></h3>
|
||||
<p id="ek-lb-desc"></p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="ek-lb-nav ek-lb-prev" id="ek-lb-prev" title="Sebelumnya">❮</button>
|
||||
<button class="ek-lb-nav ek-lb-next" id="ek-lb-next" title="Selanjutnya">❯</button>
|
||||
</div>
|
||||
|
||||
<!-- Logika Interaktif Native JS -->
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", function() {
|
||||
// 1. LOGIKA FILTER KATEGORI (SMOOTH FADE)
|
||||
const filterBtns = document.querySelectorAll('.gallery-filter-btn');
|
||||
const galleryItems = document.querySelectorAll('.gallery-item-card');
|
||||
|
||||
filterBtns.forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
// Hapus status aktif dari semua tombol
|
||||
filterBtns.forEach(b => b.classList.remove('active'));
|
||||
btn.classList.add('active');
|
||||
|
||||
const filterValue = btn.getAttribute('data-filter');
|
||||
|
||||
galleryItems.forEach(item => {
|
||||
// Sembunyikan dengan fade out
|
||||
item.style.opacity = '0';
|
||||
item.style.transform = 'scale(0.95)';
|
||||
|
||||
setTimeout(() => {
|
||||
if (filterValue === 'all' || item.classList.contains(filterValue)) {
|
||||
item.style.display = 'block';
|
||||
// Beri jeda sedikit agar display block dirender sebelum mengubah opacity
|
||||
setTimeout(() => {
|
||||
item.style.opacity = '1';
|
||||
item.style.transform = 'scale(1)';
|
||||
}, 50);
|
||||
} else {
|
||||
item.style.display = 'none';
|
||||
}
|
||||
}, 300); // 300ms sesuaikan dengan durasi CSS transition
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// 2. LOGIKA LIGHTBOX / ZOOM SLIDER
|
||||
const lightbox = document.getElementById('ek-lightbox');
|
||||
const lbImg = document.getElementById('ek-lb-img');
|
||||
const lbTitle = document.getElementById('ek-lb-title');
|
||||
const lbDesc = document.getElementById('ek-lb-desc');
|
||||
const lbCat = document.getElementById('ek-lb-cat');
|
||||
const closeBtn = document.getElementById('ek-lb-close');
|
||||
const prevBtn = document.getElementById('ek-lb-prev');
|
||||
const nextBtn = document.getElementById('ek-lb-next');
|
||||
|
||||
let currentIndex = 0;
|
||||
let visibleItems = [];
|
||||
|
||||
// Fungsi untuk memperbarui daftar item yang sedang tidak disembunyikan oleh filter
|
||||
function updateVisibleItems() {
|
||||
visibleItems = Array.from(galleryItems).filter(item => item.style.display !== 'none');
|
||||
}
|
||||
|
||||
function openLightbox(index) {
|
||||
if(visibleItems.length === 0) return;
|
||||
currentIndex = index;
|
||||
const item = visibleItems[currentIndex];
|
||||
|
||||
lbImg.src = item.getAttribute('data-src');
|
||||
lbTitle.textContent = item.getAttribute('data-title');
|
||||
lbDesc.textContent = item.getAttribute('data-desc');
|
||||
lbCat.textContent = item.getAttribute('data-cat');
|
||||
|
||||
lightbox.classList.add('show');
|
||||
document.body.style.overflow = 'hidden'; // Kunci scroll halaman belakang
|
||||
}
|
||||
|
||||
function closeLightbox() {
|
||||
lightbox.classList.remove('show');
|
||||
document.body.style.overflow = ''; // Kembalikan scroll
|
||||
setTimeout(() => lbImg.src = '', 300); // Bersihkan gambar setelah animasi tutup
|
||||
}
|
||||
|
||||
function showNext() {
|
||||
currentIndex = (currentIndex + 1) % visibleItems.length;
|
||||
openLightbox(currentIndex);
|
||||
}
|
||||
|
||||
function showPrev() {
|
||||
currentIndex = (currentIndex - 1 + visibleItems.length) % visibleItems.length;
|
||||
openLightbox(currentIndex);
|
||||
}
|
||||
|
||||
// Pasang Event Klik pada setiap foto di Grid
|
||||
galleryItems.forEach(item => {
|
||||
item.addEventListener('click', function() {
|
||||
updateVisibleItems();
|
||||
const idx = visibleItems.indexOf(this);
|
||||
if(idx !== -1) openLightbox(idx);
|
||||
});
|
||||
});
|
||||
|
||||
// Event Navigasi Lightbox
|
||||
closeBtn.addEventListener('click', closeLightbox);
|
||||
nextBtn.addEventListener('click', showNext);
|
||||
prevBtn.addEventListener('click', showPrev);
|
||||
|
||||
// Tutup jika mengklik area kosong di luar konten
|
||||
lightbox.addEventListener('click', function(e) {
|
||||
if (e.target === lightbox) closeLightbox();
|
||||
});
|
||||
|
||||
// Dukungan Navigasi Keyboard
|
||||
document.addEventListener('keydown', function(e) {
|
||||
if (!lightbox.classList.contains('show')) return;
|
||||
if (e.key === 'Escape') closeLightbox();
|
||||
if (e.key === 'ArrowRight') showNext();
|
||||
if (e.key === 'ArrowLeft') showPrev();
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
@@ -717,3 +717,155 @@ body.a11y-underline-links a { text-decoration: underline !important; text-underl
|
||||
.sidebar-html-rendered-content { font-size: 14px; line-height: 1.7; color: var(--text-color); }
|
||||
.sidebar-html-rendered-content iframe { width: 100% !important; border-radius: 8px; border: none; }
|
||||
.sidebar-html-rendered-content img { border-radius: 8px; margin: 10px 0; }
|
||||
|
||||
/* ---------------------------------------------------------
|
||||
MODUL GALERI & FASILITAS (GRID + LIGHTBOX)
|
||||
--------------------------------------------------------- */
|
||||
.gallery-filters { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; }
|
||||
.gallery-filter-btn {
|
||||
background: #ffffff;
|
||||
border: 2px solid #e2e8f0;
|
||||
color: var(--text-muted);
|
||||
padding: 8px 22px;
|
||||
border-radius: 50px;
|
||||
font-weight: 700;
|
||||
font-size: 14px;
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
.gallery-filter-btn:hover, .gallery-filter-btn.active {
|
||||
background: var(--primary-color);
|
||||
border-color: var(--primary-color);
|
||||
color: #ffffff;
|
||||
box-shadow: 0 4px 12px rgba(11, 74, 142, 0.2);
|
||||
}
|
||||
|
||||
.gallery-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
||||
gap: 25px;
|
||||
}
|
||||
|
||||
.gallery-item-card {
|
||||
background: #ffffff;
|
||||
border-radius: 14px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.04);
|
||||
cursor: pointer;
|
||||
transition: all 0.3s ease;
|
||||
border: 1px solid #f1f5f9;
|
||||
}
|
||||
.gallery-item-card:hover {
|
||||
transform: translateY(-6px);
|
||||
box-shadow: 0 15px 35px rgba(11, 74, 142, 0.12);
|
||||
border-color: var(--secondary-color);
|
||||
}
|
||||
|
||||
.gallery-img-wrapper {
|
||||
position: relative;
|
||||
aspect-ratio: 4/3;
|
||||
overflow: hidden;
|
||||
background: #f8fafc;
|
||||
}
|
||||
.gallery-img-wrapper img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
object-fit: cover;
|
||||
transition: transform 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94);
|
||||
}
|
||||
.gallery-item-card:hover .gallery-img-wrapper img {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
.gallery-overlay {
|
||||
position: absolute; top: 0; left: 0; right: 0; bottom: 0;
|
||||
background: linear-gradient(to bottom, rgba(11,74,142,0.2) 0%, rgba(11,74,142,0.8) 100%);
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
opacity: 0; transition: opacity 0.3s ease;
|
||||
}
|
||||
.gallery-item-card:hover .gallery-overlay { opacity: 1; }
|
||||
|
||||
.gallery-zoom-icon {
|
||||
font-size: 32px; color: #fff;
|
||||
transform: translateY(20px);
|
||||
transition: transform 0.3s ease;
|
||||
filter: drop-shadow(0 4px 6px rgba(0,0,0,0.3));
|
||||
}
|
||||
.gallery-item-card:hover .gallery-zoom-icon { transform: translateY(0); }
|
||||
|
||||
.gallery-item-info { padding: 22px 20px; }
|
||||
.gallery-item-info h4 { margin: 0 0 10px; font-size: 17px; font-weight: 800; color: var(--heading-color); line-height: 1.4; }
|
||||
.gallery-cat-badge {
|
||||
display: inline-block;
|
||||
font-size: 11px; font-weight: 800;
|
||||
color: var(--secondary-color);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
background: #e0f2fe; padding: 4px 12px; border-radius: 20px;
|
||||
}
|
||||
|
||||
/* NATIVE LIGHTBOX (ZOOM EFEK) */
|
||||
.ek-lightbox {
|
||||
position: fixed; top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(15, 23, 42, 0.96); z-index: 9999;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
opacity: 0; visibility: hidden; transition: all 0.3s ease;
|
||||
backdrop-filter: blur(8px);
|
||||
}
|
||||
.ek-lightbox.show { opacity: 1; visibility: visible; }
|
||||
|
||||
.ek-lb-close {
|
||||
position: absolute; top: 25px; right: 35px; font-size: 45px;
|
||||
color: rgba(255,255,255,0.6); cursor: pointer; line-height: 1;
|
||||
transition: color 0.2s, transform 0.2s; z-index: 10;
|
||||
}
|
||||
.ek-lb-close:hover { color: #f59e0b; transform: scale(1.1); }
|
||||
|
||||
.ek-lb-content {
|
||||
max-width: 900px; width: 92%; max-height: 90vh;
|
||||
display: flex; flex-direction: column;
|
||||
background: #ffffff; border-radius: 16px; overflow: hidden;
|
||||
transform: scale(0.95); transition: transform 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275);
|
||||
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
.ek-lightbox.show .ek-lb-content { transform: scale(1); }
|
||||
|
||||
.ek-lb-img-container {
|
||||
width: 100%; height: 60vh; background: #000;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.ek-lb-img-container img {
|
||||
width: 100%; height: 100%; object-fit: contain;
|
||||
}
|
||||
|
||||
.ek-lb-caption { padding: 25px 35px; text-align: center; }
|
||||
.ek-lb-cat {
|
||||
font-size: 12px; font-weight: 800; color: var(--secondary-color);
|
||||
text-transform: uppercase; letter-spacing: 1px; display: inline-block;
|
||||
margin-bottom: 8px; background: #f1f5f9; padding: 4px 14px; border-radius: 20px;
|
||||
}
|
||||
.ek-lb-caption h3 { margin: 0 0 12px; font-size: 24px; font-weight: 800; color: var(--heading-color); }
|
||||
.ek-lb-caption p { margin: 0; font-size: 15px; color: var(--text-color); line-height: 1.7; }
|
||||
|
||||
/* Tombol Navigasi Lightbox */
|
||||
.ek-lb-nav {
|
||||
position: absolute; top: 50%; transform: translateY(-50%);
|
||||
background: rgba(255,255,255,0.1); border: 1px solid rgba(255,255,255,0.2);
|
||||
color: #ffffff; width: 56px; height: 56px; border-radius: 50%;
|
||||
font-size: 20px; cursor: pointer; transition: all 0.2s ease;
|
||||
display: flex; align-items: center; justify-content: center;
|
||||
}
|
||||
.ek-lb-nav:hover { background: var(--primary-color); border-color: var(--primary-color); transform: translateY(-50%) scale(1.1); }
|
||||
.ek-lb-prev { left: 40px; }
|
||||
.ek-lb-next { right: 40px; }
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.ek-lb-nav { width: 44px; height: 44px; font-size: 16px; }
|
||||
.ek-lb-prev { left: 15px; }
|
||||
.ek-lb-next { right: 15px; }
|
||||
.ek-lb-close { top: 15px; right: 20px; font-size: 35px; }
|
||||
.ek-lb-img-container { height: 45vh; }
|
||||
.ek-lb-caption { padding: 20px; }
|
||||
.ek-lb-caption h3 { font-size: 20px; }
|
||||
.gallery-grid { grid-template-columns: 1fr; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user