Files
Instagram-Gallery-Sync-Pro/admin/views/tab-posts.php

438 lines
20 KiB
PHP

<?php
/**
* Posts Management Tab
*
* @package Instagram_Gallery_Sync_Pro
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
$database = new IGSP_Database();
$image_handler = new IGSP_Image_Handler();
// Pagination
$per_page = 20;
$current_page = isset($_GET['paged']) ? absint($_GET['paged']) : 1;
$search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
$offset = ($current_page - 1) * $per_page;
// Get posts
$total_posts = $database->count_posts_filtered(array(
'active' => null,
'search' => $search,
));
$posts = $database->get_posts(array(
'limit' => $per_page,
'offset' => $offset,
'order' => 'newest',
'active' => false, // Show all posts (active + inactive)
'search' => $search,
));
$total_pages = ceil($total_posts / $per_page);
?>
<!-- Manual Post Form -->
<div class="igsp-section">
<h2>
<?php esc_html_e('Post manuell hinzufügen', 'instagram-gallery-sync-pro'); ?>
</h2>
<p class="description">
<?php esc_html_e('Füge manuell ein Bild/Post hinzu, z.B. wenn Instagram ein Rate-Limit verhängt hat.', 'instagram-gallery-sync-pro'); ?>
</p>
<div class="igsp-manual-post-form" id="igsp-manual-post-form">
<div class="igsp-manual-post-fields">
<div class="igsp-manual-field igsp-manual-image-field">
<label>
<?php esc_html_e('Bild', 'instagram-gallery-sync-pro'); ?> <span class="required">*</span>
</label>
<div class="igsp-image-upload-area" id="igsp-image-upload-area">
<div class="igsp-image-preview" id="igsp-image-preview" style="display: none;">
<img src="" alt="" id="igsp-preview-img">
<button type="button" class="igsp-remove-image" id="igsp-remove-image"
title="<?php esc_attr_e('Bild entfernen', 'instagram-gallery-sync-pro'); ?>">
<span class="dashicons dashicons-no-alt"></span>
</button>
</div>
<div class="igsp-upload-placeholder" id="igsp-upload-placeholder">
<span class="dashicons dashicons-format-image"></span>
<span><?php esc_html_e('Klicke auf den Button unten', 'instagram-gallery-sync-pro'); ?></span>
</div>
<input type="hidden" id="igsp-attachment-id" value="">
</div>
<button type="button" class="button" id="igsp-select-image-btn">
<span class="dashicons dashicons-format-image"></span>
<?php esc_html_e('Bild auswählen', 'instagram-gallery-sync-pro'); ?>
</button>
</div>
<div class="igsp-manual-field">
<label for="igsp-manual-url">
<?php esc_html_e('Instagram URL', 'instagram-gallery-sync-pro'); ?>
</label>
<input type="url" id="igsp-manual-url" placeholder="https://www.instagram.com/p/..."
class="regular-text">
<p class="description">
<?php esc_html_e('Link zum Instagram-Post (optional).', 'instagram-gallery-sync-pro'); ?>
</p>
</div>
<div class="igsp-manual-field">
<label for="igsp-manual-caption">
<?php esc_html_e('Caption', 'instagram-gallery-sync-pro'); ?>
</label>
<textarea id="igsp-manual-caption" rows="3" class="large-text"
placeholder="<?php esc_attr_e('Beschreibung des Posts...', 'instagram-gallery-sync-pro'); ?>"></textarea>
</div>
<div class="igsp-manual-field">
<label for="igsp-manual-date">
<?php esc_html_e('Datum', 'instagram-gallery-sync-pro'); ?>
</label>
<input type="datetime-local" id="igsp-manual-date" class="regular-text">
<p class="description">
<?php esc_html_e('Veröffentlichungsdatum (optional, Standard: jetzt).', 'instagram-gallery-sync-pro'); ?>
</p>
</div>
</div>
<div class="igsp-manual-post-actions">
<button type="button" id="igsp-add-manual-post" class="button button-primary">
<span class="dashicons dashicons-plus-alt2"></span>
<?php esc_html_e('Post hinzufügen', 'instagram-gallery-sync-pro'); ?>
</button>
<div id="igsp-manual-post-result" class="igsp-sync-result" style="display: none;"></div>
</div>
</div>
</div>
<!-- Posts Table -->
<div class="igsp-section">
<div class="igsp-posts-header">
<h2>
<?php esc_html_e('Alle Posts', 'instagram-gallery-sync-pro'); ?>
<span class="igsp-post-count">(
<?php echo esc_html($total_posts); ?>)
</span>
</h2>
<form method="get" class="igsp-search-form">
<input type="hidden" name="page" value="<?php echo esc_attr(IGSP_Admin::PAGE_SLUG); ?>">
<input type="hidden" name="tab" value="posts">
<div class="igsp-search-wrapper">
<input type="search" name="s" value="<?php echo esc_attr($search); ?>"
placeholder="<?php esc_attr_e('Posts durchsuchen...', 'instagram-gallery-sync-pro'); ?>"
class="igsp-search-input">
<button type="submit" class="button">
<span class="dashicons dashicons-search"></span>
</button>
</div>
</form>
</div>
<?php if (empty($posts)): ?>
<div class="igsp-no-posts">
<?php if (!empty($search)): ?>
<p>
<?php printf(esc_html__('Keine Posts gefunden für "%s".', 'instagram-gallery-sync-pro'), esc_html($search)); ?>
</p>
<?php else: ?>
<p>
<?php esc_html_e('Noch keine Posts vorhanden. Synchronisiere dein Instagram-Konto oder füge manuell Posts hinzu.', 'instagram-gallery-sync-pro'); ?>
</p>
<?php endif; ?>
</div>
<?php else: ?>
<div class="igsp-posts-table-wrapper">
<table class="igsp-posts-table widefat striped">
<thead>
<tr>
<th class="igsp-col-thumb">
<?php esc_html_e('Bild', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-caption">
<?php esc_html_e('Caption', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-link">
<?php esc_html_e('Link', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-type">
<?php esc_html_e('Typ', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-status">
<?php esc_html_e('Status', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-date">
<?php esc_html_e('Datum', 'instagram-gallery-sync-pro'); ?>
</th>
<th class="igsp-col-actions">
<?php esc_html_e('Aktionen', 'instagram-gallery-sync-pro'); ?>
</th>
</tr>
</thead>
<tbody>
<?php foreach ($posts as $post):
// Get image URL
$thumb_url = '';
if (!empty($post->image_thumbnail_path)) {
$thumb_url = $image_handler->get_image_url($post->image_thumbnail_path);
} elseif (!empty($post->image_local_path)) {
$thumb_url = $image_handler->get_image_url($post->image_local_path);
}
$is_manual = !empty($post->is_manual);
$is_active = !empty($post->is_active);
$caption_short = !empty($post->caption) ? wp_trim_words($post->caption, 12, '...') : '—';
$posted_date = !empty($post->posted_at) ? date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($post->posted_at)) : '—';
?>
<tr class="igsp-post-row <?php echo !$is_active ? 'igsp-post-inactive' : ''; ?>"
data-post-id="<?php echo esc_attr($post->id); ?>">
<td class="igsp-col-thumb">
<?php if ($thumb_url): ?>
<img src="<?php echo esc_url($thumb_url); ?>" alt="" class="igsp-post-thumb">
<?php else: ?>
<div class="igsp-post-thumb-placeholder">
<span class="dashicons dashicons-format-image"></span>
</div>
<?php endif; ?>
</td>
<td class="igsp-col-caption">
<span class="igsp-caption-text">
<?php echo esc_html($caption_short); ?>
</span>
</td>
<td class="igsp-col-link">
<?php if (!empty($post->post_url)): ?>
<a href="<?php echo esc_url($post->post_url); ?>" target="_blank" rel="noopener noreferrer"
class="igsp-post-link" title="<?php echo esc_attr($post->post_url); ?>">
<span class="dashicons dashicons-external"></span>
</a>
<?php else: ?>
<span class="igsp-no-link">—</span>
<?php endif; ?>
</td>
<td class="igsp-col-type">
<?php if ($is_manual): ?>
<span class="igsp-type-badge igsp-type-manual">
<?php esc_html_e('Manual', 'instagram-gallery-sync-pro'); ?>
</span>
<?php else: ?>
<span class="igsp-type-badge igsp-type-synced">
<?php esc_html_e('Synced', 'instagram-gallery-sync-pro'); ?>
</span>
<?php endif; ?>
</td>
<td class="igsp-col-status">
<span
class="igsp-status-badge <?php echo $is_active ? 'igsp-status-active' : 'igsp-status-inactive'; ?>">
<?php echo $is_active ? esc_html__('Aktiv', 'instagram-gallery-sync-pro') : esc_html__('Inaktiv', 'instagram-gallery-sync-pro'); ?>
</span>
</td>
<td class="igsp-col-date">
<span class="igsp-post-date">
<?php echo esc_html($posted_date); ?>
</span>
</td>
<td class="igsp-col-actions">
<div class="igsp-action-buttons">
<button type="button" class="button button-small igsp-toggle-post"
data-post-id="<?php echo esc_attr($post->id); ?>"
title="<?php echo $is_active ? esc_attr__('Deaktivieren', 'instagram-gallery-sync-pro') : esc_attr__('Aktivieren', 'instagram-gallery-sync-pro'); ?>">
<span
class="dashicons <?php echo $is_active ? 'dashicons-hidden' : 'dashicons-visibility'; ?>"></span>
</button>
<button type="button" class="button button-small igsp-delete-post"
data-post-id="<?php echo esc_attr($post->id); ?>"
title="<?php esc_attr_e('Löschen', 'instagram-gallery-sync-pro'); ?>">
<span class="dashicons dashicons-trash"></span>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php if ($total_pages > 1): ?>
<div class="igsp-pagination">
<?php
$base_url = admin_url('admin.php?page=' . IGSP_Admin::PAGE_SLUG . '&tab=posts');
if (!empty($search)) {
$base_url .= '&s=' . urlencode($search);
}
for ($i = 1; $i <= $total_pages; $i++):
$page_url = $base_url . '&paged=' . $i;
?>
<a href="<?php echo esc_url($page_url); ?>"
class="button <?php echo $current_page === $i ? 'button-primary' : ''; ?>">
<?php echo esc_html($i); ?>
</a>
<?php endfor; ?>
<span class="igsp-pagination-info">
<?php printf(
esc_html__('Seite %1$d von %2$d (%3$d Posts)', 'instagram-gallery-sync-pro'),
$current_page,
$total_pages,
$total_posts
); ?>
</span>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
<script type="text/javascript">
jQuery(document).ready(function ($) {
// === Media Library Image Upload ===
var igspMediaFrame = null;
$('#igsp-select-image-btn').on('click', function (e) {
e.preventDefault();
if (typeof wp === 'undefined' || typeof wp.media !== 'function') {
alert('WordPress Media Library konnte nicht geladen werden. Bitte lade die Seite neu.');
return;
}
if (igspMediaFrame) {
igspMediaFrame.open();
return;
}
igspMediaFrame = wp.media({
title: '<?php echo esc_js(__('Bild auswählen', 'instagram-gallery-sync-pro')); ?>',
button: { text: '<?php echo esc_js(__('Bild verwenden', 'instagram-gallery-sync-pro')); ?>' },
multiple: false,
library: { type: 'image' }
});
igspMediaFrame.on('select', function () {
var attachment = igspMediaFrame.state().get('selection').first().toJSON();
$('#igsp-attachment-id').val(attachment.id);
var previewUrl = (attachment.sizes && attachment.sizes.medium) ? attachment.sizes.medium.url : attachment.url;
$('#igsp-preview-img').attr('src', previewUrl);
$('#igsp-image-preview').show();
$('#igsp-upload-placeholder').hide();
});
igspMediaFrame.open();
});
// Remove image
$('#igsp-remove-image').on('click', function (e) {
e.preventDefault();
e.stopPropagation();
$('#igsp-attachment-id').val('');
$('#igsp-preview-img').attr('src', '');
$('#igsp-image-preview').hide();
$('#igsp-upload-placeholder').show();
});
// === Submit Manual Post ===
$('#igsp-add-manual-post').on('click', function () {
var $btn = $(this);
var $result = $('#igsp-manual-post-result');
var attachmentId = $('#igsp-attachment-id').val();
if (!attachmentId) {
$result.removeClass('success').addClass('error').text('Bitte wähle ein Bild aus.').show();
return;
}
$btn.prop('disabled', true);
$result.hide();
var postedAt = $('#igsp-manual-date').val();
if (postedAt) {
postedAt = postedAt.replace('T', ' ') + ':00';
}
$.post(igspAdmin.ajaxUrl, {
action: 'igsp_add_manual_post',
nonce: igspAdmin.nonce,
attachment_id: attachmentId,
post_url: $('#igsp-manual-url').val(),
caption: $('#igsp-manual-caption').val(),
posted_at: postedAt
}, function (response) {
$result.removeClass('success error');
if (response.success) {
$result.addClass('success').text(response.data.message).show();
// Reset form
$('#igsp-attachment-id').val('');
$('#igsp-preview-img').attr('src', '');
$('#igsp-image-preview').hide();
$('#igsp-upload-placeholder').show();
$('#igsp-manual-url').val('');
$('#igsp-manual-caption').val('');
$('#igsp-manual-date').val('');
setTimeout(function () { location.reload(); }, 1500);
} else {
$result.addClass('error').text(response.data.message).show();
}
$btn.prop('disabled', false);
}).fail(function () {
$result.addClass('error').text('Ein Fehler ist aufgetreten.').show();
$btn.prop('disabled', false);
});
});
// === Toggle Post Status ===
$(document).on('click', '.igsp-toggle-post', function () {
var $btn = $(this);
var postId = $btn.data('post-id');
var $row = $btn.closest('.igsp-post-row');
$btn.prop('disabled', true);
$.post(igspAdmin.ajaxUrl, {
action: 'igsp_toggle_post',
nonce: igspAdmin.nonce,
post_id: postId
}, function (response) {
if (response.success) {
var $icon = $btn.find('.dashicons');
var $badge = $row.find('.igsp-status-badge');
if (response.data.is_active) {
$row.removeClass('igsp-post-inactive');
$icon.removeClass('dashicons-visibility').addClass('dashicons-hidden');
$badge.removeClass('igsp-status-inactive').addClass('igsp-status-active').text('Aktiv');
} else {
$row.addClass('igsp-post-inactive');
$icon.removeClass('dashicons-hidden').addClass('dashicons-visibility');
$badge.removeClass('igsp-status-active').addClass('igsp-status-inactive').text('Inaktiv');
}
}
$btn.prop('disabled', false);
}).fail(function () { $btn.prop('disabled', false); });
});
// === Delete Post ===
$(document).on('click', '.igsp-delete-post', function () {
if (!confirm('Diesen Post wirklich löschen?')) return;
var $btn = $(this);
var postId = $btn.data('post-id');
var $row = $btn.closest('.igsp-post-row');
$btn.prop('disabled', true);
$.post(igspAdmin.ajaxUrl, {
action: 'igsp_delete_post',
nonce: igspAdmin.nonce,
post_id: postId
}, function (response) {
if (response.success) {
$row.fadeOut(300, function () { $(this).remove(); });
} else {
$btn.prop('disabled', false);
}
}).fail(function () { $btn.prop('disabled', false); });
});
});
</script>