diff --git a/.DS_Store b/.DS_Store index 46e025f..71808ec 100644 Binary files a/.DS_Store and b/.DS_Store differ diff --git a/admin/.DS_Store b/admin/.DS_Store index 0e2b8f3..7f05f8b 100644 Binary files a/admin/.DS_Store and b/admin/.DS_Store differ diff --git a/admin/css/admin-style.css b/admin/css/admin-style.css index 36ce707..03fa3fd 100644 --- a/admin/css/admin-style.css +++ b/admin/css/admin-style.css @@ -18,7 +18,7 @@ --igsp-gray: #6c757d; --igsp-light: #f8f9fa; --igsp-border: #e2e4e7; - --igsp-shadow: 0 2px 8px rgba(0,0,0,0.08); + --igsp-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); --igsp-radius: 8px; } @@ -414,8 +414,15 @@ } @keyframes igsp-progress-pulse { - 0%, 100% { opacity: 1; } - 50% { opacity: 0.7; } + + 0%, + 100% { + opacity: 1; + } + + 50% { + opacity: 0.7; + } } .igsp-progress-text { @@ -515,8 +522,13 @@ top: 0; } -.igsp-log-type { width: 100px; } -.igsp-log-date { width: 120px; } +.igsp-log-type { + width: 100px; +} + +.igsp-log-date { + width: 120px; +} .igsp-log-badge { display: inline-block; @@ -527,10 +539,25 @@ text-transform: uppercase; } -.igsp-log-success { background: rgba(40, 167, 69, 0.1); color: var(--igsp-success); } -.igsp-log-error { background: rgba(220, 53, 69, 0.1); color: var(--igsp-error); } -.igsp-log-warning { background: rgba(255, 193, 7, 0.1); color: #856404; } -.igsp-log-info { background: rgba(23, 162, 184, 0.1); color: var(--igsp-info); } +.igsp-log-success { + background: rgba(40, 167, 69, 0.1); + color: var(--igsp-success); +} + +.igsp-log-error { + background: rgba(220, 53, 69, 0.1); + color: var(--igsp-error); +} + +.igsp-log-warning { + background: rgba(255, 193, 7, 0.1); + color: #856404; +} + +.igsp-log-info { + background: rgba(23, 162, 184, 0.1); + color: var(--igsp-info); +} .igsp-no-logs { padding: 40px; @@ -614,12 +641,12 @@ .igsp-admin-wrap { grid-template-columns: 1fr; } - + .igsp-admin-sidebar { flex-direction: row; flex-wrap: wrap; } - + .igsp-sidebar-box { flex: 1; min-width: 250px; @@ -631,19 +658,456 @@ flex-wrap: wrap; padding: 10px; } - + .igsp-tab-link { flex: 1; justify-content: center; padding: 10px; font-size: 12px; } - + .igsp-tab-link .dashicons { display: none; } - + .igsp-layout-selector { grid-template-columns: repeat(2, 1fr); } } + +/* ============================================ + Posts Management Tab + ============================================ */ + +/* Posts Header */ +.igsp-posts-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 20px; + flex-wrap: wrap; + gap: 10px; +} + +.igsp-posts-header h2 { + margin: 0 !important; + padding: 0 !important; + border: none !important; +} + +.igsp-post-count { + font-weight: 400; + color: var(--igsp-gray); + font-size: 14px; +} + +/* Search */ +.igsp-search-wrapper { + display: flex; + gap: 5px; +} + +.igsp-search-input { + min-width: 220px; + padding: 6px 12px; + border: 1px solid var(--igsp-border); + border-radius: var(--igsp-radius); +} + +/* Posts Table */ +.igsp-posts-table-wrapper { + border: 1px solid var(--igsp-border); + border-radius: var(--igsp-radius); + overflow: hidden; +} + +.igsp-posts-table { + margin: 0 !important; + border: none !important; +} + +.igsp-posts-table th { + background: var(--igsp-light); + font-weight: 600; + font-size: 13px; + padding: 12px 15px; +} + +.igsp-posts-table td { + padding: 10px 15px; + vertical-align: middle; +} + +.igsp-col-thumb { + width: 70px; +} + +.igsp-col-type { + width: 80px; +} + +.igsp-col-status { + width: 80px; +} + +.igsp-col-link { + width: 50px; + text-align: center; +} + +.igsp-col-date { + width: 150px; +} + +.igsp-col-actions { + width: 100px; +} + +/* Post Thumbnail */ +.igsp-post-thumb { + width: 50px; + height: 50px; + object-fit: cover; + border-radius: 6px; + display: block; +} + +.igsp-post-thumb-placeholder { + width: 50px; + height: 50px; + background: var(--igsp-light); + border-radius: 6px; + display: flex; + align-items: center; + justify-content: center; + color: var(--igsp-gray); +} + +.igsp-post-thumb-placeholder .dashicons { + font-size: 24px; + width: 24px; + height: 24px; +} + +/* Caption */ +.igsp-caption-text { + font-size: 13px; + color: var(--igsp-dark); + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; +} + +/* Post Link */ +.igsp-post-link { + color: var(--igsp-primary); + text-decoration: none; +} + +.igsp-post-link:hover { + color: var(--igsp-primary-hover); +} + +.igsp-post-link .dashicons { + font-size: 18px; + width: 18px; + height: 18px; +} + +.igsp-no-link { + color: var(--igsp-gray); +} + +/* Type Badges */ +.igsp-type-badge { + display: inline-block; + padding: 3px 8px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; +} + +.igsp-type-synced { + background: rgba(23, 162, 184, 0.1); + color: var(--igsp-info); +} + +.igsp-type-manual { + background: rgba(225, 48, 108, 0.1); + color: var(--igsp-primary); +} + +/* Status Badges */ +.igsp-status-badge { + display: inline-block; + padding: 3px 8px; + border-radius: 3px; + font-size: 11px; + font-weight: 600; + text-transform: uppercase; +} + +.igsp-status-active { + background: rgba(40, 167, 69, 0.1); + color: var(--igsp-success); +} + +.igsp-status-inactive { + background: rgba(220, 53, 69, 0.1); + color: var(--igsp-error); +} + +/* Inactive Row */ +.igsp-post-inactive { + opacity: 0.6; +} + +.igsp-post-inactive:hover { + opacity: 1; +} + +/* Action Buttons */ +.igsp-action-buttons { + display: flex; + gap: 5px; +} + +.igsp-action-buttons .button { + padding: 2px 6px; + min-height: 28px; + display: flex; + align-items: center; + justify-content: center; +} + +.igsp-action-buttons .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + +.igsp-delete-post { + color: var(--igsp-error) !important; + border-color: var(--igsp-error) !important; +} + +.igsp-delete-post:hover { + background: var(--igsp-error) !important; + color: #fff !important; +} + +/* Post Date */ +.igsp-post-date { + font-size: 12px; + color: var(--igsp-gray); +} + +/* No Posts */ +.igsp-no-posts { + padding: 40px; + text-align: center; + color: var(--igsp-gray); + background: var(--igsp-light); + border-radius: var(--igsp-radius); +} + +/* ============================================ + Pagination + ============================================ */ +.igsp-pagination { + display: flex; + align-items: center; + gap: 5px; + margin-top: 20px; + flex-wrap: wrap; +} + +.igsp-pagination .button { + min-width: 36px; + text-align: center; +} + +.igsp-pagination-info { + margin-left: 15px; + font-size: 13px; + color: var(--igsp-gray); +} + +/* ============================================ + Manual Post Form + ============================================ */ +.igsp-manual-post-form { + background: var(--igsp-light); + border-radius: var(--igsp-radius); + padding: 25px; +} + +.igsp-manual-post-fields { + display: grid; + grid-template-columns: auto 1fr; + gap: 20px; + align-items: start; +} + +.igsp-manual-field { + display: flex; + flex-direction: column; + gap: 6px; +} + +.igsp-manual-field label { + font-weight: 600; + font-size: 13px; + color: var(--igsp-dark); +} + +.igsp-manual-field .required { + color: var(--igsp-error); +} + +.igsp-manual-image-field { + grid-row: span 4; +} + +/* Image Upload Area */ +.igsp-image-upload-area { + width: 200px; + height: 200px; + border: 2px dashed var(--igsp-border); + border-radius: var(--igsp-radius); + cursor: pointer; + position: relative; + overflow: hidden; + transition: border-color 0.2s; + background: #fff; +} + +.igsp-image-upload-area:hover { + border-color: var(--igsp-primary); +} + +.igsp-upload-placeholder { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + height: 100%; + gap: 8px; + color: var(--igsp-gray); +} + +.igsp-upload-placeholder .dashicons { + font-size: 40px; + width: 40px; + height: 40px; + color: var(--igsp-border); +} + +.igsp-upload-placeholder span:last-child { + font-size: 13px; + font-weight: 500; +} + +/* Select Image Button */ +#igsp-select-image-btn { + margin-top: 10px; + display: inline-flex; + align-items: center; + gap: 6px; + width: 200px; + justify-content: center; +} + +#igsp-select-image-btn .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + +/* Image Preview */ +.igsp-image-preview { + width: 100%; + height: 100%; + position: relative; +} + +.igsp-image-preview img { + width: 100%; + height: 100%; + object-fit: cover; +} + +.igsp-remove-image { + position: absolute; + top: 5px; + right: 5px; + background: rgba(220, 53, 69, 0.9); + color: #fff; + border: none; + border-radius: 50%; + width: 24px; + height: 24px; + display: flex; + align-items: center; + justify-content: center; + cursor: pointer; + padding: 0; + transition: background 0.2s; +} + +.igsp-remove-image:hover { + background: var(--igsp-error); +} + +.igsp-remove-image .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + +/* Manual Post Actions */ +.igsp-manual-post-actions { + margin-top: 20px; + display: flex; + align-items: center; + gap: 15px; +} + +.igsp-manual-post-actions .button { + display: flex; + align-items: center; + gap: 6px; +} + +.igsp-manual-post-actions .dashicons { + font-size: 16px; + width: 16px; + height: 16px; +} + +@media (max-width: 782px) { + .igsp-manual-post-fields { + grid-template-columns: 1fr; + } + + .igsp-manual-image-field { + grid-row: auto; + } + + .igsp-image-upload-area { + width: 100%; + height: 150px; + } + + .igsp-posts-header { + flex-direction: column; + align-items: flex-start; + } + + .igsp-col-date, + .igsp-col-type { + display: none; + } +} \ No newline at end of file diff --git a/admin/js/admin-script.js b/admin/js/admin-script.js index d470527..167cd26 100644 --- a/admin/js/admin-script.js +++ b/admin/js/admin-script.js @@ -25,18 +25,27 @@ this.initSyncButton(); this.initToolButtons(); this.initTabPersistence(); + this.initPostsTab(); + this.initManualPostForm(); }, /** * Initialize color pickers */ initColorPickers: function () { - $('.igsp-color-picker').wpColorPicker({ - change: function (event, ui) { - // Update live preview - IGSPAdmin.updatePreview(); - } - }); + if ($('.igsp-color-picker').length === 0) { + return; + } + try { + $('.igsp-color-picker').wpColorPicker({ + change: function (event, ui) { + // Update live preview + IGSPAdmin.updatePreview(); + } + }); + } catch (e) { + // Color picker not available on this tab + } }, /** @@ -233,6 +242,210 @@ }); }, + /** + * Initialize Posts Tab functionality + */ + initPostsTab: function () { + // Toggle post active/inactive + $(document).on('click', '.igsp-toggle-post', function () { + const $button = $(this); + const postId = $button.data('post-id'); + const $row = $button.closest('.igsp-post-row'); + + $button.prop('disabled', true); + + $.post(igspAdmin.ajaxUrl, { + action: 'igsp_toggle_post', + nonce: igspAdmin.nonce, + post_id: postId + }, function (response) { + if (response.success) { + const isActive = response.data.is_active; + const $icon = $button.find('.dashicons'); + const $badge = $row.find('.igsp-status-badge'); + + if (isActive) { + $row.removeClass('igsp-post-inactive'); + $icon.removeClass('dashicons-visibility').addClass('dashicons-hidden'); + $badge.removeClass('igsp-status-inactive').addClass('igsp-status-active').text('Aktiv'); + $button.attr('title', 'Deaktivieren'); + } else { + $row.addClass('igsp-post-inactive'); + $icon.removeClass('dashicons-hidden').addClass('dashicons-visibility'); + $badge.removeClass('igsp-status-active').addClass('igsp-status-inactive').text('Inaktiv'); + $button.attr('title', 'Aktivieren'); + } + } + $button.prop('disabled', false); + }).fail(function () { + $button.prop('disabled', false); + }); + }); + + // Delete post + $(document).on('click', '.igsp-delete-post', function () { + if (!confirm(igspAdmin.strings.confirmDeletePost)) { + return; + } + + const $button = $(this); + const postId = $button.data('post-id'); + const $row = $button.closest('.igsp-post-row'); + + $button.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(); + // Update count + const $count = $('.igsp-post-count'); + const currentCount = parseInt($count.text().replace(/\D/g, '')) || 0; + $count.text('(' + Math.max(0, currentCount - 1) + ')'); + }); + } else { + $button.prop('disabled', false); + } + }).fail(function () { + $button.prop('disabled', false); + }); + }); + }, + + /** + * Initialize Manual Post Form + */ + initManualPostForm: function () { + // Only init if the button exists on this page + if ($('#igsp-select-image-btn').length === 0) { + return; + } + + let mediaFrame = null; + let selectedAttachmentId = 0; + + // Open media library via button + $('#igsp-select-image-btn').on('click', function (e) { + e.preventDefault(); + e.stopPropagation(); + + // Check if wp.media is available + if (typeof wp === 'undefined' || typeof wp.media === 'undefined') { + alert('WordPress Media Library ist nicht verfügbar. Bitte lade die Seite neu.'); + return; + } + + // If media frame already exists, reopen it + if (mediaFrame) { + mediaFrame.open(); + return; + } + + // Create media frame + mediaFrame = wp.media({ + title: igspAdmin.strings.selectImage, + button: { + text: igspAdmin.strings.useImage + }, + multiple: false, + library: { + type: 'image' + } + }); + + // When image is selected + mediaFrame.on('select', function () { + const attachment = mediaFrame.state().get('selection').first().toJSON(); + + selectedAttachmentId = attachment.id; + $('#igsp-attachment-id').val(attachment.id); + + // Show preview + const 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(); + }); + + mediaFrame.open(); + }); + + // Remove image + $('#igsp-remove-image').on('click', function (e) { + e.stopPropagation(); + selectedAttachmentId = 0; + $('#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 () { + const $button = $(this); + const $result = $('#igsp-manual-post-result'); + const attachmentId = $('#igsp-attachment-id').val(); + + if (!attachmentId) { + $result.removeClass('success').addClass('error').text('Bitte wähle ein Bild aus.').show(); + return; + } + + $button.prop('disabled', true); + $result.hide(); + + // Convert datetime-local to MySQL format + let 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 + selectedAttachmentId = 0; + $('#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(''); + + // Reload after short delay to show new post in table + setTimeout(function () { + location.reload(); + }, 1500); + } else { + $result.addClass('error').text(response.data.message).show(); + } + + $button.prop('disabled', false); + }).fail(function () { + $result.addClass('error').text('Ein Fehler ist aufgetreten.').show(); + $button.prop('disabled', false); + }); + }); + }, + /** * Update sync status */ diff --git a/admin/views/tab-posts.php b/admin/views/tab-posts.php new file mode 100644 index 0000000..c8845ba --- /dev/null +++ b/admin/views/tab-posts.php @@ -0,0 +1,438 @@ +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); +?> + + +
+ +
+ ++ +
++ +
++ +
+ ++ +
+ +| + + | ++ + | ++ + | ++ + | ++ + | ++ + | ++ + | +
|---|---|---|---|---|---|---|
|
+
+
+
+
+
+ |
+ + + + + | ++ post_url)): ?> + + + + + — + + | ++ + + + + + + + + + | ++ + + + | ++ + + + | ++ + | +