The pasted code is the Product menu code, add a logging history code based on the Inventory History so the adding, editing/updating and deleting of product will be recorded or seen in the Inventory History. The Product menu code: <?php
/**
* Plugin Name: Product Menu Snippet
* Description: Adds a Product menu with add, edit, and delete functionality, including server-side search with a clear button.
*/
global $wpdb;
// --- Configuration ---
$product_table_name = 'products'; // Adjust if you use prefixes: $wpdb->prefix . 'products';
$category_table_name = 'categories'; // Adjust if you use prefixes: $wpdb->prefix . 'categories';
// Ensure upload directory exists
$upload_dir_info = wp_upload_dir();
$upload_dir = $upload_dir_info['basedir'] . '/product_images/';
$upload_url = $upload_dir_info['baseurl'] . '/product_images/'; // Base URL for displaying images
if (!file_exists($upload_dir)) {
wp_mkdir_p($upload_dir); // Use wp_mkdir_p for recursive creation
}
$editing_product = null; // Initialize editing product variable
$message = ''; // For success/error messages
$message_type = ''; // 'success' or 'error'
// --- Handle Delete Product Action ---
if (isset($_GET['action']) && $_GET['action'] === 'delete_product' && isset($_GET['id']) && isset($_GET['_wpnonce']) && wp_verify_nonce($_GET['_wpnonce'], 'delete_product_' . absint($_GET['id']))) {
$product_id_to_delete = absint($_GET['id']);
if ($product_id_to_delete) {
// Optional: Delete image file first
$image_url_to_delete = $wpdb->get_var($wpdb->prepare("SELECT image_url FROM $product_table_name WHERE id = %d", $product_id_to_delete));
if ($image_url_to_delete) {
$image_path = str_replace($upload_url, $upload_dir, $image_url_to_delete);
if (file_exists($image_path)) {
@unlink($image_path);
}
}
// Delete product record
$deleted = $wpdb->delete( $product_table_name,
array('id' => $product_id_to_delete),
array('%d')
);
if ($deleted) {
$message = 'Product deleted successfully!';
$message_type = 'success';
// Redirect after delete to clear URL parameters
wp_redirect(remove_query_arg(array('action', 'id', '_wpnonce')));
exit;
} else {
$message = 'Error deleting product.';
$message_type = 'error';
}
}
}
// --- Handle Edit Product Action (Prepare form) ---
if (isset($_GET['action']) && $_GET['action'] === 'edit_product' && isset($_GET['id'])) {
$product_id_to_edit = absint($_GET['id']);
if ($product_id_to_edit) {
$editing_product = $wpdb->get_row(
// Make sure to select the 'unit' column if it exists
$wpdb->prepare("SELECT * FROM $product_table_name WHERE id = %d", $product_id_to_edit),
ARRAY_A
);
if (!$editing_product) {
$message = 'Product not found for editing.';
$message_type = 'error';
}
}
}
// --- Handle Add/Update Product Form Submission ---
// Use a nonce for security
if (isset($_POST['save_product']) && isset($_POST['_wpnonce_product_form']) && wp_verify_nonce($_POST['_wpnonce_product_form'], 'save_product_action')) { // Sanitize and validate input data
$product_name = isset($_POST['product_name']) ? sanitize_text_field($_POST['product_name']) : '';
$product_category = isset($_POST['product_category']) ? sanitize_text_field($_POST['product_category']) : '';
$unit = isset($_POST['unit']) ? sanitize_text_field($_POST['unit']) : ''; // Changed from volume_unit
$buying_price = isset($_POST['buying_price']) ? preg_replace('/[^0-9.]/', '', $_POST['buying_price']) : '0'; // Allow only numbers and dot
$selling_price = isset($_POST['selling_price']) ? preg_replace('/[^0-9.]/', '', $_POST['selling_price']) : '0'; // Allow only numbers and dot
$quantity_submitted = isset($_POST['quantity_input']) ? absint($_POST['quantity_input']) : 0; // Use new name 'quantity_input'
$edit_product_id = isset($_POST['edit_product_id']) ? absint($_POST['edit_product_id']) : 0;
$product_image_url = isset($_POST['old_image_url']) ? esc_url_raw($_POST['old_image_url']) : ''; // Keep old image if not new upload
// --- Image Upload Handling ---
if (isset($_FILES['product_image']) && $_FILES['product_image']['error'] === UPLOAD_ERR_OK) {
$file = $_FILES['product_image'];
// Use WordPress functions for handling uploads securely
if (!function_exists('wp_handle_upload')) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
}
$upload_overrides = array('test_form' => false); // Important for security
// Specify target directory within uploads
$movefile = wp_handle_upload($file, $upload_overrides, current_time('mysql'));
if ($movefile && !isset($movefile['error'])) {
// Success! $movefile contains 'url', 'file' (path), 'type'
$product_image_url = $movefile['url'];
// Optional: Delete old image if updating and upload is successful
if ($edit_product_id && isset($_POST['old_image_url']) && $_POST['old_image_url'] !== $product_image_url) {
$old_image_path = str_replace($upload_url, $upload_dir, esc_url_raw($_POST['old_image_url']));
if (file_exists($old_image_path)) {
@unlink($old_image_path);
}
}
} else {
// $movefile['error'] contains the error message
$message = 'Image upload error: ' . esc_html($movefile['error']);
$message_type = 'error';
}
} elseif (isset($_FILES['product_image']) && $_FILES['product_image']['error'] !== UPLOAD_ERR_NO_FILE) {
// Handle other upload errors
$message = 'Image upload error code: ' . $_FILES['product_image']['error'];
$message_type = 'error';
}
// --- End Image Upload Handling ---
// Proceed only if no upload error occurred or no file was uploaded
if ($message_type !== 'error') {
// Added check for unit (optional, depends if it's required)
if (!empty($product_name) && !empty($product_category) && is_numeric($buying_price) && is_numeric($selling_price)) {
$product_data = array(
'image_url' => $product_image_url,
'name' => $product_name,
'category' => $product_category,
'unit' => $unit, // Changed from volume_unit
'buying_price' => (float)$buying_price, // Store as float
'selling_price' => (float)$selling_price, // Store as float
// 'in_stock' will be handled below based on add/edit
'updated_at' => current_time('mysql') // Always update 'updated_at'
);
// Base format array (excluding in_stock and created_at for now)
$data_format = array('%s', '%s', '%s', '%s', '%f', '%f', '%s'); // image_url, name, category, unit, buying_price, selling_price, updated_at
if ($edit_product_id) {
// --- UPDATE existing product ---
// Fetch current stock
$current_stock = $wpdb->get_var(
$wpdb->prepare("SELECT in_stock FROM $product_table_name WHERE id = %d", $edit_product_id)
);
if ($current_stock === null) {
$message = 'Error: Could not find product to update stock.';
$message_type = 'error';
} else {
// Calculate new stock: Add submitted quantity to current stock
$new_stock_value = absint($current_stock) + $quantity_submitted;
$product_data['in_stock'] = $new_stock_value;
$data_format[] = '%d'; // Add format for in_stock
$updated = $wpdb->update(
$product_table_name,
$product_data,
array('id' => $edit_product_id), // WHERE clause
$data_format, // Format for values being updated
array('%d') // Format for WHERE clause
);
if ($updated !== false) {
$message = 'Product updated successfully!';
$message_type = 'success';
// Clear editing state after successful update
$editing_product = null;
// Optional: Redirect to clear form and prevent resubmission
// wp_redirect(remove_query_arg(array('action', 'id'))); exit;
} else {
$message = 'Error updating product. ' . $wpdb->last_error;
$message_type = 'error';
}
}
} else {
// --- INSERT new product ---
$product_data['in_stock'] = $quantity_submitted; // Initial stock is the submitted quantity
$product_data['created_at'] = current_time('mysql');
$data_format[] = '%d'; // Add format for in_stock
$data_format[] = '%s'; // Add format for created_at
$inserted = $wpdb->insert(
$product_table_name,
$product_data,
$data_format
);
if ($inserted) {
$message = 'Product added successfully!';
$message_type = 'success';
// Optional: Redirect or clear form fields
} else {
$message = 'Error adding product. ' . $wpdb->last_error;
$message_type = 'error';
}
}
} else {
$message = 'Please fill in all required fields with valid data.';
$message_type = 'error';
}
} // End check for upload error
} elseif (isset($_POST['save_product'])) {
// Nonce check failed
$message = 'Security check failed. Please try again.';
$message_type = 'error';
}
// --- Fetch Products and Categories for Display ---
// Base SQL query
$sql = "SELECT id, image_url, name, category, unit, in_stock, buying_price, selling_price, created_at, updated_at FROM $product_table_name";
$where = '';
// Get the search term from the URL query parameter
$search_term = isset($_GET['product_search']) ? sanitize_text_field(wp_unslash($_GET['product_search'])) : '';
// Add search condition if search term is present
if (!empty($search_term)) {
// Prepare the search term for a LIKE query
$search_like = '%' . $wpdb->esc_like($search_term) . '%';
$where = $wpdb->prepare(
" WHERE name LIKE %s OR category LIKE %s OR unit LIKE %s",
$search_like,
$search_like,
$search_like
);
}
$order_by = " ORDER BY name ASC";
// Combine the SQL parts
$products_sql = $sql . $where . $order_by;
// Execute the query
$products = $wpdb->get_results($products_sql, ARRAY_A);
$categories = $wpdb->get_results("SELECT name FROM $category_table_name ORDER BY name ASC", ARRAY_A);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Product Management</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin: 0;
padding: 0;
background-color: #f4f7f9;
color: #333;
}
.dashboard-container { display: flex; }
.sidebar { width: 240px; background-color: #D1B48C; color: #000000; height: 100vh; position: fixed; left: 0; top: 0; overflow-y: auto; box-shadow: 2px 0 5px rgba(0, 0, 0, 0.1); z-index: 1000; }
.sidebar-menu { padding: 20px 0; }
.sidebar-menu ul { list-style: none; padding: 0; margin: 0; }
.sidebar-menu li a { display: flex; align-items: center; padding: 12px 20px; text-decoration: none; color: #000000; transition: background-color 0.3s ease, color 0.3s ease; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 16px; }
.sidebar-menu li a i { margin-right: 12px; width: 20px; text-align: center; flex-shrink: 0; }
.sidebar-menu li a:hover { background-color: #ffffff; color: #000000; }
.sidebar-menu li.active a { background-color: #ffffff; color: #000000; font-weight: bold; }
.main-content { margin-left: 240px; padding: 20px; flex-grow: 1; }
.header { background-color: #fff; padding: 15px 30px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); margin-bottom: 20px; border-bottom: 1px solid #eee; }
.header h1 { margin: 0; font-size: 22px; color: #2f4050; }
.product-content { display: flex; flex-wrap: wrap; gap: 20px; } /* Allow wrapping */
.product-form-container { flex: 1 1 400px; /* Flex basis 400px, allow grow/shrink */ max-width: 500px; background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); border: 1px solid #eee; }
.product-form-container h2 { margin-top: 0; margin-bottom: 15px; color: #2f4050; border-bottom: 1px solid #eee; padding-bottom: 10px; font-size: 18px; }
.product-form-container form { display: flex; flex-direction: column; }
/* --- Reduced Spacing in Add Product Form --- */
.product-form-container label {
margin-bottom: 3px; /* Reduced space below label */
font-weight: 600;
display: block;
font-size: 0.9em;
}
.product-form-container input[type="text"],
.product-form-container input[type="number"],
.product-form-container input[type="file"],
.product-form-container select {
padding: 8px 10px;
margin-bottom: 6px; /* Reduced space below input/select */
border: 1px solid #ddd;
border-radius: 4px;
font-size: 1em;
width: 100%;
box-sizing: border-box;
font-family: inherit;
}
/* --- End Reduced Spacing --- */
.product-form-container input[type="number"] { appearance: textfield; -moz-appearance: textfield; /* For Firefox */ } /* Basic styling for number input */
.product-form-container select { appearance: none; -webkit-appearance: none; -moz-appearance: none; background-image: url('data:image/svg+xml;utf8,<svg fill="%23444" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'); background-repeat: no-repeat; background-position-x: calc(100% - 10px); background-position-y: center; padding-right: 35px; }
.product-form-container button[type="submit"], .button-cancel { padding: 10px 15px; color: #000000; border: none; border-radius: 4px; cursor: pointer; font-size: 1em; transition: background-color 0.3s ease; text-decoration: none; display: inline-block; text-align: center; }
.product-form-container button[type="submit"] { background-color: #D1B48C; /* WP Blue */ margin-right: 10px;}
.product-form-container button[type="submit"]:hover { background-color: #be9b7b; }
.button-cancel { background-color: #D1B48C; } /* Grey */
.button-cancel:hover { background-color: #be9b7b; }
.form-buttons { margin-top: 15px; } /* Slightly increased top margin for buttons */
.product-list-container { flex: 2 1 600px; /* Flex basis 600px */ background-color: #fff; padding: 20px; border-radius: 8px; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); border: 1px solid #eee; overflow-x: auto; /* Add horizontal scroll if needed */ }
.product-list-container h2 { margin-top: 0; margin-bottom: 10px; color: #2f4050; border-bottom: 1px solid #eee; padding-bottom: 10px; font-size: 18px; }
/* --- Improved Styles for Search Bar --- */
.product-list-container form {
display: flex;
align-items: center;
margin-bottom: 15px;
gap: 8px; /* Add gap between wrapper and button */
}
.search-wrapper {
position: relative;
display: flex; /* Use flex for better control */
flex-grow: 1; /* Allow wrapper to take available space */
align-items: center; /* Vertically align items */
}
.product-search-bar {
padding: 8px 30px 8px 10px; /* Adjust padding: top/bottom, right (for clear), left */
border: 1px solid #ccc; /* Slightly darker border */
border-radius: 4px;
font-size: 1em;
font-family: inherit;
width: 100%;
box-sizing: border-box;
line-height: 1.5; /* Adjust line height for better vertical centering */
transition: border-color 0.2s ease-in-out;
}
.product-search-bar:focus {
border-color: #0073aa; /* Highlight border on focus */
outline: none; /* Remove default outline */
box-shadow: 0 0 0 1px #0073aa; /* Optional: Add subtle focus shadow */
}
.clear-search-button {
position: absolute;
top: 50%;
right: 8px; /* Adjust position */
transform: translateY(-50%);
background: none;
border: none;
font-size: 1.5em; /* Slightly larger 'x' */
color: #aaa; /* Lighter color */
cursor: pointer;
padding: 0 4px;
line-height: 1;
display: none; /* Hide initially - JS will show it */
transition: color 0.2s ease-in-out;
}
.clear-search-button:hover {
color: #555; /* Darker on hover */
}
.search-submit-button {
padding: 8px 12px; /* Adjust padding */
background-color: #0073aa;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 1em;
line-height: 1.5; /* Match input line height */
transition: background-color 0.3s ease;
flex-shrink: 0;
display: inline-flex; /* Align icon nicely */
align-items: center;
justify-content: center;
}
.search-submit-button i {
font-size: 0.95em; /* Adjust icon size if needed */
}
.search-submit-button:hover {
background-color: #005a87;
}
/* --- End Search Bar Styles --- */
.product-list-container table { width: 100%; border-collapse: collapse; }
.product-list-container th, .product-list-container td { padding: 10px 12px; text-align: left; border-bottom: 1px solid #eee; font-size: 0.95em; vertical-align: middle; }
.product-list-container th { background-color: #f9f9f9; font-weight: 600; color: #555; white-space: nowrap; }
.product-list-container tbody tr:last-child td { border-bottom: none; }
.product-list-container tbody tr:hover { background-color: #f5f5f5; }
.product-list-container table img { max-width: 45px; max-height: 45px; display: block; border-radius: 3px; }
.product-actions a { margin-right: 5px; text-decoration: none; padding: 4px 8px; border-radius: 4px; color: #fff; font-size: 0.9em; white-space: nowrap; }
.product-actions a i { margin-right: 3px; }
.product-actions a.edit { background-color: #ffc107; } /* Yellow */
.product-actions a.edit:hover { background-color: #e0a800; }
.product-actions a.delete { background-color: #dc3545; } /* Red */
.product-actions a.delete:hover { background-color: #c82333; }
/* Message Styles */
.notice-wrap { margin-bottom: 15px; }
.notice { padding: 10px 15px; border-radius: 4px; border-left: 4px solid; }
.notice-success { background-color: #d4edda; border-color: #28a745; color: #155724; }
.notice-error { background-color: #f8d7da; border-color: #dc3545; color: #721c24; }
</style>
</head>
<body>
<div class="dashboard-container">
<aside class="sidebar">
<div class="sidebar-menu">
<ul>
<li><a href="http://localhost/inventory/index.php/admin-page/">Dashboard</a></li>
<?php
session_start();
$current_username = isset($_SESSION['username']) ? $_SESSION['username'] : '';
if ($current_username === 'admin') : ?>
<li><a href="http://localhost/inventory/index.php/usersmanagement/">User Management</a></li>
<li><a href="http://localhost/inventory/index.php/category-page/">Categories</a></li>
<li><a href="http://localhost/inventory/index.php/products/">Products</a></li>
<li><a href="http://localhost/inventory/index.php/order/">Orders</a></li>
<li><a href="http://localhost/inventory/index.php/view-order/">View Orders</a></li>
<li><a href="http://localhost/inventory/index.php/sales/">Sales & Report</a></li>
<li><a href="http://localhost/inventory/index.php/report/">Inventory Report</a></li>
<li><a href="http://localhost/inventory/index.php/history/">Inventory History</a></li>
<?php else: ?>
<li><a href="http://localhost/inventory/index.php/category-page/">Categories</a></li>
<li><a href="http://localhost/inventory/index.php/products/">Products</a></li>
<li><a href="http://localhost/inventory/index.php/order/">Orders</a></li>
<?php endif; ?>
<li><a href="http://localhost/inventory/index.php/sign-in2/" onclick="return confirm('Are you sure you want to log out?');">Logout</a></li>
</ul>
</div>
</aside>
<main class="main-content">
<header class="header">
<h1>Products Management</h1>
</header>
<?php if ($message): ?>
<div class="notice-wrap">
<div class="notice notice-<?php echo esc_attr($message_type); ?>">
<p><?php echo esc_html($message); ?></p>
</div>
</div>
<?php endif; ?>
<section class="product-content">
<div class="product-form-container">
<h2><?php echo $editing_product ? 'Edit Product' : 'Add New Product'; ?></h2>
<form method="post" enctype="multipart/form-data">
<!-- Add nonce field for security -->
<?php wp_nonce_field('save_product_action', '_wpnonce_product_form'); ?>
<input type="hidden" name="edit_product_id" value="<?php echo esc_attr($editing_product['id'] ?? ''); ?>">
<input type="hidden" name="old_image_url" value="<?php echo esc_attr($editing_product['image_url'] ?? ''); ?>">
<label for="product_name">Product Name:</label>
<input type="text" id="product_name" name="product_name" placeholder="Enter product name" value="<?php echo esc_attr($editing_product['name'] ?? ''); ?>" required>
<label for="product_category">Category:</label>
<select id="product_category" name="product_category" required>
<option value="">Select Category</option>
<?php if (!empty($categories)): ?>
<?php foreach ($categories as $category): ?>
<option value="<?php echo esc_attr($category['name']); ?>" <?php selected($editing_product['category'] ?? '', $category['name']); ?>>
<?php echo esc_html($category['name']); ?>
</option>
<?php endforeach; ?>
<?php else: ?>
<option value="" disabled>No categories found</option>
<?php endif; ?>
</select>
<!-- Changed Volume Unit to Unit -->
<label for="unit">Unit:</label>
<input type="text" id="unit" name="unit" placeholder="e.g., kg, l, ml, pcs" value="<?php echo esc_attr($editing_product['unit'] ?? ''); ?>">
<label for="product_image">Product Image:
<?php if (!empty($editing_product['image_url'])): ?>
<img src="<?php echo esc_url($editing_product['image_url']); ?>" style="max-width: 30px; max-height: 30px; vertical-align: middle; margin-left: 5px;">
<?php endif; ?>
</label>
<input type="file" id="product_image" name="product_image" accept="image/jpeg,image/png,image/gif">
<?php if (!empty($editing_product['image_url'])): ?>
<small>Current image shown. Upload a new file to replace it.</small>
<?php endif; ?>
<label for="buying_price">Buying Price:</label>
<input type="number" step="0.01" min="0" id="buying_price" name="buying_price" placeholder="0.00" value="<?php echo esc_attr($editing_product['buying_price'] ?? '0.00'); ?>" required>
<label for="selling_price">Selling Price:</label>
<input type="number" step="0.01" min="0" id="selling_price" name="selling_price" placeholder="0.00" value="<?php echo esc_attr($editing_product['selling_price'] ?? '0.00'); ?>" required>
<!-- *** MODIFIED QUANTITY INPUT *** -->
<label for="quantity_input">
<?php echo $editing_product ? 'Quantity to Add:' : 'Quantity:'; ?>
</label>
<input type="number" min="0" id="quantity_input" name="quantity_input" placeholder="Quantity" value="0" required>
<?php if ($editing_product): ?>
<small>Current Stock: <?php echo esc_html($editing_product['in_stock']); ?>. Enter amount to add.</small>
<?php endif; ?>
<!-- *** END MODIFICATION *** -->
<div class="form-buttons">
<button type="submit" name="save_product"><?php echo $editing_product ? 'Update Product' : 'Add Product'; ?></button>
<?php if ($editing_product): ?>
<a href="<?php echo remove_query_arg(array('action', 'id')); // Link to clear edit state ?>" class="button-cancel">Cancel Edit</a>
<?php endif; ?>
</div>
</form>
</div>
<div class="product-list-container">
<h2>Product List</h2>
<form method="GET">
<div class="product-search-wrapper">
<input type="text" id="product-search" class="product-search-bar" name="product_search"
placeholder="Search products..." value="<?php echo esc_attr($search_term); ?>">
<?php if (!empty($search_term)): ?>
<button type="submit" class="product-search-clear"
onclick="this.form.product_search.value = ''; this.form.submit(); return false;">
×
</button>
<?php endif; ?>
</div>
</form>
<table id="product-table">
<thead>
<tr>
<th>No.</th>
<th>Image</th>
<th>Product Name</th>
<th>Category</th>
<th>Unit</th>
<th>In-Stock</th>
<th>Buying Price</th>
<th>Selling Price</th>
<th>Date Created</th>
<th>Date Updated</th>
<th>Action</th>
</tr>
</thead>
<tbody id="product-table-body">
<?php if (empty($products)): ?>
<tr><td colspan="11" style="text-align: center;">
<?php echo !empty($search_term) ? 'No products match your search.' : 'No products added yet.'; ?>
</td></tr>
<?php else: ?>
<?php $i = 1; foreach ($products as $product):
$edit_url = add_query_arg(['action' => 'edit_product', 'id' => $product['id']], get_permalink());
$delete_url = add_query_arg([
'action' => 'delete_product',
'id' => $product['id'],
'_wpnonce' => wp_create_nonce('delete_product_' . $product['id'])
], get_permalink());
?>
<tr>
<td><?php echo $i++; ?></td>
<td>
<?php if ($product['image_url']): ?>
<img src="<?php echo esc_url($product['image_url']); ?>" alt="<?php echo esc_attr($product['name']); ?>" />
<?php else: ?>
<span style="color: #999; font-size: 0.9em;">No Image</span>
<?php endif; ?>
</td>
<td><?php echo esc_html($product['name']); ?></td>
<td><?php echo esc_html($product['category']); ?></td>
<td><?php echo esc_html($product['unit']); ?></td>
<td><?php echo esc_html($product['in_stock']); ?></td>
<td><?php echo number_format_i18n((float)$product['buying_price'], 2); ?></td>
<td><?php echo number_format_i18n((float)$product['selling_price'], 2); ?></td>
<td><?php echo esc_html(mysql2date(get_option('date_format'), $product['created_at'])); ?></td>
<td><?php echo esc_html(mysql2date(get_option('date_format'), $product['updated_at'])); ?></td>
<td class="product-actions">
<a href="<?php echo esc_url($edit_url); ?>" class="edit"><i class="fas fa-edit"></i> Edit</a>
<a href="<?php echo esc_url($delete_url); ?>" class="delete" onclick="return confirm('Are you sure you want to delete this product: <?php echo esc_js($product['name']); ?>?')"><i class="fas fa-trash-alt"></i> Delete</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</section>
</main>
</div>
<!-- JavaScript for Clear Button (No changes needed here from previous version) -->
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log("Clear Button Script: DOM Loaded");
// --- Clear Search Button Logic ---
const searchInput = document.getElementById('product-search');
const clearButton = document.getElementById('clear-search-btn');
if (searchInput && clearButton) {
console.log("Clear Button Script: Elements found.");
// Function to show/hide clear button
const toggleClearButton = () => {
// Use 'inline-block' to show it next to text
clearButton.style.display = searchInput.value.trim() !== '' ? 'inline-block' : 'none';
};
// Show/hide button based on input changes
searchInput.addEventListener('input', toggleClearButton);
console.log("Clear Button Script: 'input' listener attached.");
// Handle clear button click
clearButton.addEventListener('click', function(event) {
console.log("Clear Button Script: Click event triggered on button.");
event.preventDefault(); // Prevent any default button behavior
searchInput.value = ''; // Clear the input field visually
clearButton.style.display = 'none'; // Hide the button immediately
console.log("Clear Button Script: Input cleared and button hidden.");
try {
const currentHref = window.location.href;
console.log("Clear Button Script: Current href:", currentHref);
const currentUrl = new URL(currentHref);
console.log("Clear Button Script: Original URL object created:", currentUrl.toString());
currentUrl.searchParams.delete('product_search'); // Remove the specific parameter
const newUrlString = currentUrl.toString();
console.log("Clear Button Script: New URL string:", newUrlString);
// Redirect to the cleaned URL
window.location.href = newUrlString;
console.log("Clear Button Script: Redirect initiated to:", newUrlString);
} catch (error) {
console.error("Clear Button Script: Error during URL manipulation or redirect:", error);
// Provide feedback if redirect fails
alert("An error occurred while trying to clear the search. Please check the console (F12) and reload the page manually.");
}
});
console.log("Clear Button Script: 'click' listener attached.");
// Initial check in case the page loaded with a search term
toggleClearButton();
console.log("Clear Button Script: Initial button state set.");
} else {
if (!searchInput) console.error("Clear Button Script: Could not find search input #product-search.");
if (!clearButton) console.error("Clear Button Script: Could not find clear button #clear-search-btn.");
}
// --- End Clear Search Button Logic ---
console.log("Clear Button Script: Setup Complete.");
});
</script>
</body>
</html>
<?php
// End of PHP Snippet
?>