feat(ui): add tab navigation, history tab with generated content list, single item delete, and update domain URLs
This commit is contained in:
+152
-14
@@ -1,12 +1,12 @@
|
||||
<?php
|
||||
/**
|
||||
* Plugin Name: DummyLab – Dummy Post & Content Generator
|
||||
* Plugin URI: https://apps.masbudikusuma.my.id/dummylab-wp
|
||||
* Plugin URI: https://apps.masbudi.my.id/dummylab-wp
|
||||
* Description: Advanced dummy content generator for WordPress development with safety controls and bulk purge features.
|
||||
* Version: 1.3.0
|
||||
* Version: 1.4.0
|
||||
* Author: masbudikusuma
|
||||
* Author URI: https://masbudi.my.id
|
||||
* Donate link: https://saweria.co/masbudikusuma
|
||||
* Donate link: https://donate.masbudi.my.id/dummylab-wp
|
||||
* Text Domain: dummylab
|
||||
* License: GPL-2.0+
|
||||
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
|
||||
@@ -32,8 +32,8 @@ class DummyLab {
|
||||
add_action('admin_init', [$this, 'handle_activation_redirect']);
|
||||
add_action('admin_post_dummylab_generate', [$this, 'handle_generate']);
|
||||
add_action('admin_post_dummylab_purge', [$this, 'handle_purge']);
|
||||
add_action('admin_post_dummylab_delete_single', [$this, 'handle_delete_single']);
|
||||
|
||||
// Filter untuk deskripsi dinamis (ID/EN) dan Link Donasi di halaman Plugin Admin
|
||||
add_filter('all_plugins', [$this, 'dynamic_plugin_description']);
|
||||
add_filter('plugin_row_meta', [$this, 'add_plugin_row_meta'], 10, 2);
|
||||
}
|
||||
@@ -52,7 +52,6 @@ class DummyLab {
|
||||
}
|
||||
}
|
||||
|
||||
// Mengubah deskripsi plugin di wp-admin/plugins.php sesuai bahasa situs (ID / EN)
|
||||
public function dynamic_plugin_description($all_plugins) {
|
||||
$plugin_file = plugin_basename(__FILE__);
|
||||
if (isset($all_plugins[$plugin_file])) {
|
||||
@@ -66,12 +65,11 @@ class DummyLab {
|
||||
return $all_plugins;
|
||||
}
|
||||
|
||||
// Menambahkan Link Donasi di sebelah "Visit plugin site"
|
||||
public function add_plugin_row_meta($links, $file) {
|
||||
if ($file === plugin_basename(__FILE__)) {
|
||||
$locale = get_locale();
|
||||
$donate_label = (strpos($locale, 'id') === 0) ? '☕ Donasi' : '☕ Donate';
|
||||
$links[] = '<a href="https://saweria.co/masbudikusuma" target="_blank" style="color: #b35900; font-weight: 600;">' . $donate_label . '</a>';
|
||||
$links[] = '<a href="https://donate.masbudi.my.id/dummylab-wp" target="_blank" style="color: #b35900; font-weight: 600;">' . $donate_label . '</a>';
|
||||
}
|
||||
return $links;
|
||||
}
|
||||
@@ -92,6 +90,7 @@ class DummyLab {
|
||||
}
|
||||
|
||||
$ui_lang = isset($_GET['ui_lang']) && $_GET['ui_lang'] === 'en' ? 'en' : 'id';
|
||||
$current_tab = isset($_GET['tab']) && $_GET['tab'] === 'history' ? 'history' : 'generator';
|
||||
$users = get_users(['fields' => ['ID', 'display_name']]);
|
||||
|
||||
$query = new WP_Query([
|
||||
@@ -108,7 +107,7 @@ class DummyLab {
|
||||
?>
|
||||
<style>
|
||||
.dummylab-wrap { max-width: 1200px; margin: 20px 20px 0 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; }
|
||||
.dummylab-header { background: #fff; border: 1px solid #c3c4c7; border-radius: 8px; padding: 20px 24px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 1px 3px rgba(0,0,0,0.04); margin-bottom: 24px; }
|
||||
.dummylab-header { background: #fff; border: 1px solid #c3c4c7; border-radius: 8px; padding: 20px 24px; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 1px 3px rgba(0,0,0,0.04); margin-bottom: 20px; }
|
||||
.dummylab-header h1 { margin: 0 0 6px 0; font-size: 22px; font-weight: 600; color: #1d2327; display: flex; align-items: center; gap: 8px; }
|
||||
.dummylab-header p { margin: 0; color: #646970; font-size: 13px; }
|
||||
|
||||
@@ -116,6 +115,12 @@ class DummyLab {
|
||||
.dummylab-lang-btn { text-decoration: none; padding: 5px 14px; border-radius: 16px; font-size: 12px; font-weight: 600; color: #50575e; transition: all 0.2s ease; }
|
||||
.dummylab-lang-btn.active { background: #2271b1; color: #fff; box-shadow: 0 1px 2px rgba(0,0,0,0.1); }
|
||||
|
||||
/* Modern Tabs */
|
||||
.dummylab-tabs { display: flex; gap: 8px; margin-bottom: 20px; border-bottom: 2px solid #e2e8f0; }
|
||||
.dummylab-tab-item { padding: 10px 18px; text-decoration: none; font-weight: 600; color: #646970; border-bottom: 2px solid transparent; margin-bottom: -2px; font-size: 14px; transition: all 0.2s ease; display: flex; align-items: center; gap: 8px; }
|
||||
.dummylab-tab-item:hover { color: #2271b1; }
|
||||
.dummylab-tab-item.active { color: #2271b1; border-bottom-color: #2271b1; }
|
||||
|
||||
.dummylab-container { display: flex; gap: 24px; align-items: flex-start; }
|
||||
.dummylab-main-card { flex: 2; background: #fff; border: 1px solid #c3c4c7; border-radius: 8px; padding: 24px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); min-width: 550px; }
|
||||
.dummylab-sidebar { flex: 1; display: flex; flex-direction: column; gap: 20px; min-width: 320px; }
|
||||
@@ -164,17 +169,28 @@ class DummyLab {
|
||||
</div>
|
||||
|
||||
<div class="dummylab-wrap">
|
||||
<!-- Header Banner -->
|
||||
<div class="dummylab-header">
|
||||
<div>
|
||||
<h1>🧪 DummyLab <span style="font-size: 14px; font-weight: 400; color: #646970;">v1.3.0</span></h1>
|
||||
<p><?php echo $t['created_by']; ?> <a href="https://masbudi.my.id" target="_blank" style="text-decoration: none; font-weight: 600; color: #2271b1;">masbudikusuma</a> • <a href="https://apps.masbudikusuma.my.id/dummylab-wp" target="_blank" style="text-decoration: none; color: #2271b1;"><?php echo $t['plugin_doc']; ?></a> • <a href="https://saweria.co/masbudikusuma" target="_blank" style="text-decoration: none; font-weight: 600; color: #b35900;">☕ <?php echo $t['link_donate']; ?></a></p>
|
||||
<h1>🧪 DummyLab <span style="font-size: 14px; font-weight: 400; color: #646970;">v1.4.0</span></h1>
|
||||
<p><?php echo $t['created_by']; ?> <a href="https://masbudi.my.id" target="_blank" style="text-decoration: none; font-weight: 600; color: #2271b1;">masbudikusuma</a> • <a href="https://apps.masbudi.my.id/dummylab-wp" target="_blank" style="text-decoration: none; color: #2271b1;"><?php echo $t['plugin_doc']; ?></a> • <a href="https://donate.masbudi.my.id/dummylab-wp" target="_blank" style="text-decoration: none; font-weight: 600; color: #b35900;">☕ <?php echo $t['link_donate']; ?></a></p>
|
||||
</div>
|
||||
<div class="dummylab-lang-switch">
|
||||
<a href="<?php echo esc_url(add_query_arg('ui_lang', 'id')); ?>" class="dummylab-lang-btn <?php echo $ui_lang === 'id' ? 'active' : ''; ?>">🇮🇩 ID</a>
|
||||
<a href="<?php echo esc_url(add_query_arg('ui_lang', 'en')); ?>" class="dummylab-lang-btn <?php echo $ui_lang === 'en' ? 'active' : ''; ?>">🇬🇧 EN</a>
|
||||
<a href="<?php echo esc_url(add_query_arg(['ui_lang' => 'id', 'tab' => $current_tab])); ?>" class="dummylab-lang-btn <?php echo $ui_lang === 'id' ? 'active' : ''; ?>">🇮🇩 ID</a>
|
||||
<a href="<?php echo esc_url(add_query_arg(['ui_lang' => 'en', 'tab' => $current_tab])); ?>" class="dummylab-lang-btn <?php echo $ui_lang === 'en' ? 'active' : ''; ?>">🇬🇧 EN</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Navigation Tabs -->
|
||||
<div class="dummylab-tabs">
|
||||
<a href="<?php echo esc_url(add_query_arg(['tab' => 'generator', 'ui_lang' => $ui_lang])); ?>" class="dummylab-tab-item <?php echo $current_tab === 'generator' ? 'active' : ''; ?>">
|
||||
🚀 <?php echo $t['tab_generator']; ?>
|
||||
</a>
|
||||
<a href="<?php echo esc_url(add_query_arg(['tab' => 'history', 'ui_lang' => $ui_lang])); ?>" class="dummylab-tab-item <?php echo $current_tab === 'history' ? 'active' : ''; ?>">
|
||||
📜 <?php echo $t['tab_history']; ?> (<?php echo esc_html($dummy_count); ?>)
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<?php if (isset($_GET['status'])): ?>
|
||||
<div class="notice notice-success is-dismissible" style="border-radius: 6px; margin-bottom: 20px; padding: 12px 16px;">
|
||||
<p style="font-size: 14px; margin: 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
|
||||
@@ -188,12 +204,16 @@ class DummyLab {
|
||||
echo '<a href="' . esc_url($target_url) . '" class="button button-secondary" style="font-weight: 600; text-decoration: none;">' . esc_html($t['btn_view_list']) . ' ' . esc_html($type_label) . ' →</a>';
|
||||
} elseif ($_GET['status'] === 'purged') {
|
||||
echo '<span>🧹 <strong>' . esc_html(intval($_GET['count'])) . '</strong> ' . esc_html($t['msg_purged']) . '</span>';
|
||||
} elseif ($_GET['status'] === 'deleted_single') {
|
||||
echo '<span>🗑️ ' . esc_html($t['msg_deleted_single']) . '</span>';
|
||||
}
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($current_tab === 'generator'): ?>
|
||||
<!-- GENERATOR TAB CONTENT -->
|
||||
<div class="dummylab-container">
|
||||
<div class="dummylab-main-card">
|
||||
<form id="dummylab-generate-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
|
||||
@@ -331,6 +351,84 @@ class DummyLab {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php else: ?>
|
||||
<!-- HISTORY TAB CONTENT -->
|
||||
<div class="dummylab-main-card" style="min-width: 100%;">
|
||||
<h2>📜 <?php echo $t['history_title']; ?></h2>
|
||||
<p style="color: #646970; margin-bottom: 20px;"><?php echo $t['history_desc']; ?></p>
|
||||
|
||||
<?php
|
||||
$history_query = new WP_Query([
|
||||
'post_type' => ['post', 'page'],
|
||||
'posts_per_page' => 50,
|
||||
'meta_key' => $this->meta_key,
|
||||
'meta_value' => '1',
|
||||
'post_status' => 'any',
|
||||
]);
|
||||
?>
|
||||
|
||||
<?php if ($history_query->have_posts()): ?>
|
||||
<table class="wp-list-table widefat fixed striped table-view-list" style="border-radius: 6px; overflow: hidden; border: 1px solid #c3c4c7;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="font-weight: 600; width: 35%;"><?php echo $t['th_title']; ?></th>
|
||||
<th style="font-weight: 600; width: 12%;"><?php echo $t['th_type']; ?></th>
|
||||
<th style="font-weight: 600; width: 15%;"><?php echo $t['th_status']; ?></th>
|
||||
<th style="font-weight: 600; width: 15%;"><?php echo $t['th_author']; ?></th>
|
||||
<th style="font-weight: 600; width: 13%;"><?php echo $t['th_date']; ?></th>
|
||||
<th style="font-weight: 600; width: 10%; text-align: right;"><?php echo $t['th_action']; ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php while ($history_query->have_posts()): $history_query->the_post();
|
||||
$item_id = get_the_ID();
|
||||
$item_type = get_post_type($item_id);
|
||||
$edit_link = get_edit_post_link($item_id);
|
||||
$view_link = get_permalink($item_id);
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<strong><a href="<?php echo esc_url($edit_link); ?>" target="_blank"><?php the_title(); ?></a></strong>
|
||||
<?php if (has_post_thumbnail($item_id)): ?>
|
||||
<span style="font-size: 11px; background: #e0f2fe; color: #0369a1; padding: 2px 6px; border-radius: 4px; margin-left: 6px;">🖼️ Image</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<span style="text-transform: capitalize; font-weight: 600; color: #475569;">
|
||||
<?php echo esc_html($item_type); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span style="display: inline-block; padding: 2px 8px; border-radius: 12px; font-size: 11px; font-weight: 600; background: #f1f5f9; color: #334155;">
|
||||
<?php echo esc_html(get_post_status($item_id)); ?>
|
||||
</span>
|
||||
</td>
|
||||
<td><?php the_author(); ?></td>
|
||||
<td><?php echo get_the_date('d M Y H:i'); ?></td>
|
||||
<td style="text-align: right;">
|
||||
<div style="display: flex; gap: 8px; justify-content: flex-end; align-items: center;">
|
||||
<a href="<?php echo esc_url($view_link); ?>" target="_blank" title="View" style="text-decoration: none;">👁️</a>
|
||||
<a href="<?php echo esc_url($edit_link); ?>" target="_blank" title="Edit" style="text-decoration: none;">✏️</a>
|
||||
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>" style="display: inline;" onsubmit="return confirm('Hapus item dummy ini?');">
|
||||
<?php wp_nonce_field('dummylab_delete_single_action', 'dummylab_nonce'); ?>
|
||||
<input type="hidden" name="action" value="dummylab_delete_single">
|
||||
<input type="hidden" name="post_id" value="<?php echo esc_attr($item_id); ?>">
|
||||
<input type="hidden" name="ui_lang" value="<?php echo esc_attr($ui_lang); ?>">
|
||||
<button type="submit" style="background: none; border: none; cursor: pointer; padding: 0;" title="Delete">🗑️</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endwhile; wp_reset_postdata(); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php else: ?>
|
||||
<div style="padding: 40px; text-align: center; background: #f8fafc; border-radius: 6px; border: 1px dashed #cbd5e1;">
|
||||
<p style="font-size: 16px; color: #646970; margin: 0;"><?php echo $t['empty_history']; ?></p>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
@@ -360,10 +458,13 @@ class DummyLab {
|
||||
'created_by' => 'Created by',
|
||||
'plugin_doc' => 'Plugin Documentation',
|
||||
'link_donate' => 'Donate Support',
|
||||
'tab_generator' => 'Generator',
|
||||
'tab_history' => 'Generated History',
|
||||
'msg_generated' => 'dummy item(s) generated successfully!',
|
||||
'check_msg' => 'Please check your %s section.',
|
||||
'btn_view_list' => 'View List of',
|
||||
'msg_purged' => 'dummy items deleted successfully!',
|
||||
'msg_deleted_single' => 'Dummy item deleted successfully.',
|
||||
'loading_title' => 'Generating dummy content...',
|
||||
'loading_subtitle' => 'Please wait a few moments while we create your test data and images.',
|
||||
'sec_general' => 'General Settings',
|
||||
@@ -414,6 +515,15 @@ class DummyLab {
|
||||
'safety_item1' => 'All dummy posts tracked via unique metadata key.',
|
||||
'safety_item2' => 'Clean purge removes featured images from Media Library.',
|
||||
'safety_item3' => 'Safe for staging and local theme testing.',
|
||||
'history_title' => 'Generated Dummy Content List',
|
||||
'history_desc' => 'List of all posts and pages currently generated by DummyLab.',
|
||||
'th_title' => 'Title',
|
||||
'th_type' => 'Type',
|
||||
'th_status' => 'Status',
|
||||
'th_author' => 'Author',
|
||||
'th_date' => 'Date',
|
||||
'th_action' => 'Actions',
|
||||
'empty_history' => 'No dummy content generated yet.',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -421,10 +531,13 @@ class DummyLab {
|
||||
'created_by' => 'Dibuat oleh',
|
||||
'plugin_doc' => 'Dokumentasi Plugin',
|
||||
'link_donate' => 'Dukung Donasi',
|
||||
'tab_generator' => 'Generator',
|
||||
'tab_history' => 'Riwayat Konten',
|
||||
'msg_generated' => 'konten dummy berhasil dibuat!',
|
||||
'check_msg' => 'Silakan cek daftar %s Anda.',
|
||||
'btn_view_list' => 'Lihat Daftar',
|
||||
'msg_purged' => 'data dummy berhasil dibersihkan!',
|
||||
'msg_deleted_single' => 'Item dummy berhasil dihapus.',
|
||||
'loading_title' => 'Sedang membuat konten dummy...',
|
||||
'loading_subtitle' => 'Mohon tunggu beberapa saat. Server sedang mengunduh gambar dan membuat data artikel.',
|
||||
'sec_general' => 'Pengaturan Utama',
|
||||
@@ -475,6 +588,15 @@ class DummyLab {
|
||||
'safety_item1' => 'Setiap postingan dummy dilindungi metadata internal unik.',
|
||||
'safety_item2' => 'Fitur Purge juga membersihkan berkas gambar dari Media Library.',
|
||||
'safety_item3' => 'Aman digunakan pada lingkungan staging maupun lokal.',
|
||||
'history_title' => 'Daftar Konten Dummy Dihasilkan',
|
||||
'history_desc' => 'Daftar seluruh artikel dan halaman dummy yang aktif dibuat oleh DummyLab.',
|
||||
'th_title' => 'Judul',
|
||||
'th_type' => 'Tipe',
|
||||
'th_status' => 'Status',
|
||||
'th_author' => 'Penulis',
|
||||
'th_date' => 'Tanggal',
|
||||
'th_action' => 'Aksi',
|
||||
'empty_history' => 'Belum ada konten dummy yang dibuat.',
|
||||
];
|
||||
}
|
||||
|
||||
@@ -595,7 +717,23 @@ class DummyLab {
|
||||
}
|
||||
}
|
||||
|
||||
wp_redirect(admin_url('tools.php?page=dummylab&ui_lang=' . $ui_lang . '&status=generated&count=' . $count . '&type=' . $post_type));
|
||||
wp_redirect(admin_url('tools.php?page=dummylab&tab=generator&ui_lang=' . $ui_lang . '&status=generated&count=' . $count . '&type=' . $post_type));
|
||||
exit;
|
||||
}
|
||||
|
||||
public function handle_delete_single() {
|
||||
if (!current_user_can('manage_options') || !check_admin_referer('dummylab_delete_single_action', 'dummylab_nonce')) {
|
||||
wp_die('Akses ditolak.');
|
||||
}
|
||||
|
||||
$post_id = isset($_POST['post_id']) ? intval($_POST['post_id']) : 0;
|
||||
$ui_lang = isset($_POST['ui_lang']) ? sanitize_text_field($_POST['ui_lang']) : 'id';
|
||||
|
||||
if ($post_id > 0) {
|
||||
wp_delete_post($post_id, true);
|
||||
}
|
||||
|
||||
wp_redirect(admin_url('tools.php?page=dummylab&tab=history&ui_lang=' . $ui_lang . '&status=deleted_single'));
|
||||
exit;
|
||||
}
|
||||
|
||||
@@ -624,7 +762,7 @@ class DummyLab {
|
||||
}
|
||||
}
|
||||
|
||||
wp_redirect(admin_url('tools.php?page=dummylab&ui_lang=' . $ui_lang . '&status=purged&count=' . $purged_count));
|
||||
wp_redirect(admin_url('tools.php?page=dummylab&tab=generator&ui_lang=' . $ui_lang . '&status=purged&count=' . $purged_count));
|
||||
exit;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user