=== /catering-order-manager.php ===
<?php
/**
* Plugin Name: Catering Order Manager
* Plugin URI: https://example.com/plugins/catering-order-manager
* Description: Manage catering & restaurant orders from quotation -> payment -> delivery -> feedback.
* Version: 0.1.0
* Author: Generated by AI
* Author URI: https://example.com
* Text Domain: catering-order-manager
* Domain Path: /languages
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
define( 'COM_PLUGIN_VERSION', '0.1.0' );
define( 'COM_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'COM_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
// Autoload includes
require_once COM_PLUGIN_DIR . 'includes/class-com-activator.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-deactivator.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-quote.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-order.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-payments.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-feedback.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-admin.php';
require_once COM_PLUGIN_DIR . 'includes/class-com-frontend.php';
register_activation_hook( __FILE__, array( 'COM_Activator', 'activate' ) );
register_deactivation_hook( __FILE__, array( 'COM_Deactivator', 'deactivate' ) );
// Initialize plugin
add_action( 'plugins_loaded', function() {
// textdomain
load_plugin_textdomain( 'catering-order-manager', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
// Init core classes
COM_Admin::init();
COM_Frontend::init();
COM_Quote::init();
COM_Order::init();
COM_Payments::init();
COM_Feedback::init();
} );
// Enqueue assets
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_style( 'com-frontend', COM_PLUGIN_URL . 'assets/css/frontend.css', array(), COM_PLUGIN_VERSION );
wp_enqueue_script( 'com-frontend', COM_PLUGIN_URL . 'assets/js/frontend.js', array( 'jquery' ), COM_PLUGIN_VERSION, true );
wp_localize_script( 'com-frontend', 'com_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ) ) );
} );
add_action( 'admin_enqueue_scripts', function() {
wp_enqueue_style( 'com-admin', COM_PLUGIN_URL . 'assets/css/admin.css', array(), COM_PLUGIN_VERSION );
wp_enqueue_script( 'com-admin', COM_PLUGIN_URL . 'assets/js/admin.js', array( 'jquery' ), COM_PLUGIN_VERSION, true );
} );
?>
=== /includes/class-com-activator.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Activator {
public static function activate() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$quotes_table = $wpdb->prefix . 'com_quotes';
$orders_table = $wpdb->prefix . 'com_orders';
$feedback_table = $wpdb->prefix . 'com_feedback';
require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
$sql = "CREATE TABLE $quotes_table (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
customer_name varchar(200) NOT NULL,
customer_email varchar(200) NOT NULL,
details text NOT NULL,
items longtext NOT NULL,
total decimal(10,2) NOT NULL DEFAULT '0.00',
status varchar(50) NOT NULL DEFAULT 'pending',
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta( $sql );
$sql = "CREATE TABLE $orders_table (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
quote_id bigint(20) unsigned DEFAULT NULL,
customer_id bigint(20) unsigned DEFAULT NULL,
items longtext NOT NULL,
total decimal(10,2) NOT NULL DEFAULT '0.00',
status varchar(50) NOT NULL DEFAULT 'pending',
payment_status varchar(50) NOT NULL DEFAULT 'unpaid',
scheduled_date datetime DEFAULT NULL,
assigned_to bigint(20) unsigned DEFAULT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta( $sql );
$sql = "CREATE TABLE $feedback_table (
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
order_id bigint(20) unsigned NOT NULL,
customer_name varchar(200) DEFAULT NULL,
rating tinyint(1) DEFAULT NULL,
comment text DEFAULT NULL,
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
dbDelta( $sql );
// Save plugin version
add_option( 'com_plugin_version', COM_PLUGIN_VERSION );
}
}
?>
=== /includes/class-com-deactivator.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Deactivator {
public static function deactivate() {
// nothing for now; could clear scheduled events
}
}
?>
=== /includes/class-com-admin.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Admin {
public static function init() {
add_action( 'admin_menu', array( __CLASS__, 'register_menus' ) );
add_action( 'admin_post_com_export_csv', array( __CLASS__, 'export_csv' ) );
}
public static function register_menus() {
add_menu_page( 'Catering Orders', 'Catering Orders', 'manage_options', 'com-dashboard', array( __CLASS__, 'dashboard_page' ), 'dashicons-food', 56 );
add_submenu_page( 'com-dashboard', 'Quotes', 'Quotes', 'manage_options', 'com-quotes', array( __CLASS__, 'quotes_page' ) );
add_submenu_page( 'com-dashboard', 'Orders', 'Orders', 'manage_options', 'com-orders', array( __CLASS__, 'orders_page' ) );
add_submenu_page( 'com-dashboard', 'Feedback', 'Feedback', 'manage_options', 'com-feedback', array( __CLASS__, 'feedback_page' ) );
}
public static function dashboard_page() {
echo '<div class="wrap"><h1>Catering Order Manager</h1><p>Summary and stats coming soon.</p></div>';
}
public static function quotes_page() {
echo '<div class="wrap"><h1>Quotes</h1><p>Quotes list - implement table list here.</p></div>';
}
public static function orders_page() {
echo '<div class="wrap"><h1>Orders</h1><p>Orders list - implement table list here.</p></div>';
}
public static function feedback_page() {
echo '<div class="wrap"><h1>Feedback</h1><p>Feedback list - implement table list here.</p></div>';
}
public static function export_csv() {
// placeholder for CSV export
}
}
?>
=== /includes/class-com-frontend.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Frontend {
public static function init() {
add_shortcode( 'com_quote_form', array( __CLASS__, 'quote_form_shortcode' ) );
add_shortcode( 'com_customer_portal', array( __CLASS__, 'customer_portal_shortcode' ) );
add_action( 'wp_ajax_com_submit_quote', array( __CLASS__, 'ajax_submit_quote' ) );
add_action( 'wp_ajax_nopriv_com_submit_quote', array( __CLASS__, 'ajax_submit_quote' ) );
}
public static function quote_form_shortcode( $atts ) {
ob_start();
include COM_PLUGIN_DIR . 'templates/quote-form.php';
return ob_get_clean();
}
public static function customer_portal_shortcode( $atts ) {
ob_start();
include COM_PLUGIN_DIR . 'templates/customer-portal.php';
return ob_get_clean();
}
public static function ajax_submit_quote() {
check_ajax_referer( 'com-quote', 'security' );
$name = sanitize_text_field( $_POST['name'] ?? '' );
$email = sanitize_email( $_POST['email'] ?? '' );
$items = wp_kses_post( $_POST['items'] ?? '' );
$total = floatval( $_POST['total'] ?? 0 );
$details = wp_kses_post( $_POST['details'] ?? '' );
global $wpdb;
$table = $wpdb->prefix . 'com_quotes';
$wpdb->insert( $table, array(
'customer_name' => $name,
'customer_email' => $email,
'details' => $details,
'items' => maybe_serialize( $items ),
'total' => $total,
'status' => 'pending'
) );
// Notify admin
wp_mail( get_option( 'admin_email' ), 'New Quote Request', "New quote from $name ($email)" );
wp_send_json_success( array( 'message' => 'Quote submitted' ) );
}
}
?>
=== /includes/class-com-quote.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Quote {
public static function init() {
// Admin actions: approve, edit, convert to order
add_action( 'admin_post_com_convert_quote', array( __CLASS__, 'convert_to_order' ) );
}
public static function convert_to_order() {
// convert quote ID -> create order row
if ( empty( $_POST['quote_id'] ) ) wp_die( 'No quote id' );
$quote_id = intval( $_POST['quote_id'] );
global $wpdb;
$qtable = $wpdb->prefix . 'com_quotes';
$otable = $wpdb->prefix . 'com_orders';
$quote = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $qtable WHERE id = %d", $quote_id ) );
if ( ! $quote ) wp_die( 'Quote not found' );
$wpdb->insert( $otable, array(
'quote_id' => $quote->id,
'items' => $quote->items,
'total' => $quote->total,
'status' => 'confirmed',
'payment_status' => 'unpaid'
) );
$order_id = $wpdb->insert_id;
// update quote status
$wpdb->update( $qtable, array( 'status' => 'accepted' ), array( 'id' => $quote->id ) );
wp_redirect( admin_url( 'admin.php?page=com-orders&message=order_created&order_id=' . $order_id ) );
exit;
}
}
?>
=== /includes/class-com-order.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Order {
public static function init() {
// actions: change status, assign to staff, schedule
add_action( 'admin_post_com_update_order', array( __CLASS__, 'update_order' ) );
}
public static function update_order() {
// placeholder: update order fields
wp_redirect( admin_url( 'admin.php?page=com-orders' ) );
exit;
}
}
?>
=== /includes/class-com-payments.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Payments {
public static function init() {
// register payment endpoints and webhooks
add_action( 'init', array( __CLASS__, 'maybe_handle_return' ) );
}
public static function maybe_handle_return() {
// placeholder to receive gateway callbacks/webhooks
}
// Helpers for creating invoices (simple PDF placeholder)
public static function generate_invoice_pdf( $order_id ) {
// For production: integrate with a proper PDF library (e.g. mpdf)
$upload_dir = wp_upload_dir();
$file = $upload_dir['basedir'] . "/com-invoice-{$order_id}.txt";
file_put_contents( $file, "Invoice for order {$order_id}\n" );
return $file;
}
}
?>
=== /includes/class-com-feedback.php ===
<?php
if ( ! defined( 'ABSPATH' ) ) exit;
class COM_Feedback {
public static function init() {
add_action( 'wp_ajax_com_submit_feedback', array( __CLASS__, 'ajax_submit_feedback' ) );
add_action( 'wp_ajax_nopriv_com_submit_feedback', array( __CLASS__, 'ajax_submit_feedback' ) );
}
public static function ajax_submit_feedback() {
check_ajax_referer( 'com-feedback', 'security' );
$order_id = intval( $_POST['order_id'] ?? 0 );
$rating = intval( $_POST['rating'] ?? 0 );
$comment = sanitize_textarea_field( $_POST['comment'] ?? '' );
$name = sanitize_text_field( $_POST['name'] ?? '' );
if ( ! $order_id ) wp_send_json_error( array( 'message' => 'Order required' ) );
global $wpdb;
$table = $wpdb->prefix . 'com_feedback';
$wpdb->insert( $table, array( 'order_id' => $order_id, 'rating' => $rating, 'comment' => $comment, 'customer_name' => $name ) );
wp_send_json_success( array( 'message' => 'Thanks for your feedback' ) );
}
}
?>
=== /templates/quote-form.php ===
<?php
// Simple quote form example
?>
<form id="com-quote-form" method="post" action="">
<?php wp_nonce_field( 'com-quote', 'com_quote_nonce' ); ?>
<p><label>Your name<br/><input type="text" name="name" required></label></p>
<p><label>Email<br/><input type="email" name="email" required></label></p>
<p><label>Items (JSON or simple text)<br/><textarea name="items" required></textarea></label></p>
<p><label>Additional details<br/><textarea name="details"></textarea></label></p>
<p><label>Total estimate<br/><input type="number" step="0.01" name="total" required></label></p>
<p><button type="button" id="com-submit-quote">Request Quotation</button></p>
</form>
<script>
jQuery(document).ready(function($){
$('#com-submit-quote').on('click', function(){
var data = {
action: 'com_submit_quote',
security: $('input[name="com_quote_nonce"]').val(),
name: $('input[name="name"]').val(),
email: $('input[name="email"]').val(),
items: $('textarea[name="items"]').val(),
details: $('textarea[name="details"]').val(),
total: $('input[name="total"]').val()
};
$.post(com_ajax.ajax_url, data, function(resp){
if(resp.success) alert(resp.data.message);
else alert('Error');
});
});
});
</script>
=== /templates/customer-portal.php ===
<?php
if ( ! is_user_logged_in() ) {
echo '<p>Please <a href="' . wp_login_url( get_permalink() ) . '">login</a> to view your orders.</p>';
return;
}
$current_user = wp_get_current_user();
?>
<div class="com-customer-portal">
<h3>Welcome, <?php echo esc_html( $current_user->display_name ); ?></h3>
<p>List of quotes and orders will appear here (implement listing with queries).</p>
</div>
=== /assets/css/frontend.css ===
/* Basic styles - extend as needed */
.com-customer-portal{padding:20px;background:#fff;border:1px solid #eee}
=== /assets/js/frontend.js ===
// Placeholder frontend JS - extend as needed
=== /assets/css/admin.css ===
/* admin styles */
=== /assets/js/admin.js ===
// admin scripts