
https://www.mobirise-tutorials.com/Tuto ... Upload.php
Code: Alles auswählen
<?php
// Konfiguration - Pfade zur Bildergalerie
define('UPLOAD_DIR', 'uploads/');
define('THUMB_DIR', 'uploads/thumbs/');
// Funktion zum Abrufen der Bilder
function getGalleryImages() {
$images = [];
if (!is_dir(UPLOAD_DIR)) {
return $images;
}
$files = glob(UPLOAD_DIR . '*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE);
foreach ($files as $file) {
$filename = basename($file);
$thumbPath = THUMB_DIR . $filename;
$images[] = [
'filename' => $filename,
'full_path' => $file,
'thumb_path' => file_exists($thumbPath) ? $thumbPath : $file,
'size' => filesize($file),
'modified' => filemtime($file)
];
}
// Sortiere nach Dateiname (aufsteigend, numerisch korrekt)
usort($images, function($a, $b) {
return strnatcmp($a['filename'], $b['filename']);
});
return $images;
}
$galleryImages = getGalleryImages();
// Parameter für Paginierung
$imagesPerPage = isset($_GET['per_page']) ? max(6, min(50, intval($_GET['per_page']))) : 12;
$currentPage = isset($_GET['page']) ? max(1, intval($_GET['page'])) : 1;
$totalImages = count($galleryImages);
$totalPages = ceil($totalImages / $imagesPerPage);
$startIndex = ($currentPage - 1) * $imagesPerPage;
$currentImages = array_slice($galleryImages, $startIndex, $imagesPerPage);
?>
<style>
body {
background-color: white;
}
.gallery-container {
max-width: 1400px;
margin: 0 auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}
.gallery-header {
text-align: center;
margin-bottom: 40px;
}
.gallery-title {
font-size: 2.5rem;
color: #333;
margin-bottom: 10px;
background: linear-gradient(45deg, #667eea, #764ba2);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gallery-stats {
color: #666;
font-size: 1.1rem;
margin-bottom: 20px;
}
.gallery-controls {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
margin-bottom: 30px;
flex-wrap: wrap;
}
.per-page-selector {
display: flex;
align-items: center;
gap: 10px;
}
.per-page-selector select {
padding: 8px 12px;
border: 2px solid #e1e5e9;
border-radius: 8px;
font-size: 14px;
background: white;
cursor: pointer;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 25px;
margin-bottom: 40px;
}
.gallery-item {
background: white;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
cursor: pointer;
}
.gallery-item:hover {
transform: translateY(-8px);
box-shadow: 0 12px 40px rgba(0, 0, 0, 0.15);
}
.gallery-item img {
width: 100%;
height: 250px;
object-fit: cover;
transition: transform 0.3s ease;
}
.gallery-item:hover img {
transform: scale(1.1);
}
.gallery-item-info {
padding: 15px;
text-align: center;
}
.image-title {
font-weight: 600;
color: #333;
font-size: 14px;
margin-bottom: 5px;
word-break: break-word;
}
.image-meta {
font-size: 12px;
color: #888;
}
.pagination {
display: flex;
justify-content: center;
align-items: center;
gap: 10px;
margin-top: 40px;
flex-wrap: wrap;
}
.pagination a, .pagination span {
padding: 10px 15px;
text-decoration: none;
border: 2px solid #e1e5e9;
border-radius: 8px;
color: #333;
font-weight: 500;
transition: all 0.3s ease;
min-width: 45px;
text-align: center;
}
.pagination a:hover {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border-color: transparent;
}
.pagination .current {
background: linear-gradient(45deg, #667eea, #764ba2);
color: white;
border-color: transparent;
}
.pagination .disabled {
opacity: 0.5;
cursor: not-allowed;
}
.pagination .disabled:hover {
background: white;
color: #333;
border-color: #e1e5e9;
}
.lightbox {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.95);
z-index: 10000;
cursor: pointer;
justify-content: center;
align-items: center;
}
.lightbox-content {
display: flex;
flex-direction: column;
align-items: center;
max-width: 95vw;
max-height: 95vh;
text-align: center;
}
.lightbox img {
max-width: 100%;
max-height: 100%;
object-fit: contain;
border-radius: 10px;
box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
}
.lightbox-info {
color: white;
margin-top: 20px;
font-size: 16px;
}
.lightbox-close {
position: absolute;
top: 20px;
right: 30px;
color: white;
font-size: 40px;
cursor: pointer;
z-index: 10001;
transition: opacity 0.3s ease;
}
.lightbox-close:hover {
opacity: 0.7;
}
.lightbox-nav {
position: absolute;
top: 50%;
transform: translateY(-50%);
color: white;
font-size: 30px;
cursor: pointer;
background: rgba(0, 0, 0, 0.5);
padding: 20px;
border-radius: 50%;
transition: all 0.3s ease;
user-select: none;
}
.lightbox-nav:hover {
background: rgba(0, 0, 0, 0.8);
}
.lightbox-prev {
left: 30px;
}
.lightbox-next {
right: 30px;
}
.empty-gallery {
text-align: center;
padding: 80px 20px;
color: #666;
}
.empty-gallery h3 {
font-size: 1.5rem;
margin-bottom: 10px;
}
/* Responsive */
@media (max-width: 768px) {
.gallery-container {
padding: 15px;
}
.gallery-title {
font-size: 2rem;
}
.gallery-grid {
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 20px;
}
.gallery-controls {
flex-direction: column;
gap: 15px;
}
.pagination {
gap: 5px;
}
.pagination a, .pagination span {
padding: 8px 12px;
font-size: 14px;
}
.lightbox-nav {
font-size: 24px;
padding: 15px;
}
.lightbox-close {
font-size: 30px;
top: 15px;
right: 20px;
}
}
@media (max-width: 480px) {
.gallery-grid {
grid-template-columns: 1fr;
gap: 15px;
}
.lightbox-nav {
display: none;
}
}
/* NEU: Bilder in der Lightbox auf größeren Bildschirmen verkleinern */
@media (min-width: 769px) {
.lightbox img {
max-width: 80vw;
max-height: 80vh;
}
}
</style>
<div id="galerie" class="gallery-container">
<div class="gallery-header">
<h1 class="gallery-title"> Bilder der Rehmühle</h1>
<div class="gallery-stats">
<?php echo $totalImages; ?> Bilder
<?php if ($totalPages > 1): ?>
• Seite <?php echo $currentPage; ?> von <?php echo $totalPages; ?>
<?php endif; ?>
</div>
</div>
<?php if ($totalImages > 0): ?>
<div class="gallery-controls">
<div class="per-page-selector">
<label for="per-page">Bilder pro Seite:</label>
<select id="per-page" onchange="changePerPage(this.value)">
<option value="6" <?php echo $imagesPerPage == 6 ? 'selected' : ''; ?>>6</option>
<option value="12" <?php echo $imagesPerPage == 12 ? 'selected' : ''; ?>>12</option>
<option value="24" <?php echo $imagesPerPage == 24 ? 'selected' : ''; ?>>24</option>
<option value="48" <?php echo $imagesPerPage == 48 ? 'selected' : ''; ?>>48</option>
</select>
</div>
</div>
<div class="gallery-grid">
<?php foreach ($currentImages as $index => $image): ?>
<div class="gallery-item" onclick="openLightbox(event, <?php echo $startIndex + $index; ?>)">
<img
src="<?php echo htmlspecialchars($image['thumb_path']); ?>"
alt="<?php echo htmlspecialchars($image['filename']); ?>"
loading="lazy"
>
<div class="gallery-item-info">
<div class="image-title">
<?php echo htmlspecialchars($image['filename']); ?>
</div>
<div class="image-meta">
<?php echo date('d.m.Y', $image['modified']); ?> •
<?php echo number_format($image['size'] / 1024, 1); ?> KB
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if ($totalPages > 1): ?>
<div class="pagination">
<?php if ($currentPage > 1): ?>
<a href="?page=1&per_page=<?php echo $imagesPerPage; ?>">«</a>
<a href="?page=<?php echo $currentPage - 1; ?>&per_page=<?php echo $imagesPerPage; ?>">‹</a>
<?php else: ?>
<span class="disabled">«</span>
<span class="disabled">‹</span>
<?php endif; ?>
<?php
$start = max(1, $currentPage - 2);
$end = min($totalPages, $currentPage + 2);
if ($start > 1) {
echo '<a href="?page=1&per_page=' . $imagesPerPage . '">1</a>';
if ($start > 2) echo '<span>...</span>';
}
for ($i = $start; $i <= $end; $i++): ?>
<?php if ($i == $currentPage): ?>
<span class="current"><?php echo $i; ?></span>
<?php else: ?>
<a href="?page=<?php echo $i; ?>&per_page=<?php echo $imagesPerPage; ?>"><?php echo $i; ?></a>
<?php endif; ?>
<?php endfor;
if ($end < $totalPages) {
if ($end < $totalPages - 1) echo '<span>...</span>';
echo '<a href="?page=' . $totalPages . '&per_page=' . $imagesPerPage . '">' . $totalPages . '</a>';
}
?>
<?php if ($currentPage < $totalPages): ?>
<a href="?page=<?php echo $currentPage + 1; ?>&per_page=<?php echo $imagesPerPage; ?>">›</a>
<a href="?page=<?php echo $totalPages; ?>&per_page=<?php echo $imagesPerPage; ?>">»</a>
<?php else: ?>
<span class="disabled">›</span>
<span class="disabled">»</span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php else: ?>
<div class="empty-gallery">
<h3>Noch keine Bilder verfügbar</h3>
<p>Die Galerie ist momentan leer.</p>
</div>
<?php endif; ?>
</div>
<div id="lightbox" class="lightbox" onclick="closeLightbox()">
<span class="lightbox-close" onclick="closeLightbox()">×</span>
<div class="lightbox-prev lightbox-nav" onclick="event.stopPropagation(); prevImage()">‹</div>
<div class="lightbox-next lightbox-nav" onclick="event.stopPropagation(); nextImage()">›</div>
<div class="lightbox-content">
<img id="lightbox-img" src="" alt="">
<div id="lightbox-info" class="lightbox-info"></div>
</div>
</div>
<script>
// Galerie-Daten für JavaScript
const allImages = <?php echo json_encode($galleryImages); ?>;
let currentLightboxIndex = 0;
function openLightbox(event, index) {
event.stopPropagation();
currentLightboxIndex = index;
updateLightboxContent();
document.getElementById('lightbox').style.display = 'flex';
document.body.style.overflow = 'hidden';
}
function closeLightbox() {
document.getElementById('lightbox').style.display = 'none';
document.body.style.overflow = 'auto';
}
function updateLightboxContent() {
if (allImages[currentLightboxIndex]) {
const image = allImages[currentLightboxIndex];
document.getElementById('lightbox-img').src = image.full_path;
document.getElementById('lightbox-info').innerHTML =
'<strong>' + image.filename + '</strong><br>' +
new Date(image.modified * 1000).toLocaleDateString('de-DE') + ' • ' +
(image.size / 1024).toFixed(1) + ' KB';
}
}
function nextImage() {
if (currentLightboxIndex < allImages.length - 1) {
currentLightboxIndex++;
updateLightboxContent();
}
}
function prevImage() {
if (currentLightboxIndex > 0) {
currentLightboxIndex--;
updateLightboxContent();
}
}
function changePerPage(value) {
const url = new URL(window.location);
url.searchParams.set('per_page', value);
url.searchParams.set('page', '1');
window.location = url;
}
// Fix für unerwartetes Popup beim Neuladen
window.onload = function() {
document.getElementById('lightbox').style.display = 'none';
}
// Keyboard Navigation
document.addEventListener('keydown', function(e) {
const lightbox = document.getElementById('lightbox');
if (lightbox.style.display === 'flex') {
switch(e.key) {
case 'Escape':
closeLightbox();
break;
case 'ArrowLeft':
prevImage();
break;
case 'ArrowRight':
nextImage();
break;
}
}
});
// Touch/Swipe Support für Mobile
let touchStartX = 0;
let touchEndX = 0;
document.getElementById('lightbox').addEventListener('touchstart', function(e) {
touchStartX = e.changedTouches[0].screenX;
});
document.getElementById('lightbox').addEventListener('touchend', function(e) {
touchEndX = e.changedTouches[0].screenX;
handleSwipe();
});
function handleSwipe() {
const swipeDistance = touchEndX - touchStartX;
const minSwipeDistance = 50;
if (Math.abs(swipeDistance) > minSwipeDistance) {
if (swipeDistance > 0) {
prevImage(); // Swipe right = previous image
} else {
nextImage(); // Swipe left = next image
}
}
}
// Lazy Loading für bessere Performance
if ('IntersectionObserver' in window) {
const imageObserver = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove('lazy');
observer.unobserve(img);
}
});
});
document.querySelectorAll('img[data-src]').forEach(img => {
imageObserver.observe(img);
});
}
</script>
Code: Alles auswählen
https://www.mobirise-tutorials.com/Tutorials-3/Galerie-Upload.php?gal_per_page=6&gal_page=1#galerie
Code: Alles auswählen
<?php
// ========== KONFIG ==========
define('UPLOAD_DIR', 'uploads/');
define('THUMB_DIR', 'uploads/thumbs/');
// Optional: Wenn du die Links auf einen *bestimmten* Seitenpfad zwingen willst,
// kannst du hier z.B. '/Tutorials-3/Galerie-Upload.php' setzen.
// Leer lassen => es wird automatisch die aktuelle Seite (PHP_SELF) verwendet.
const GALLERY_SELF_PATH = ''; // z.B. '/deine-seite.php'
// ========== HILFSFUNKTIONEN ==========
function gallery_self_path(): string {
if (GALLERY_SELF_PATH !== '') return GALLERY_SELF_PATH;
// Sicherer, basisrelativer Pfad zur aktuell ausgeführten Seite
$path = parse_url($_SERVER['PHP_SELF'] ?? '', PHP_URL_PATH);
return $path ?: '/';
}
// Baut eine Galerie-URL: NUR die Galerie-Parameter, sonst nichts (robust gegen Konflikte)
function gallery_url_clean(int $page, int $perPage): string {
$path = gallery_self_path();
$query = http_build_query([
'gal_page' => max(1, $page),
'gal_per_page' => max(6, min(50, $perPage)),
]);
$url = $path . '?' . $query . '#galerie';
return htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
}
// Bilder holen
function getGalleryImages(): array {
$images = [];
if (!is_dir(UPLOAD_DIR)) return $images;
$files = glob(UPLOAD_DIR . '*.{jpg,jpeg,png,gif,webp}', GLOB_BRACE) ?: [];
foreach ($files as $file) {
$filename = basename($file);
$images[] = [
'filename' => $filename,
'full_path' => $file,
'thumb_path' => $file, // Original als Thumb
'size' => @filesize($file) ?: 0,
'modified' => @filemtime($file) ?: time(),
];
}
usort($images, fn($a,$b) => strnatcmp($a['filename'], $b['filename']));
return $images;
}
// ========== LOGIK ==========
$galleryImages = getGalleryImages();
$imagesPerPage = isset($_GET['gal_per_page']) ? max(6, min(50, (int)$_GET['gal_per_page'])) : 12;
$currentPage = isset($_GET['gal_page']) ? max(1, (int)$_GET['gal_page']) : 1;
$totalImages = count($galleryImages);
$totalPages = max(1, (int)ceil($totalImages / $imagesPerPage));
$currentPage = min($currentPage, $totalPages);
$startIndex = ($currentPage - 1) * $imagesPerPage;
$currentImages = array_slice($galleryImages, $startIndex, $imagesPerPage);
?>
<style>
/* ... (dein bestehendes CSS, unverändert) ... */
.gallery-container img { image-rendering:-webkit-optimize-contrast!important; image-rendering:optimize-contrast!important; image-rendering:crisp-edges!important; -ms-interpolation-mode:nearest-neighbor!important; transform:none!important; filter:none!important; }
.gallery-container img { max-width:100%!important; height:auto!important; display:block!important; }
body{background-color:white;}
.gallery-container{max-width:1400px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;scroll-margin-top:90px;}
.gallery-header{text-align:center;margin-bottom:40px;}
.gallery-title{font-size:2.5rem;color:#333;margin-bottom:10px;background:linear-gradient(45deg,#667eea,#764ba2);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;}
.gallery-stats{color:#666;font-size:1.1rem;margin-bottom:20px;}
.gallery-controls{display:flex;justify-content:center;align-items:center;gap:20px;margin-bottom:30px;flex-wrap:wrap;}
.per-page-selector{display:flex;align-items:center;gap:10px;}
.per-page-selector select{padding:8px 12px;border:2px solid #e1e5e9;border-radius:8px;font-size:14px;background:white;cursor:pointer;}
.gallery-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:25px;margin-bottom:40px;}
.gallery-item{background:white;border-radius:15px;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.08);transition:all .3s ease;cursor:pointer;}
.gallery-item:hover{transform:translateY(-8px);box-shadow:0 12px 40px rgba(0,0,0,.15);}
.gallery-item img{width:100%;height:250px;object-fit:cover;transition:transform .3s ease;}
.gallery-item:hover img{transform:scale(1.1)!important;}
.gallery-item-info{padding:15px;text-align:center;}
.image-title{font-weight:600;color:#333;font-size:14px;margin-bottom:5px;word-break:break-word;}
.image-meta{font-size:12px;color:#888;}
.pagination{display:flex;justify-content:center;align-items:center;gap:10px;margin-top:40px;flex-wrap:wrap;}
.pagination a,.pagination span{padding:10px 15px;text-decoration:none;border:2px solid #e1e5e9;border-radius:8px;color:#333;font-weight:500;transition:all .3s ease;min-width:45px;text-align:center;}
.pagination a:hover{background:linear-gradient(45deg,#667eea,#764ba2);color:white;border-color:transparent;}
.pagination .current{background:linear-gradient(45deg,#667eea,#764ba2);color:white;border-color:transparent;}
.pagination .disabled{opacity:.5;cursor:not-allowed;}
.pagination .disabled:hover{background:white;color:#333;border-color:#e1e5e9;}
.lightbox{display:none;position:fixed;inset:0;background:rgba(0,0,0,.95);z-index:10000;cursor:pointer;justify-content:center;align-items:center;}
.lightbox-content{display:flex;flex-direction:column;align-items:center;max-width:95vw;max-height:95vh;text-align:center;}
.lightbox img{max-width:100%;max-height:100%;object-fit:contain;border-radius:10px;box-shadow:0 0 50px rgba(0,0,0,.5);}
.lightbox-info{color:white;margin-top:20px;font-size:16px;}
.lightbox-close{position:absolute;top:20px;right:30px;color:white;font-size:40px;cursor:pointer;z-index:10001;transition:opacity .3s ease;}
.lightbox-close:hover{opacity:.7;}
.lightbox-nav{position:absolute;top:50%;transform:translateY(-50%);color:white;font-size:30px;cursor:pointer;background:rgba(0,0,0,.5);padding:20px;border-radius:50%;transition:all .3s ease;user-select:none;}
.lightbox-nav:hover{background:rgba(0,0,0,.8);}
.lightbox-prev{left:30px;}
.lightbox-next{right:30px;}
.empty-gallery{text-align:center;padding:80px 20px;color:#666;}
.empty-gallery h3{font-size:1.5rem;margin-bottom:10px;}
@media(max-width:768px){.gallery-container{padding:15px}.gallery-title{font-size:2rem}.gallery-grid{grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:20px}.gallery-controls{flex-direction:column;gap:15px}.pagination{gap:5px}.pagination a,.pagination span{padding:8px 12px;font-size:14px}.lightbox-nav{font-size:24px;padding:15px}.lightbox-close{font-size:30px;top:15px;right:20px}}
@media(max-width:480px){.gallery-grid{grid-template-columns:1fr;gap:15px}.lightbox-nav{display:none}}
@media(min-width:769px){.lightbox img{max-width:80vw;max-height:80vh}}
</style>
<div id="galerie" class="gallery-container">
<div class="gallery-header">
<h1 class="gallery-title">Bilder</h1>
<div class="gallery-stats">
<?php echo $totalImages; ?> Bilder
<?php if ($totalPages > 1): ?> • Seite <?php echo $currentPage; ?> von <?php echo $totalPages; ?> <?php endif; ?>
</div>
</div>
<?php if ($totalImages > 0): ?>
<div class="gallery-controls">
<div class="per-page-selector">
<label for="per-page">Bilder pro Seite:</label>
<select id="per-page" onchange="changePerPage(this.value)">
<option value="6" <?php echo $imagesPerPage == 6 ? 'selected' : ''; ?>>6</option>
<option value="12" <?php echo $imagesPerPage == 12 ? 'selected' : ''; ?>>12</option>
<option value="24" <?php echo $imagesPerPage == 24 ? 'selected' : ''; ?>>24</option>
<option value="48" <?php echo $imagesPerPage == 48 ? 'selected' : ''; ?>>48</option>
</select>
</div>
</div>
<div class="gallery-grid">
<?php foreach ($currentImages as $index => $image): ?>
<div class="gallery-item" onclick="openLightbox(event, <?php echo $startIndex + $index; ?>)">
<img src="<?php echo htmlspecialchars($image['thumb_path']); ?>" alt="<?php echo htmlspecialchars($image['filename']); ?>" loading="lazy">
<div class="gallery-item-info">
<div class="image-title"><?php echo htmlspecialchars($image['filename']); ?></div>
<div class="image-meta"><?php echo date('d.m.Y', $image['modified']); ?> • <?php echo number_format($image['size'] / 1024, 1); ?> KB</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php if ($totalPages > 1): ?>
<div class="pagination" id="gal-pagination">
<?php if ($currentPage > 1): ?>
<a href="<?php echo gallery_url_clean(1, $imagesPerPage); ?>" data-gal-page="1">«</a>
<a href="<?php echo gallery_url_clean($currentPage-1, $imagesPerPage); ?>" data-gal-page="<?php echo $currentPage-1; ?>">‹</a>
<?php else: ?>
<span class="disabled">«</span>
<span class="disabled">‹</span>
<?php endif; ?>
<?php
$start = max(1, $currentPage - 2);
$end = min($totalPages, $currentPage + 2);
if ($start > 1) {
echo '<a href="'.gallery_url_clean(1, $imagesPerPage).'" data-gal-page="1">1</a>';
if ($start > 2) echo '<span>...</span>';
}
for ($i = $start; $i <= $end; $i++) {
if ($i == $currentPage) {
echo '<span class="current">'.$i.'</span>';
} else {
echo '<a href="'.gallery_url_clean($i, $imagesPerPage).'" data-gal-page="'.$i.'">'.$i.'</a>';
}
}
if ($end < $totalPages) {
if ($end < $totalPages - 1) echo '<span>...</span>';
echo '<a href="'.gallery_url_clean($totalPages, $imagesPerPage).'" data-gal-page="'.$totalPages.'">'.$totalPages.'</a>';
}
?>
<?php if ($currentPage < $totalPages): ?>
<a href="<?php echo gallery_url_clean($currentPage+1, $imagesPerPage); ?>" data-gal-page="<?php echo $currentPage+1; ?>">›</a>
<a href="<?php echo gallery_url_clean($totalPages, $imagesPerPage); ?>" data-gal-page="<?php echo $totalPages; ?>">»</a>
<?php else: ?>
<span class="disabled">›</span>
<span class="disabled">»</span>
<?php endif; ?>
</div>
<?php endif; ?>
<?php else: ?>
<div class="empty-gallery">
<h3>Noch keine Bilder verfügbar</h3>
<p>Die Galerie ist momentan leer.</p>
</div>
<?php endif; ?>
</div>
<div id="lightbox" class="lightbox" onclick="closeLightbox()">
<span class="lightbox-close" onclick="closeLightbox()">×</span>
<div class="lightbox-prev lightbox-nav" onclick="event.stopPropagation(); prevImage()">‹</div>
<div class="lightbox-next lightbox-nav" onclick="event.stopPropagation(); nextImage()">›</div>
<div class="lightbox-content">
<img id="lightbox-img" src="" alt="">
<div id="lightbox-info" class="lightbox-info"></div>
</div>
</div>
<script>
// Daten
const allImages = <?php echo json_encode($galleryImages); ?>;
let currentLightboxIndex = 0;
// Lightbox
function openLightbox(e, idx){ e.stopPropagation(); currentLightboxIndex = idx; updateLightbox(); document.getElementById('lightbox').style.display='flex'; document.body.style.overflow='hidden'; }
function closeLightbox(){ document.getElementById('lightbox').style.display='none'; document.body.style.overflow='auto'; }
function updateLightbox(){
const img = allImages[currentLightboxIndex]; if(!img) return;
document.getElementById('lightbox-img').src = img.full_path;
document.getElementById('lightbox-info').innerHTML =
'<strong>'+img.filename+'</strong><br>'+
new Date(img.modified*1000).toLocaleDateString('de-DE')+' • '+(img.size/1024).toFixed(1)+' KB';
}
function nextImage(){ if(currentLightboxIndex < allImages.length-1){ currentLightboxIndex++; updateLightbox(); } }
function prevImage(){ if(currentLightboxIndex > 0){ currentLightboxIndex--; updateLightbox(); } }
// Per-Page
function changePerPage(value){
const url = new URL(window.location.href);
url.searchParams.set('gal_per_page', value);
url.searchParams.set('gal_page', '1');
url.hash = 'galerie';
window.location = url.toString();
}
// Onload: Hash beachten
window.onload = function(){
document.getElementById('lightbox').style.display='none';
if (location.hash === '#galerie') {
const el = document.getElementById('galerie');
if (el) el.scrollIntoView({ behavior: 'instant', block: 'start' });
}
};
// Tastatur
document.addEventListener('keydown', e=>{
const lb = document.getElementById('lightbox');
if (lb.style.display === 'flex') {
if (e.key === 'Escape') closeLightbox();
if (e.key === 'ArrowLeft') prevImage();
if (e.key === 'ArrowRight') nextImage();
}
});
// Touch/Swipe
let touchStartX=0,touchEndX=0;
document.getElementById('lightbox').addEventListener('touchstart', e=>{ touchStartX = e.changedTouches[0].screenX; });
document.getElementById('lightbox').addEventListener('touchend', e=>{
touchEndX = e.changedTouches[0].screenX;
const d = touchEndX - touchStartX; if (Math.abs(d) > 50) { d > 0 ? prevImage() : nextImage(); }
});
// Zusätzliche Absicherung: Pagination-Klicks per JS setzen (falls ein <base> o.ä. stört)
document.getElementById('gal-pagination')?.addEventListener('click', function(e){
const a = e.target.closest('a[data-gal-page]');
if (!a) return;
// Wenn ein Theme/Script das Link-Ziel verbiegt, erzwingen wir unseren Weg:
e.preventDefault();
const url = new URL(window.location.href);
url.searchParams.set('gal_page', a.getAttribute('data-gal-page'));
url.searchParams.set('gal_per_page', '<?php echo $imagesPerPage; ?>');
url.hash = 'galerie';
window.location = url.toString();
});
// Optionales Lazy Loading (nur wenn data-src vorhanden)
if ('IntersectionObserver' in window) {
const obs = new IntersectionObserver((entries,o)=>entries.forEach(en=>{
if (en.isIntersecting) {
const img = en.target;
if (img.dataset && img.dataset.src) { img.src = img.dataset.src; img.classList.remove('lazy'); o.unobserve(img); }
}
}));
document.querySelectorAll('img[data-src]').forEach(img=>obs.observe(img));
}
</script>
ChatGPT hat geschrieben:
Was das Problem war
Parameter-Konflikt
Dein ursprüngliches Skript verwendete ?page=... und ?per_page=....
Mobirise verwendet aber intern auch die Parameter page und per_page in manchen Blöcken oder beim internen Routing.
Wenn dein Include auf einer Mobirise-Seite eingebettet war, kollidierten diese Parameter.
Ergebnis:
Dein Link änderte zwar ?page=2
Aber Mobirise interpretierte diesen Wert selbst – und lieferte weiter Seite 1 der Galerie zurück.
Doppelte IDs & Hash-Verhalten
Dein Mobirise-Block und das Galerie-Skript hatten beide id="galerie".
Das war kein direkter Fehler, aber Mobirise hat auf Klicks mit JavaScript gescrollt und das Neuladen der Galerie teilweise blockiert.
Basis-URL & <base href>
Mobirise setzt in vielen Projekten <base href="..."> in den <head>.
Dadurch haben relative Links wie ?page=2 manchmal nicht auf die gleiche Seite gezeigt, sondern wurden durch die Base-URL umgeleitet.
Teilweise blieb man deshalb visuell auf Seite 1 hängen, obwohl sich die URL änderte.
Was wir geändert haben
Eigene Parameter verwendet
Statt page / per_page nehmen wir jetzt gal_page und gal_per_page.
Diese sind eindeutig und können nicht mit Mobirise kollidieren.
Links explizit auf dieselbe Seite gesetzt
Alle Paginierungs-Links werden jetzt dynamisch mit $_SERVER['PHP_SELF'] gebaut.
Dadurch zeigen sie immer auf das richtige PHP-Skript – egal, wie Mobirise-URLs, Includes oder Unterverzeichnisse strukturiert sind.
Hash #galerie am Ende
Der Hash sorgt dafür, dass der Browser nach dem Reload automatisch zum Galerie-Bereich springt.
Das machen wir sauber und konsistent in allen Links.
JavaScript-Fallback eingebaut
Falls Mobirise per JavaScript einen Link-Click überschreibt, fängt unser Skript den Klick ab und setzt die URL aktiv neu.
Damit erzwingen wir, dass wirklich die nächste Galerie-Seite geladen wird.
In einfachen Worten
Vorher:
→ Klick auf „Seite 2“ → Mobirise fing ?page=2 ab → Galerie blieb auf Seite 1 → Sprunganker funktionierte trotzdem, weil der Hash ja da war.
Jetzt:
→ Klick auf „Seite 2“ → unser Link geht mit eigenen Parametern → keine Kollision mehr → PHP lädt Seite 2 → Browser springt zur Galerie.
Mitglieder in diesem Forum: 0 Mitglieder und 2 Gäste