Compare commits

...
11 Commits
Author SHA1 Message Date
idtemankampus-creator 42204421ff docs: update bilingual README (EN/ID) and embed capture.png preview 2026-09-18 13:42:55 +07:00
idtemankampus-creator 9f39e5fe80 docs: add plain text README.md and push to Gitea main branch 2026-09-18 13:28:06 +07:00
idtemankampus-creator 359b4bf37c fix(ui): align action link with Deactivate, rename to Generator, and clean up row meta 2026-09-18 13:14:08 +07:00
idtemankampus-creator 7269718665 feat(ui): add dashboard shortcut to plugin action links and row meta 2026-09-18 13:10:04 +07:00
idtemankampus-creator cabda4a9da feat(media): add local offline SVG generator option alongside Picsum Online 2026-09-18 08:47:01 +07:00
idtemankampus-creator 6159c8fd15 feat(ui): add tab navigation, history tab with generated content list, single item delete, and update domain URLs 2026-09-18 08:34:04 +07:00
idtemankampus-creator e8b955a650 feat(i18n): add dynamic plugin row description based on site locale and donate link 2026-09-18 08:28:20 +07:00
idtemankampus-creator ad2aa48b97 feat(ux): add activation redirect, loading state overlay, and direct view list button in notice 2026-09-18 08:22:45 +07:00
idtemankampus-creator 593d39ffe6 style(ui): redesign dashboard with modern WP admin aesthetics, responsive grid, custom CSS, and pill switcher 2026-09-17 22:51:52 +07:00
idtemankampus-creator b32a036e52 feat(ui): add bilingual ID/EN support, toggle language, and documentation sidebars 2026-09-17 22:37:56 +07:00
idtemankampus-creator 216d3fffd1 feat(core): update DummyLab with full form options, author masbudikusuma, and strict security 2026-09-17 22:35:51 +07:00
3 changed files with 839 additions and 85 deletions
+70
View File
@@ -0,0 +1,70 @@
# 🧪 DummyLab – Dummy Post & Content Generator
![DummyLab Preview](capture.png)
**DummyLab** is a modern WordPress plugin designed to quickly, safely, and flexibly generate dummy posts and pages for layout and theme testing before publishing real content.
---
## ✨ Key Features (English)
* **Multilingual UI & Content:** Full interface and content generation support in English (🇬🇧) and Indonesian (🇮🇩).
* **Dual Image Source:**
* 🖼️ **Picsum Photos (Online):** Fetch high-quality realistic placeholder photos.
* ⚡ **SVG Placeholder (100% Offline):** Superfast local vector placeholder generator without internet dependency.
* **Full Parameter Customization:** Set post count, content type, status (*Publish, Draft, Pending, Private, Scheduled*), categories, tags, author, date range, and dummy comments.
* **Safety Purge & Rollback:** One-click cleanup feature to remove all generated dummy items and media attachments without affecting original content.
* **Content History Tab:** Manage and delete generated dummy items individually from the dashboard.
* **Modern Admin UX:** Built with clean CSS Grid, language pill-switcher, loading state overlay, and quick action links.
## 🚀 Installation
1. Clone this repository into your WordPress plugins directory:
`wp-content/plugins/dummylab`
2. Activate the plugin via WordPress Admin > **Plugins** > **Installed Plugins**.
3. You will be automatically redirected to **Tools > DummyLab**.
## 👨‍💻 Author & Support
* **Author:** masbudikusuma ([masbudi.my.id](https://masbudi.my.id))
* **Documentation:** [apps.masbudi.my.id/dummylab-wp](https://apps.masbudi.my.id/dummylab-wp)
* **Donate Support:** [donate.masbudi.my.id/dummylab-wp](https://donate.masbudi.my.id/dummylab-wp)
---
# 🧪 DummyLab – Generator Konten & Post Dummy
![Tampilan DummyLab](capture.png)
**DummyLab** adalah plugin WordPress modern untuk membuat data *dummy* (Post & Page) secara cepat, aman, dan fleksibel untuk kebutuhan pengujian tata letak (*layout testing*) sebelum konten asli dipublikasikan.
---
## ✨ Fitur Utama (Bahasa Indonesia)
* **Multilingual UI & Konten:** Dukungan antarmuka dan konten buatan dalam Bahasa Indonesia (🇮🇩) dan Bahasa Inggris (🇬🇧).
* **Dua Sumber Gambar:**
* 🖼️ **Picsum Photos (Online):** Mengunduh foto realistis berkualitas tinggi.
* ⚡ **SVG Placeholder (100% Offline):** Pembuatan gambar vektor lokal yang super cepat dan aman tanpa koneksi internet.
* **Kustomisasi Parameter Lengkap:** Atur jumlah postingan, tipe konten, status (*Publish, Draft, Pending, Private, Scheduled*), kategori, tag, penulis, rentang tanggal, hingga komentar *dummy*.
* **Safety Purge & Rollback:** Fitur pembersihan sekali klik (*1-click purge*) yang menghapus seluruh data *dummy* beserta berkas gambarnya dari Media Library tanpa menyentuh konten asli web.
* **Riwayat Konten (History Tab):** Kelola dan hapus postingan *dummy* secara individual dari dashboard.
* **Admin UX Modern:** Tampilan berbasis CSS Grid modern, tombol pemilih bahasa *pill-switcher*, indikator status *loading overlay*, dan pintasan cepat (*action links*).
## 🚀 Cara Instalasi
1. Klon repositori ini ke folder: `wp-content/plugins/dummylab`
2. Aktifkan plugin via Dashboard WordPress > **Plugins** > **Installed Plugins**.
3. Anda akan otomatis diarahkan ke menu kontrol: **Tools > DummyLab**.
## 👨‍💻 Pembuat & Dukungan
* **Author:** masbudikusuma ([masbudi.my.id](https://masbudi.my.id))
* **Dokumentasi Aplikasi:** [apps.masbudi.my.id/dummylab-wp](https://apps.masbudi.my.id/dummylab-wp)
* **Dukung Donasi:** [donate.masbudi.my.id/dummylab-wp](https://donate.masbudi.my.id/dummylab-wp)
---
## 📄 License / Lisensi
This project is licensed under the [GPL v2 or later](http://www.gnu.org/licenses/gpl-2.0.txt).
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

+766 -82
View File
@@ -1,17 +1,19 @@
<?php <?php
/** /**
* Plugin Name: DummyLab – Dummy Post & Content Generator * Plugin Name: DummyLab – Dummy Post & Content Generator
* Plugin URI: https://wordpress.org/plugins/dummylab-wp/ * Plugin URI: https://apps.masbudi.my.id/dummylab-wp
* Description: Generates safe dummy posts for development & layout testing with one-click cleanup feature. * Description: Advanced dummy content generator for WordPress development with safety controls and bulk purge features.
* Version: 1.0.0 * Version: 1.5.2
* Author: A. Budi Kusuma * Author: masbudikusuma
* Author URI: https://masbudi.my.id
* Donate link: https://donate.masbudi.my.id/dummylab-wp
* Text Domain: dummylab * Text Domain: dummylab
* License: GPL-2.0+ * License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
*/ */
if (!defined('ABSPATH')) { if (!defined('ABSPATH')) {
exit; // Exit if accessed directly. exit;
} }
class DummyLab { class DummyLab {
@@ -27,8 +29,60 @@ class DummyLab {
private function __construct() { private function __construct() {
add_action('admin_menu', [$this, 'add_admin_menu']); add_action('admin_menu', [$this, 'add_admin_menu']);
add_action('admin_init', [$this, 'handle_activation_redirect']);
add_action('admin_post_dummylab_generate', [$this, 'handle_generate']); add_action('admin_post_dummylab_generate', [$this, 'handle_generate']);
add_action('admin_post_dummylab_purge', [$this, 'handle_purge']); add_action('admin_post_dummylab_purge', [$this, 'handle_purge']);
add_action('admin_post_dummylab_delete_single', [$this, 'handle_delete_single']);
add_filter('all_plugins', [$this, 'dynamic_plugin_description']);
add_filter('plugin_row_meta', [$this, 'add_plugin_row_meta'], 10, 2);
add_filter('plugin_action_links_' . plugin_basename(__FILE__), [$this, 'add_plugin_action_links']);
}
public static function activate_plugin() {
add_option('dummylab_do_activation_redirect', true);
}
public function handle_activation_redirect() {
if (get_option('dummylab_do_activation_redirect', false)) {
delete_option('dummylab_do_activation_redirect');
if (!isset($_GET['activate-multi'])) {
wp_safe_redirect(admin_url('tools.php?page=dummylab'));
exit;
}
}
}
public function dynamic_plugin_description($all_plugins) {
$plugin_file = plugin_basename(__FILE__);
if (isset($all_plugins[$plugin_file])) {
$locale = get_locale();
if (strpos($locale, 'id') === 0) {
$all_plugins[$plugin_file]['Description'] = 'Generate post dummy (bahasa Indonesia atau Inggris) lengkap dengan judul, isi artikel, gambar unggulan, kategori, tag, penulis, tanggal, dan komentar dummy. Cocok untuk melihat simulasi tampilan tema sebelum diisi konten asli.';
} else {
$all_plugins[$plugin_file]['Description'] = 'Generate dummy posts and pages (Indonesian or English) with custom titles, article body, featured images, categories, tags, author, date, and comments. Perfect for testing theme layouts before publishing real content.';
}
}
return $all_plugins;
}
// Menambahkan Link Donasi bersih di baris meta bawah
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://donate.masbudi.my.id/dummylab-wp" target="_blank" style="color: #b35900; font-weight: 600;">' . esc_html($donate_label) . '</a>';
}
return $links;
}
// Menambahkan link "Generator" di sebelah Deactivate (Rapi & Sejajar)
public function add_plugin_action_links($links) {
$locale = get_locale();
$label = (strpos($locale, 'id') === 0) ? 'Generator' : 'Generator';
$generator_link = '<a href="' . esc_url(admin_url('tools.php?page=dummylab')) . '">' . esc_html($label) . '</a>';
array_unshift($links, $generator_link);
return $links;
} }
public function add_admin_menu() { public function add_admin_menu() {
@@ -46,131 +100,711 @@ class DummyLab {
return; return;
} }
// Count existing dummy posts $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([ $query = new WP_Query([
'post_type' => 'post', 'post_type' => ['post', 'page', 'attachment'],
'posts_per_page' => -1, 'posts_per_page' => -1,
'meta_key' => $this->meta_key, 'meta_key' => $this->meta_key,
'meta_value' => '1', 'meta_value' => '1',
'fields' => 'ids', 'fields' => 'ids',
'post_status' => 'any',
]); ]);
$dummy_count = $query->found_posts; $dummy_count = $query->found_posts;
$t = $this->get_translations($ui_lang);
?> ?>
<div class="wrap"> <style>
<h1>🧪 DummyLab – Post Generator</h1> .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; }
<p>Generate dummy posts safely for design testing and layout development.</p> .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; }
<hr /> .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; }
.dummylab-lang-switch { background: #f0f0f1; padding: 4px; border-radius: 20px; display: flex; gap: 4px; border: 1px solid #dcdcde; }
.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); }
.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; }
.dummylab-section-title { font-size: 15px; font-weight: 600; color: #1d2327; margin: 20px 0 14px 0; padding-bottom: 8px; border-bottom: 1px solid #f0f0f1; display: flex; align-items: center; gap: 8px; }
.dummylab-section-title:first-of-type { margin-top: 0; }
.dummylab-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 16px; }
.dummylab-field { display: flex; flex-direction: column; gap: 6px; }
.dummylab-field.full-width { grid-column: span 2; }
.dummylab-field label { font-size: 13px; font-weight: 600; color: #2c3338; }
.dummylab-field input[type="text"],
.dummylab-field input[type="number"],
.dummylab-field select { width: 100%; border: 1px solid #8c8f94; border-radius: 6px; padding: 7px 10px; font-size: 13px; background-color: #fff; box-shadow: 0 0 0 transparent; transition: border-color 0.15s ease-in-out; }
.dummylab-field input:focus, .dummylab-field select:focus { border-color: #2271b1; box-shadow: 0 0 0 1px #2271b1; outline: none; }
.dummylab-field .description { margin: 2px 0 0 0; font-size: 12px; color: #646970; line-height: 1.4; }
.dummylab-checkbox-group { display: flex; flex-direction: column; gap: 10px; padding: 12px; background: #f6f7f7; border-radius: 6px; border: 1px solid #dcdcde; }
.dummylab-checkbox-group label { font-weight: 500; font-size: 13px; color: #1d2327; display: flex; align-items: center; gap: 8px; cursor: pointer; }
.dummylab-side-card { background: #fff; border: 1px solid #c3c4c7; border-radius: 8px; padding: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.04); }
.dummylab-side-card.purge-card { border-top: 4px solid #d63638; }
.dummylab-side-card h3 { margin: 0 0 12px 0; font-size: 15px; font-weight: 600; color: #1d2327; display: flex; align-items: center; gap: 8px; }
.dummylab-badge-count { display: inline-block; background: #fcf0f0; color: #d63638; font-weight: 700; font-size: 16px; padding: 4px 12px; border-radius: 20px; border: 1px solid #f5c6cb; margin-left: 6px; }
.dummylab-guide-list { margin: 0; padding-left: 20px; color: #3c434a; font-size: 13px; line-height: 1.6; }
.dummylab-guide-list li { margin-bottom: 8px; }
.dummylab-safety-list { margin: 0; padding-left: 18px; color: #3c434a; font-size: 13px; line-height: 1.6; list-style-type: square; }
.dummylab-safety-list li { margin-bottom: 6px; }
.dummylab-btn-primary { background: #2271b1 !important; border-color: #2271b1 !important; border-radius: 6px !important; padding: 8px 20px !important; font-size: 14px !important; height: auto !important; cursor: pointer; }
.dummylab-btn-danger { background: #d63638 !important; border-color: #d63638 !important; color: #fff !important; border-radius: 6px !important; padding: 6px 18px !important; font-size: 13px !important; height: auto !important; width: 100%; text-align: center; }
.dummylab-btn-danger:disabled { background: #f6f7f7 !important; border-color: #dcdcde !important; color: #a7aaad !important; cursor: not-allowed; }
.dummylab-loading-overlay { display: none; position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(15, 23, 42, 0.6); backdrop-filter: blur(4px); z-index: 999999; align-items: center; justify-content: center; flex-direction: column; color: #fff; }
.dummylab-spinner { width: 50px; height: 50px; border: 5px solid rgba(255, 255, 255, 0.3); border-radius: 50%; border-top-color: #38bdf8; animation: dummylab-spin 1s ease-in-out infinite; margin-bottom: 16px; }
@keyframes dummylab-spin { to { transform: rotate(360deg); } }
.dummylab-loading-text { font-size: 18px; font-weight: 600; text-align: center; }
.dummylab-loading-subtext { font-size: 13px; color: #cbd5e1; margin-top: 6px; text-align: center; }
</style>
<div id="dummylab-loading-overlay" class="dummylab-loading-overlay">
<div class="dummylab-spinner"></div>
<div class="dummylab-loading-text"><?php echo $t['loading_title']; ?></div>
<div class="dummylab-loading-subtext"><?php echo $t['loading_subtitle']; ?></div>
</div>
<div class="dummylab-wrap">
<div class="dummylab-header">
<div>
<h1>🧪 DummyLab <span style="font-size: 14px; font-weight: 400; color: #646970;">v1.5.2</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> &bull; <a href="https://apps.masbudi.my.id/dummylab-wp" target="_blank" style="text-decoration: none; color: #2271b1;"><?php echo $t['plugin_doc']; ?></a> &bull; <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', '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>
<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'])): ?> <?php if (isset($_GET['status'])): ?>
<div class="notice notice-success is-dismissible"> <div class="notice notice-success is-dismissible" style="border-radius: 6px; margin-bottom: 20px; padding: 12px 16px;">
<p> <p style="font-size: 14px; margin: 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap;">
<?php <?php
if ($_GET['status'] === 'generated') { if ($_GET['status'] === 'generated') {
echo esc_html(intval($_GET['count'])) . ' dummy posts generated successfully!'; $gen_type = isset($_GET['type']) && $_GET['type'] === 'page' ? 'page' : 'post';
$type_label = ($gen_type === 'page') ? ($ui_lang === 'en' ? 'Pages' : 'Halaman (Page)') : ($ui_lang === 'en' ? 'Posts' : 'Post');
$target_url = ($gen_type === 'page') ? admin_url('edit.php?post_type=page') : admin_url('edit.php');
echo '<span>🎉 <strong>' . esc_html(intval($_GET['count'])) . '</strong> ' . esc_html($t['msg_generated']) . ' ' . sprintf(esc_html($t['check_msg']), '<strong>' . esc_html($type_label) . '</strong>') . '</span>';
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) . ' &rarr;</a>';
} elseif ($_GET['status'] === 'purged') { } elseif ($_GET['status'] === 'purged') {
echo esc_html(intval($_GET['count'])) . ' dummy posts deleted successfully!'; 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> </p>
</div> </div>
<?php endif; ?> <?php endif; ?>
<div style="display: flex; gap: 20px; margin-top: 20px;"> <?php if ($current_tab === 'generator'): ?>
<!-- Generate Form --> <div class="dummylab-container">
<div class="card" style="max-width: 400px; width: 100%;"> <div class="dummylab-main-card">
<h2>Generate Dummy Posts</h2> <form id="dummylab-generate-form" method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>"> <?php wp_nonce_field('dummylab_generate_action', 'dummylab_nonce'); ?>
<?php wp_nonce_field('dummylab_generate_action', 'dummylab_nonce'); ?> <input type="hidden" name="action" value="dummylab_generate">
<input type="hidden" name="action" value="dummylab_generate"> <input type="hidden" name="ui_lang" value="<?php echo esc_attr($ui_lang); ?>">
<p> <div class="dummylab-section-title">⚙️ <?php echo $t['sec_general']; ?></div>
<label for="post_count"><strong>Number of Posts:</strong></label><br> <div class="dummylab-grid">
<input type="number" id="post_count" name="post_count" value="5" min="1" max="50" class="regular-text" required> <div class="dummylab-field">
</p> <label for="post_count"><?php echo $t['lbl_count']; ?></label>
<p> <input type="number" id="post_count" name="post_count" value="5" min="1" max="50" required>
<label for="post_status"><strong>Post Status:</strong></label><br> </div>
<select name="post_status" id="post_status"> <div class="dummylab-field">
<option value="publish">Publish</option> <label for="post_type"><?php echo $t['lbl_type']; ?></label>
<option value="draft">Draft</option> <select name="post_type" id="post_type">
</select> <option value="post"><?php echo $t['opt_post']; ?></option>
</p> <option value="page"><?php echo $t['opt_page']; ?></option>
<submit_button> </select>
<?php submit_button('Generate Posts', 'primary', 'submit', false); ?> </div>
</form> <div class="dummylab-field">
<label for="content_lang"><?php echo $t['lbl_content_lang']; ?></label>
<select name="content_lang" id="content_lang">
<option value="id">🇮🇩 Bahasa Indonesia</option>
<option value="en">🇬🇧 English</option>
</select>
</div>
<div class="dummylab-field">
<label for="post_status"><?php echo $t['lbl_status']; ?></label>
<select name="post_status" id="post_status">
<option value="publish"><?php echo $t['opt_publish']; ?></option>
<option value="draft"><?php echo $t['opt_draft']; ?></option>
<option value="pending"><?php echo $t['opt_pending']; ?></option>
<option value="private"><?php echo $t['opt_private']; ?></option>
</select>
</div>
</div>
<div class="dummylab-section-title">🏷️ <?php echo $t['sec_taxonomy']; ?></div>
<div class="dummylab-grid">
<div class="dummylab-field full-width">
<label for="categories"><?php echo $t['lbl_cats']; ?></label>
<input type="text" name="categories" id="categories" placeholder="Teknologi, Berita, Hiburan">
<p class="description"><?php echo $t['desc_cats']; ?></p>
</div>
<div class="dummylab-field full-width">
<label for="tags"><?php echo $t['lbl_tags']; ?></label>
<input type="text" name="tags" id="tags" placeholder="wordpress, dummy, test">
<p class="description"><?php echo $t['desc_tags']; ?></p>
</div>
<div class="dummylab-field">
<label for="post_author"><?php echo $t['lbl_author']; ?></label>
<select name="post_author" id="post_author">
<option value="random"><?php echo $t['opt_random_author']; ?></option>
<?php foreach ($users as $user): ?>
<option value="<?php echo esc_attr($user->ID); ?>"><?php echo esc_html($user->display_name); ?></option>
<?php endforeach; ?>
</select>
</div>
<div class="dummylab-field">
<label for="date_option"><?php echo $t['lbl_date']; ?></label>
<select name="date_option" id="date_option">
<option value="now"><?php echo $t['opt_date_now']; ?></option>
<option value="random_past"><?php echo $t['opt_date_past']; ?></option>
<option value="future"><?php echo $t['opt_date_future']; ?></option>
</select>
</div>
</div>
<div class="dummylab-section-title">📝 <?php echo $t['sec_content']; ?></div>
<div class="dummylab-grid">
<div class="dummylab-field">
<label for="content_length"><?php echo $t['lbl_length']; ?></label>
<select name="content_length" id="content_length">
<option value="short"><?php echo $t['opt_len_short']; ?></option>
<option value="medium" selected><?php echo $t['opt_len_medium']; ?></option>
<option value="long"><?php echo $t['opt_len_long']; ?></option>
</select>
</div>
<div class="dummylab-field">
<label for="image_source"><?php echo $t['lbl_image_source']; ?></label>
<select name="image_source" id="image_source">
<option value="picsum" selected><?php echo $t['opt_img_picsum']; ?></option>
<option value="local_svg"><?php echo $t['opt_img_svg']; ?></option>
</select>
</div>
<div class="dummylab-field full-width">
<label for="image_size"><?php echo $t['lbl_image_size']; ?></label>
<select name="image_size" id="image_size">
<option value="800/600"><?php echo $t['opt_img_small']; ?></option>
<option value="1200/800" selected><?php echo $t['opt_img_med']; ?></option>
<option value="1600/1000"><?php echo $t['opt_img_large']; ?></option>
</select>
</div>
<div class="dummylab-field full-width">
<div class="dummylab-checkbox-group">
<label><input type="checkbox" name="use_featured_image" value="1" checked> 🖼️ <?php echo $t['opt_use_img']; ?></label>
<label><input type="checkbox" name="add_comments" value="1"> 💬 <?php echo $t['opt_comments']; ?></label>
<label><input type="checkbox" name="make_sticky" value="1"> 📌 <?php echo $t['opt_sticky']; ?></label>
</div>
</div>
</div>
<div style="margin-top: 24px;">
<input type="submit" id="dummylab-submit-btn" class="button button-primary dummylab-btn-primary" value="<?php echo esc_attr($t['btn_generate']); ?>">
</div>
</form>
</div>
<div class="dummylab-sidebar">
<div class="dummylab-side-card purge-card">
<h3>🗑️ <?php echo $t['purge_title']; ?></h3>
<p style="font-size: 13px; color: #50575e; margin: 0 0 12px 0;">
<?php echo $t['purge_active']; ?>: <span class="dummylab-badge-count"><?php echo esc_html($dummy_count); ?></span>
</p>
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
<?php wp_nonce_field('dummylab_purge_action', 'dummylab_nonce'); ?>
<input type="hidden" name="action" value="dummylab_purge">
<input type="hidden" name="ui_lang" value="<?php echo esc_attr($ui_lang); ?>">
<p class="description" style="margin-bottom: 14px;"><?php echo $t['purge_desc']; ?></p>
<?php submit_button($t['btn_purge'], 'delete dummylab-btn-danger', 'submit', false, ['disabled' => ($dummy_count === 0)]); ?>
</form>
</div>
<div class="dummylab-side-card">
<h3>📘 <?php echo $t['guide_title']; ?></h3>
<ol class="dummylab-guide-list">
<li><?php echo $t['guide_step1']; ?></li>
<li><?php echo $t['guide_step2']; ?></li>
<li><?php echo $t['guide_step3']; ?></li>
<li><?php echo $t['guide_step4']; ?></li>
</ol>
</div>
<div class="dummylab-side-card" style="background-color: #f8fafc;">
<h3>🛡️ <?php echo $t['safety_title']; ?></h3>
<ul class="dummylab-safety-list">
<li><?php echo $t['safety_item1']; ?></li>
<li><?php echo $t['safety_item2']; ?></li>
<li><?php echo $t['safety_item3']; ?></li>
</ul>
</div>
</div>
</div> </div>
<?php else: ?>
<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>
<!-- Purge / Cleanup Form --> <?php
<div class="card" style="max-width: 400px; width: 100%; border-left: 4px solid #dc3232;"> $history_query = new WP_Query([
<h2>Cleanup / Purge Data</h2> 'post_type' => ['post', 'page'],
<p>Currently active dummy posts: <strong><?php echo esc_html($dummy_count); ?></strong></p> 'posts_per_page' => 50,
<form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>"> 'meta_key' => $this->meta_key,
<?php wp_nonce_field('dummylab_purge_action', 'dummylab_nonce'); ?> 'meta_value' => '1',
<input type="hidden" name="action" value="dummylab_purge"> 'post_status' => 'any',
]);
?>
<p class="description">This action will permanently delete all posts created by DummyLab.</p> <?php if ($history_query->have_posts()): ?>
<?php submit_button('Delete All Dummy Posts', 'delete', 'submit', false, ['disabled' => ($dummy_count === 0)]); ?> <table class="wp-list-table widefat fixed striped table-view-list" style="border-radius: 6px; overflow: hidden; border: 1px solid #c3c4c7;">
</form> <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> </div>
</div> <?php endif; ?>
</div> </div>
<script>
document.addEventListener('DOMContentLoaded', function() {
var form = document.getElementById('dummylab-generate-form');
if (form) {
form.addEventListener('submit', function() {
var overlay = document.getElementById('dummylab-loading-overlay');
var btn = document.getElementById('dummylab-submit-btn');
if (overlay) {
overlay.style.display = 'flex';
}
if (btn) {
btn.disabled = true;
btn.value = '⏳ Generating...';
}
});
}
});
</script>
<?php <?php
} }
private function get_translations($lang) {
if ($lang === 'en') {
return [
'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',
'sec_taxonomy' => 'Taxonomy & Author',
'sec_content' => 'Content & Media',
'lbl_count' => 'Post/Page Count',
'lbl_type' => 'Content Type',
'opt_post' => 'Post',
'opt_page' => 'Page',
'lbl_content_lang' => 'Content Language',
'lbl_status' => 'Post Status',
'opt_publish' => 'Publish',
'opt_draft' => 'Draft',
'opt_pending' => 'Pending Review',
'opt_private' => 'Private',
'lbl_cats' => 'Categories',
'desc_cats' => 'Categories created automatically if not present. Comma-separated.',
'lbl_tags' => 'Additional Tags',
'desc_tags' => 'Optional, comma-separated tags.',
'lbl_author' => 'Author',
'opt_random_author' => 'Random from all users',
'lbl_date' => 'Post Date',
'opt_date_now' => 'Current time',
'opt_date_past' => 'Random in past few days',
'opt_date_future' => 'Future date (Scheduled)',
'lbl_length' => 'Article Length',
'opt_len_short' => 'Short (2-3 paragraphs)',
'opt_len_medium' => 'Medium (4-6 paragraphs + heading)',
'opt_len_long' => 'Long (7-10 paragraphs + heading, quote)',
'lbl_image_source' => 'Image Source Method',
'opt_img_picsum' => 'Picsum Photos (Online - High Quality Photos)',
'opt_img_svg' => 'SVG Placeholder (100% Offline & Fast)',
'lbl_image_size' => 'Featured Image Size',
'opt_use_img' => 'Include featured image',
'opt_img_small' => 'Small (800x600)',
'opt_img_med' => 'Medium (1200x800)',
'opt_img_large' => 'Large (1600x1000)',
'opt_comments' => 'Include dummy comments',
'opt_sticky' => 'Make first post sticky (Post type only)',
'btn_generate' => '🚀 Generate Dummy Data',
'purge_title' => 'Cleanup & Purge',
'purge_active' => 'Active dummy items',
'purge_desc' => 'Permanently deletes all posts, pages, and media attachments created by DummyLab.',
'btn_purge' => 'Delete All Dummy Data',
'guide_title' => 'Quick Usage Guide',
'guide_step1' => 'Select total count and content type (Post/Page).',
'guide_step2' => 'Choose generated text language and length.',
'guide_step3' => 'Choose between online photos or offline fast SVG images.',
'guide_step4' => 'Click Purge anytime to completely clean test data.',
'safety_title' => 'Development Safety',
'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.',
];
}
return [
'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 memproses data artikel dan gambar.',
'sec_general' => 'Pengaturan Utama',
'sec_taxonomy' => 'Taksonomi & Penulis',
'sec_content' => 'Konten & Media',
'lbl_count' => 'Jumlah Post/Halaman',
'lbl_type' => 'Tipe Konten',
'opt_post' => 'Post',
'opt_page' => 'Halaman (Page)',
'lbl_content_lang' => 'Bahasa Konten',
'lbl_status' => 'Status Post',
'opt_publish' => 'Publish (terbit)',
'opt_draft' => 'Draft',
'opt_pending' => 'Pending Review',
'opt_private' => 'Private',
'lbl_cats' => 'Kategori',
'desc_cats' => 'Kategori dibuat otomatis jika belum ada. Pisahkan dengan koma.',
'lbl_tags' => 'Tag Tambahan',
'desc_tags' => 'Opsional, pisahkan dengan koma.',
'lbl_author' => 'Penulis',
'opt_random_author' => 'Acak dari semua pengguna',
'lbl_date' => 'Tanggal Post',
'opt_date_now' => 'Waktu sekarang',
'opt_date_past' => 'Acak dalam beberapa hari terakhir',
'opt_date_future' => 'Rentang tanggal tertentu (Scheduled)',
'lbl_length' => 'Panjang Artikel',
'opt_len_short' => 'Pendek (2-3 paragraf)',
'opt_len_medium' => 'Sedang (4-6 paragraf + heading)',
'opt_len_long' => 'Panjang (7-10 paragraf + heading, quote)',
'lbl_image_source' => 'Metode Sumber Gambar',
'opt_img_picsum' => 'Picsum Photos (Online - Foto Asli Realistis)',
'opt_img_svg' => 'SVG Placeholder (100% Offline & Super Cepat)',
'lbl_image_size' => 'Ukuran Gambar Unggulan',
'opt_use_img' => 'Sertakan gambar unggulan',
'opt_img_small' => 'Kecil (800x600)',
'opt_img_med' => 'Sedang (1200x800)',
'opt_img_large' => 'Besar (1600x1000)',
'opt_comments' => 'Sertakan komentar dummy',
'opt_sticky' => 'Jadikan post pertama sebagai sticky post (khusus Post)',
'btn_generate' => '🚀 Generate Data Dummy',
'purge_title' => 'Pembersihan & Purge',
'purge_active' => 'Total data dummy aktif',
'purge_desc' => 'Tindakan ini akan menghapus permanen seluruh post, page, dan gambar yang dibuat oleh DummyLab.',
'btn_purge' => 'Hapus Semua Data Dummy',
'guide_title' => 'Panduan Penggunaan',
'guide_step1' => 'Pilih jumlah data dan tipe konten (Post atau Halaman).',
'guide_step2' => 'Atur bahasa dan panjang artikel yang akan dihasilkan.',
'guide_step3' => 'Pilih sumber gambar online (foto asli) atau offline (SVG instan).',
'guide_step4' => 'Gunakan tombol Purge untuk menghapus semua data pengujian.',
'safety_title' => 'Pengembangan Aman',
'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.',
];
}
public function handle_generate() { public function handle_generate() {
if (!current_user_can('manage_options') || !check_admin_referer('dummylab_generate_action', 'dummylab_nonce')) { if (!current_user_can('manage_options') || !check_admin_referer('dummylab_generate_action', 'dummylab_nonce')) {
wp_die('Unauthorized request.'); wp_die('Akses ditolak.');
} }
$count = isset($_POST['post_count']) ? min(50, max(1, intval($_POST['post_count']))) : 5; require_once(ABSPATH . 'wp-admin/includes/image.php');
$status = isset($_POST['post_status']) && in_array($_POST['post_status'], ['publish', 'draft']) ? $_POST['post_status'] : 'publish'; require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$titles = [ $ui_lang = isset($_POST['ui_lang']) ? sanitize_text_field($_POST['ui_lang']) : 'id';
'Exploring the Future of Web Architecture', $count = isset($_POST['post_count']) ? min(50, max(1, intval($_POST['post_count']))) : 5;
'10 Essential Tips for Responsive Design', $post_type = isset($_POST['post_type']) && in_array($_POST['post_type'], ['post', 'page']) ? $_POST['post_type'] : 'post';
'Understanding High-Performance Server Configurations', $lang = isset($_POST['content_lang']) ? sanitize_text_field($_POST['content_lang']) : 'id';
'A Deep Dive into Modern CMS Solutions', $status = isset($_POST['post_status']) ? sanitize_text_field($_POST['post_status']) : 'publish';
'Optimizing Database Queries for Scalability', $categories_raw = isset($_POST['categories']) ? sanitize_text_field($_POST['categories']) : '';
'Building Secure Application Infrastructure' $tags_raw = isset($_POST['tags']) ? sanitize_text_field($_POST['tags']) : '';
]; $author_opt = isset($_POST['post_author']) ? sanitize_text_field($_POST['post_author']) : 'random';
$date_opt = isset($_POST['date_option']) ? sanitize_text_field($_POST['date_option']) : 'now';
$content_length = isset($_POST['content_length']) ? sanitize_text_field($_POST['content_length']) : 'medium';
$image_source = isset($_POST['image_source']) ? sanitize_text_field($_POST['image_source']) : 'picsum';
$use_image = isset($_POST['use_featured_image']) ? true : false;
$image_size = isset($_POST['image_size']) ? sanitize_text_field($_POST['image_size']) : '1200/800';
$add_comments = isset($_POST['add_comments']) ? true : false;
$make_sticky = isset($_POST['make_sticky']) ? true : false;
$paragraphs = [ $cat_ids = [];
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.', if ($post_type === 'post' && !empty($categories_raw)) {
'Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.', $cat_names = array_map('trim', explode(',', $categories_raw));
'Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris.' foreach ($cat_names as $cat_name) {
]; if (empty($cat_name)) continue;
$term = term_exists($cat_name, 'category');
for ($i = 0; $i < $count; $i++) { if (!$term) {
$random_title = $titles[array_rand($titles)] . ' #' . rand(100, 999); $term = wp_insert_term($cat_name, 'category');
$random_content = '<p>' . $paragraphs[array_rand($paragraphs)] . '</p><p>' . $paragraphs[array_rand($paragraphs)] . '</p>'; }
if (!is_wp_error($term)) {
$post_id = wp_insert_post([ $cat_ids[] = (int) $term['term_id'];
'post_title' => $random_title, }
'post_content' => $random_content,
'post_status' => $status,
'post_type' => 'post',
'post_author' => get_current_user_id(),
]);
if ($post_id && !is_wp_error($post_id)) {
update_post_meta($post_id, $this->meta_key, '1');
} }
} }
wp_redirect(admin_url('tools.php?page=dummylab&status=generated&count=' . $count)); $tag_names = !empty($tags_raw) ? array_map('trim', explode(',', $tags_raw)) : [];
$user_ids = get_users(['fields' => 'ID']);
for ($i = 0; $i < $count; $i++) {
$author_id = ($author_opt === 'random') ? $user_ids[array_rand($user_ids)] : intval($author_opt);
$post_date = current_time('mysql');
$final_status = $status;
if ($date_opt === 'random_past') {
$days_back = rand(1, 30);
$post_date = date('Y-m-d H:i:s', strtotime("-$days_back days"));
} elseif ($date_opt === 'future') {
$days_ahead = rand(1, 15);
$post_date = date('Y-m-d H:i:s', strtotime("+$days_ahead days"));
$final_status = 'future';
}
$title = $this->get_sample_title($lang, $i);
$content = $this->get_sample_content($lang, $content_length);
$post_data = [
'post_title' => $title,
'post_content' => $content,
'post_status' => $final_status,
'post_type' => $post_type,
'post_author' => $author_id,
'post_date' => $post_date,
];
if ($post_type === 'post' && !empty($cat_ids)) {
$post_data['post_category'] = [$cat_ids[array_rand($cat_ids)]];
}
if ($post_type === 'post' && !empty($tag_names)) {
$post_data['tags_input'] = $tag_names;
}
$post_id = wp_insert_post($post_data);
if ($post_id && !is_wp_error($post_id)) {
update_post_meta($post_id, $this->meta_key, '1');
if ($use_image) {
if ($image_source === 'local_svg') {
$size_parts = explode('/', $image_size);
$w = isset($size_parts[0]) ? intval($size_parts[0]) : 1200;
$h = isset($size_parts[1]) ? intval($size_parts[1]) : 800;
$colors = ['#1e293b', '#0f172a', '#1e3a8a', '#14532d', '#701a75', '#312e81', '#831843', '#7c2d12'];
$bg_color = $colors[array_rand($colors)];
$svg_content = '<svg xmlns="http://www.w3.org/2000/svg" width="' . $w . '" height="' . $h . '" viewBox="0 0 ' . $w . ' ' . $h . '">' .
'<rect width="100%" height="100%" fill="' . $bg_color . '"/>' .
'<text x="50%" y="45%" dominant-baseline="middle" text-anchor="middle" fill="#ffffff" font-size="36" font-family="sans-serif" font-weight="bold">DummyLab Placeholder</text>' .
'<text x="50%" y="55%" dominant-baseline="middle" text-anchor="middle" fill="#94a3b8" font-size="20" font-family="sans-serif">' . $w . ' x ' . $h . ' - Post #' . $post_id . '</text>' .
'</svg>';
$file_name = 'dummylab-svg-' . $post_id . '-' . rand(100, 999) . '.svg';
$upload = wp_upload_bits($file_name, null, $svg_content);
if (!$upload['error']) {
$attachment = [
'post_mime_type' => 'image/svg+xml',
'post_title' => 'DummyLab SVG ' . $post_id,
'post_content' => '',
'post_status' => 'inherit'
];
$attach_id = wp_insert_attachment($attachment, $upload['file'], $post_id);
if ($attach_id && !is_wp_error($attach_id)) {
$attach_data = wp_generate_attachment_metadata($attach_id, $upload['file']);
wp_update_attachment_metadata($attach_id, $attach_data);
set_post_thumbnail($post_id, $attach_id);
update_post_meta($attach_id, $this->meta_key, '1');
}
}
} else {
$image_url = 'https://picsum.photos/' . $image_size . '?random=' . rand(1, 9999);
$tmp = download_url($image_url);
if (!is_wp_error($tmp)) {
$file_array = [
'name' => 'dummylab-' . $post_id . '.jpg',
'tmp_name' => $tmp
];
$attach_id = media_handle_sideload($file_array, $post_id);
if (!is_wp_error($attach_id)) {
set_post_thumbnail($post_id, $attach_id);
update_post_meta($attach_id, $this->meta_key, '1');
}
@unlink($tmp);
}
}
}
if ($i === 0 && $make_sticky && $post_type === 'post') {
stick_post($post_id);
}
if ($add_comments) {
$comment_count = rand(1, 3);
for ($c = 0; $c < $comment_count; $c++) {
wp_insert_comment([
'comment_post_ID' => $post_id,
'comment_author' => 'Tester Dummy',
'comment_author_email' => '[email protected]',
'comment_content' => ($lang === 'id') ? 'Artikel yang sangat bermanfaat dan informatif!' : 'Great content, thanks for sharing!',
'comment_approved' => 1,
]);
}
}
}
}
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; exit;
} }
public function handle_purge() { public function handle_purge() {
if (!current_user_can('manage_options') || !check_admin_referer('dummylab_purge_action', 'dummylab_nonce')) { if (!current_user_can('manage_options') || !check_admin_referer('dummylab_purge_action', 'dummylab_nonce')) {
wp_die('Unauthorized request.'); wp_die('Akses ditolak.');
} }
$ui_lang = isset($_POST['ui_lang']) ? sanitize_text_field($_POST['ui_lang']) : 'id';
$query = new WP_Query([ $query = new WP_Query([
'post_type' => 'post', 'post_type' => ['post', 'page', 'attachment'],
'posts_per_page' => -1, 'posts_per_page' => -1,
'meta_key' => $this->meta_key, 'meta_key' => $this->meta_key,
'meta_value' => '1', 'meta_value' => '1',
'fields' => 'ids', 'fields' => 'ids',
'post_status' => 'any',
]); ]);
$purged_count = 0; $purged_count = 0;
@@ -182,9 +816,59 @@ class DummyLab {
} }
} }
wp_redirect(admin_url('tools.php?page=dummylab&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; exit;
} }
private function get_sample_title($lang, $index) {
$titles_id = [
'Panduan Lengkap Pengembangan Infrastruktur Web Modern',
'Mengoptimalkan Performa Database untuk Trafik Tinggi',
'Desain Responsif dan Pengalaman Pengguna Terbaik',
'Strategi Keamanan Server dan Arsitektur Komputasi Awan',
'Manajemen Konten Efektif untuk Pertumbuhan Bisnis'
];
$titles_en = [
'Exploring the Future of Scalable Web Architecture',
'10 Essential Practices for High-Performance Servers',
'Understanding Modern UI/UX Design Principles',
'Building Secure Application Infrastructures',
'Optimizing Database Queries for Enterprise Solutions'
];
$arr = ($lang === 'id') ? $titles_id : $titles_en;
return $arr[array_rand($arr)] . ' #' . rand(100, 999);
}
private function get_sample_content($lang, $length) {
$p_id = [
'Pengembangan aplikasi web modern memerlukan perhatian ekstra pada arsitektur sistem dasar. Komponen seperti manajemen memori, optimasi kueri, dan konfigurasi server menjadi kunci utama.',
'Dengan menerapkan standar keamanan terbaik, kita dapat mencegah potensi bahaya siber dan memastikan layanan tetap stabil di bawah beban lalu lintas data yang tinggi.',
'Pengalaman pengguna merupakan elemen krusial. Tata letak visual yang konsisten serta navigasi intuitif memudahkan pengunjung dalam menemukan informasi secara cepat.'
];
$p_en = [
'Modern web applications require strict adherence to solid system architectures. Key aspects include efficient database queries, memory management, and caching layer implementation.',
'Ensuring continuous infrastructure security prevents vulnerabilities while guaranteeing optimal uptime during high-volume traffic spikes.',
'User experience design directly impacts engagement rates. Clean layouts, readable typography, and intuitive interfaces make content consumption seamless.'
];
$paragraphs = ($lang === 'id') ? $p_id : $p_en;
$output = '';
$loops = ($length === 'short') ? 2 : (($length === 'long') ? 7 : 4);
for ($k = 0; $k < $loops; $k++) {
$output .= '<p>' . $paragraphs[array_rand($paragraphs)] . '</p>';
if ($length !== 'short' && $k === 1) {
$output .= '<h2>' . (($lang === 'id') ? 'Sub-judul Informasi Penting' : 'Key Technical Insights') . '</h2>';
}
if ($length === 'long' && $k === 3) {
$output .= '<blockquote><p>' . (($lang === 'id') ? 'Keamanan dan kecepatan adalah fondasi utama pengembangan web.' : 'Security and performance are the core foundations of web development.') . '</p></blockquote>';
}
}
return $output;
}
} }
register_activation_hook(__FILE__, ['DummyLab', 'activate_plugin']);
DummyLab::get_instance(); DummyLab::get_instance();