Files
WP-Business-Forum/includes/forum-plugin-watch.php
2026-04-05 12:40:36 +02:00

269 lines
14 KiB
PHP

<?php
/**
* WP Business Forum — Plugin-Watch Profil-Tab & Benachrichtigungen
* Pfad: includes/forum-plugin-watch.php
*/
if ( ! defined( 'ABSPATH' ) ) exit;
/* ══════════════════════════════════════════════════════════════
Allowed Tabs erweitern
══════════════════════════════════════════════════════════════ */
add_filter( 'wbf_allowed_profile_tabs', function( $tabs ) {
$tabs[] = 'plugins';
return $tabs;
} );
/* ══════════════════════════════════════════════════════════════
Tab-Inhalt rendern (direkt via class-forum-shortcodes.php Hook)
══════════════════════════════════════════════════════════════ */
function wbf_render_plugin_watch_tab( $profile, $current ) {
$watches = function_exists('vmcp_bridge_get_watches')
? vmcp_bridge_get_watches( $profile->id, 100 )
: [];
$archive_url = get_post_type_archive_link('mc_plugin') ?: home_url('/mc-plugins/');
// Nonce für vmcp_toggle_watch (aus MC-Plugin)
$vmcp_nonce = wp_create_nonce('vmcp_nonce');
$ajax_url = admin_url('admin-ajax.php');
?>
<div class="wbf-profile-card wbf-plugin-watch-card">
<div class="wbf-profile-card__header">
<i class="fas fa-bell"></i> Beobachtete Plugins
<span class="wbf-profile-card__count" id="wbf-watch-count-badge"><?php echo count($watches); ?></span>
</div>
<?php if ( empty($watches) ) : ?>
<div class="wbf-profile-empty" style="text-align:center;padding:24px 16px;">
<i class="fas fa-bell-slash" style="font-size:2.2em;color:#2a3a4a;margin-bottom:10px;display:block;"></i>
<p style="margin:0 0 10px;color:#4a6a8a;">Du beobachtest noch kein Plugin.</p>
<a href="<?php echo esc_url($archive_url); ?>" style="color:#00d4ff;font-weight:600;">
Plugins entdecken →
</a>
</div>
<?php else : ?>
<ul class="wbf-watch-list" id="wbf-watch-list">
<?php foreach ( $watches as $w ) :
$link = get_permalink( $w->plugin_id );
$thumb = get_the_post_thumbnail_url( $w->plugin_id, 'thumbnail' );
$version = get_post_meta( $w->plugin_id, '_vmcp_version', true );
$premium = get_post_meta( $w->plugin_id, '_vmcp_premium', true ) === '1';
$initial = mb_strtoupper( mb_substr( $w->post_title, 0, 1 ) );
$since = human_time_diff( strtotime($w->created_at), current_time('timestamp') );
?>
<li class="wbf-watch-item" data-plugin="<?php echo (int)$w->plugin_id; ?>">
<a href="<?php echo esc_url($link); ?>" class="wbf-watch-item__thumb">
<?php if ($thumb): ?>
<img src="<?php echo esc_url($thumb); ?>" alt="" loading="lazy">
<?php else: ?>
<div class="wbf-watch-item__initial"><?php echo esc_html($initial); ?></div>
<?php endif; ?>
</a>
<div class="wbf-watch-item__body">
<a href="<?php echo esc_url($link); ?>" class="wbf-watch-item__name">
<?php echo esc_html($w->post_title); ?>
</a>
<div class="wbf-watch-item__meta">
<?php if ($version): ?>
<span class="wbf-watch-item__ver">v<?php echo esc_html($version); ?></span>
<?php endif; ?>
<?php if ($premium): ?>
<span class="wbf-watch-item__premium">⭐ Premium</span>
<?php endif; ?>
<span class="wbf-watch-item__since">Seit <?php echo esc_html($since); ?></span>
</div>
</div>
<button type="button"
class="wbf-watch-unwatch-btn"
data-plugin="<?php echo (int)$w->plugin_id; ?>"
title="Beobachtung beenden">
<i class="fas fa-bell-slash"></i>
</button>
</li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<!-- Wunschliste (client-seitig aus localStorage) -->
<div class="wbf-profile-card wbf-plugin-watch-card" style="margin-top:20px;">
<div class="wbf-profile-card__header">
<i class="fas fa-heart"></i> Wunschliste
<span class="wbf-profile-card__count wbf-wishlist-count-badge">0</span>
</div>
<div id="wbf-wishlist-plugin-content">
<div class="wbf-profile-empty" style="text-align:center;padding:20px;">
<i class="fas fa-spinner fa-spin" style="color:#2a3a4a;font-size:1.5em;display:block;margin-bottom:8px;"></i>
Lade Wunschliste…
</div>
</div>
</div>
<script>
(function(){
var ajaxUrl = <?php echo wp_json_encode( $ajax_url ); ?>;
var nonce = <?php echo wp_json_encode( $vmcp_nonce ); ?>;
var archiveUrl = <?php echo wp_json_encode( $archive_url ); ?>;
/* ── Unwatch direkt aus dem Profil ── */
document.querySelectorAll('.wbf-watch-unwatch-btn').forEach(function(btn) {
btn.addEventListener('click', function() {
var pluginId = btn.dataset.plugin;
if (!confirm('Beobachtung für dieses Plugin wirklich beenden?')) return;
btn.disabled = true;
btn.innerHTML = '<i class="fas fa-spinner fa-spin"></i>';
var fd = new FormData();
fd.append('action', 'vmcp_toggle_watch');
fd.append('nonce', nonce);
fd.append('plugin_id', pluginId);
fetch(ajaxUrl, { method:'POST', body:fd })
.then(function(r){ return r.json(); })
.then(function(res){
if (res.success && !res.data.watching) {
var li = btn.closest('.wbf-watch-item');
if (li) {
li.style.opacity = '0';
li.style.transition = 'opacity .3s';
setTimeout(function(){ li.remove(); }, 300);
}
// Badge aktualisieren
var badge = document.getElementById('wbf-watch-count-badge');
if (badge) badge.textContent = Math.max(0, (parseInt(badge.textContent)||0)-1);
// Leerliste zeigen wenn keine mehr da
var list = document.getElementById('wbf-watch-list');
if (list && list.querySelectorAll('.wbf-watch-item').length <= 1) {
setTimeout(function(){
list.closest('.wbf-plugin-watch-card').querySelector('.wbf-profile-card__header').insertAdjacentHTML('afterend',
'<div class="wbf-profile-empty" style="text-align:center;padding:24px 16px;">' +
'<i class="fas fa-bell-slash" style="font-size:2.2em;color:#2a3a4a;margin-bottom:10px;display:block;"></i>' +
'<p style="margin:0 0 10px;color:#4a6a8a;">Du beobachtest noch kein Plugin.</p>' +
'<a href="'+archiveUrl+'" style="color:#00d4ff;font-weight:600;">Plugins entdecken →</a></div>'
);
if (list) list.remove();
}, 350);
}
} else {
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-bell-slash"></i>';
if (res.data && res.data.message) alert(res.data.message);
}
})
.catch(function(){
btn.disabled = false;
btn.innerHTML = '<i class="fas fa-bell-slash"></i>';
alert('Fehler beim Verbinden. Bitte Seite neu laden.');
});
});
});
/* ── Wunschliste aus localStorage laden ── */
var wishlistContent = document.getElementById('wbf-wishlist-plugin-content');
var wishlistBadge = document.querySelector('.wbf-wishlist-count-badge');
var favs = [];
try { favs = JSON.parse(localStorage.getItem('vmcp_favs') || '[]'); } catch(e){}
if (wishlistBadge) wishlistBadge.textContent = favs.length;
if (!favs || favs.length === 0) {
wishlistContent.innerHTML =
'<div class="wbf-profile-empty" style="text-align:center;padding:24px 16px;">' +
'<i class="fas fa-heart-crack" style="font-size:2.2em;color:#2a3a4a;margin-bottom:10px;display:block;"></i>' +
'<p style="margin:0 0 10px;color:#4a6a8a;">Deine Wunschliste ist leer.</p>' +
'<a href="' + archiveUrl + '" style="color:#00d4ff;font-weight:600;">Plugins entdecken →</a>' +
'</div>';
return;
}
/* Plugins via vmcp AJAX laden */
var fd2 = new FormData();
fd2.append('action', 'vmcp_wishlist_load');
fd2.append('nonce', nonce);
fd2.append('favs', JSON.stringify(favs));
fetch(ajaxUrl, { method:'POST', body:fd2 })
.then(function(r){ return r.json(); })
.then(function(res){
if (res.success && res.data && res.data.html) {
wishlistContent.innerHTML = res.data.html;
} else {
wishlistContent.innerHTML =
'<div class="wbf-profile-empty" style="padding:20px;text-align:center;">' +
'<p style="color:#4a6a8a;">Keine Plugins gefunden.</p></div>';
}
})
.catch(function(){
wishlistContent.innerHTML =
'<div class="wbf-profile-empty" style="padding:20px;text-align:center;">' +
'<p style="color:#4a6a8a;">Fehler beim Laden.</p></div>';
});
})();
</script>
<style>
.wbf-watch-list { list-style:none; margin:0; padding:12px; display:flex; flex-direction:column; gap:8px; }
.wbf-watch-item {
display:flex; align-items:center; gap:12px; padding:10px 12px;
background:rgba(255,255,255,.03); border:1px solid rgba(255,255,255,.06);
border-radius:10px; transition:border-color .15s, opacity .3s;
}
.wbf-watch-item:hover { border-color:rgba(0,212,255,.2); }
.wbf-watch-item__thumb img,
.wbf-watch-item__thumb { width:42px; height:42px; border-radius:8px; object-fit:cover; display:block; flex-shrink:0; }
.wbf-watch-item__initial {
width:42px; height:42px; border-radius:8px; flex-shrink:0;
background:rgba(0,212,255,.1); border:1px solid rgba(0,212,255,.2);
display:flex; align-items:center; justify-content:center;
font-size:18px; font-weight:800; color:#00d4ff;
}
.wbf-watch-item__body { flex:1; min-width:0; }
.wbf-watch-item__name { display:block; font-weight:700; color:#e0e6f0; text-decoration:none; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.wbf-watch-item__name:hover { color:#00d4ff; }
.wbf-watch-item__meta { display:flex; flex-wrap:wrap; gap:6px; margin-top:3px; font-size:12px; }
.wbf-watch-item__ver { color:#00d4ff; }
.wbf-watch-item__premium { color:#f5c542; }
.wbf-watch-item__since { color:#4a6a8a; }
.wbf-watch-unwatch-btn {
background:none; border:none; cursor:pointer; color:#3a4a5a;
font-size:15px; padding:6px; border-radius:6px; flex-shrink:0;
transition:color .15s, background .15s;
}
.wbf-watch-unwatch-btn:hover { color:#e11d48; background:rgba(225,29,72,.1); }
.wbf-plugin-watch-card .vmcp-grid { gap:10px; }
</style>
<?php
}
/* ══════════════════════════════════════════════════════════════
Benachrichtigung rendern
══════════════════════════════════════════════════════════════ */
add_filter( 'wbf_notification_html', function( $html, $notif ) {
if ( $notif->type !== 'plugin_update' ) return $html;
$plugin_id = (int) $notif->object_id;
$post = get_post( $plugin_id );
if ( ! $post ) return $html;
$title = esc_html( $post->post_title );
$link = esc_url( get_permalink( $plugin_id ) );
$version = esc_html( get_post_meta( $plugin_id, '_vmcp_version', true ) );
$thumb = get_the_post_thumbnail_url( $plugin_id, 'thumbnail' );
$time_ago = human_time_diff( strtotime($notif->created_at), current_time('timestamp') );
ob_start(); ?>
<div class="wbf-notif-item<?php echo $notif->is_read ? '' : ' wbf-notif-unread'; ?>"
data-id="<?php echo (int)$notif->id; ?>">
<div class="wbf-notif-icon wbf-notif-icon--plugin">
<?php if ($thumb): ?>
<img src="<?php echo esc_url($thumb); ?>" width="36" height="36"
style="border-radius:6px;object-fit:cover;display:block;" alt="">
<?php else: ?>
<i class="fas fa-puzzle-piece"></i>
<?php endif; ?>
</div>
<div class="wbf-notif-body">
<span class="wbf-notif-text">
<a href="<?php echo $link; ?>"><?php echo $title; ?></a>
wurde aktualisiert<?php echo $version ? ' auf <strong>v'.$version.'</strong>' : ''; ?>.
</span>
<span class="wbf-notif-time">vor <?php echo esc_html($time_ago); ?></span>
</div>
</div>
<?php return ob_get_clean();
}, 10, 2 );