I am getting these two session start errors on my site and I have done everything to fix but they persist.
[26-May-2025 03:30:02 UTC] PHP Warning: session_start(): Session cannot be started after headers have already been sent in /home/u402881756/domains/realrender3d.app/public_html/books/wp-content/plugins/custom-books/includes/form-handler.php on line 5
[26-May-2025 03:30:02 UTC] PHP Warning: session_start(): Session cannot be started after headers have already been sent in /home/u402881756/domains/realrender3d.app/public_html/books/wp-content/plugins/custom-books/book-personalizer.php on line 12
Here is my main plugin file:
<?php
/**
* Plugin Name: Custom Book Personalizer
* Description: A plugin for personalizing children's books.
* Version: 1.0
* Author: Nastin Gwaza
*/
if (!defined('ABSPATH')) exit; // Exit if accessed directly
add_action('plugins_loaded', function () {
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
}, 1); // Run very early
// ✅ Plugin constants
define('BP_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('BP_PLUGIN_URL', plugin_dir_url(__FILE__));
// ✅ Load includes
$includes = [
BP_PLUGIN_DIR . 'includes/scripts.php',
BP_PLUGIN_DIR . 'includes/admin-product-meta.php',
BP_PLUGIN_DIR . 'includes/woocommerce-hooks.php',
BP_PLUGIN_DIR . 'includes/settings.php',
BP_PLUGIN_DIR . 'includes/face-swap-handler.php', // Added AI image generator
];
foreach ($includes as $file) {
if (file_exists($file)) {
require_once $file;
}
}
// ✅ Preview page shortcode
add_shortcode('book_preview_page', function () {
ob_start();
include BP_PLUGIN_DIR . 'includes/shortcode-preview-page.php';
return ob_get_clean();
});
// ✅ Personalization form shortcode with product_id handling
function bp_render_personalization_page($atts) {
$atts = shortcode_atts([
'product_id' => get_the_ID()
], $atts);
$product_id = intval($atts['product_id']);
ob_start();
include BP_PLUGIN_DIR . 'includes/personalization-page.php';
return ob_get_clean();
}
function bp_register_shortcodes_after_wc_loaded() {
if (function_exists('wc_get_product')) {
add_shortcode('book_personalizer', 'bp_render_personalization_page');
}
}
add_action('init', 'bp_register_shortcodes_after_wc_loaded');
// ✅ Hook form submission
add_action('admin_post_bp_handle_form', 'bp_handle_form_submission');
add_action('admin_post_nopriv_bp_handle_form', 'bp_handle_form_submission');
add_action('admin_post_bp_add_to_cart', 'bp_add_to_cart_from_preview');
add_action('admin_post_nopriv_bp_add_to_cart', 'bp_add_to_cart_from_preview');
require_once BP_PLUGIN_DIR . 'includes/form-handler.php';
// 1. Add personalization data to cart item
add_filter('woocommerce_add_cart_item_data', function($cart_item_data, $product_id, $variation_id) {
if (isset($_POST['personalization_data'])) {
$cart_item_data['personalization_data'] = json_decode(stripslashes($_POST['personalization_data']), true);
$cart_item_data['unique_key'] = md5(microtime().rand()); // Prevent merging similar items
}
return $cart_item_data;
}, 10, 3);
// 2. Show personalization on cart and checkout
add_filter('woocommerce_get_item_data', function($item_data, $cart_item) {
if (isset($cart_item['personalization_data'])) {
$pdata = $cart_item['personalization_data'];
if (!empty($pdata['child_name'])) {
$item_data[] = [
'key' => 'Child's Name',
'value' => sanitize_text_field($pdata['child_name']),
];
}
if (!empty($pdata['age_group'])) {
$item_data[] = [
'key' => 'Age Group',
'value' => sanitize_text_field($pdata['age_group']),
];
}
if (!empty($pdata['gender'])) {
$item_data[] = [
'key' => 'Gender',
'value' => sanitize_text_field($pdata['gender']),
];
}
}
return $item_data;
}, 10, 2);
// 3. Save personalization in order meta
add_action('woocommerce_add_order_item_meta', function($item_id, $values) {
if (!empty($values['personalization_data'])) {
wc_add_order_item_meta($item_id, 'Personalization Details', $values['personalization_data']);
}
}, 10, 2);
and here is my form-handler.php file:
<?php
defined('ABSPATH') || exit;
if (!session_id()) {
session_start();
}
add_action('admin_post_nopriv_bp_handle_form_submission', 'bp_handle_form_submission');
add_action('admin_post_bp_handle_form_submission', 'bp_handle_form_submission');
function bp_handle_form_submission() {
if (!isset($_POST['bp_personalize_nonce']) || !wp_verify_nonce($_POST['bp_personalize_nonce'], 'bp_personalize_action')) {
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
wp_redirect(home_url('/personalize-book?error=invalid_nonce&product_id=' . $product_id));
exit;
}
$required_fields = ['product_id', 'child_name', 'age_group', 'gender', 'birth_month', 'relation'];
foreach ($required_fields as $field) {
if (empty($_POST[$field])) {
$product_id = isset($_POST['product_id']) ? intval($_POST['product_id']) : 0;
wp_redirect(home_url('/personalize-book?error=missing_fields&product_id=' . $product_id));
exit;
}
}
$product_id = intval($_POST['product_id']);
$product = wc_get_product($product_id);
if (!$product) {
wp_redirect(home_url('/personalize-book?error=invalid_input&product_id=' . $product_id));
exit;
}
$child_image_url = '';
if (!empty($_FILES['child_image']['tmp_name'])) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
$uploaded = media_handle_upload('child_image', 0);
if (is_wp_error($uploaded)) {
wp_redirect(home_url('/personalize-book?error=image_upload&product_id=' . $product_id));
exit;
} else {
$child_image_url = wp_get_attachment_url($uploaded);
}
}
$_SESSION['bp_personalization'] = [
'product_id' => $product_id,
'child_name' => sanitize_text_field($_POST['child_name']),
'age_group' => sanitize_text_field($_POST['age_group']),
'gender' => sanitize_text_field($_POST['gender']),
'birth_month' => sanitize_text_field($_POST['birth_month']),
'relation' => sanitize_text_field($_POST['relation']),
'child_image_url' => esc_url_raw($child_image_url),
];
// Redirect to face swap handler (or preview page)
wp_safe_redirect(admin_url('admin-post.php?action=bp_handle_face_swap'));
exit;
}
Did I leave any white space anywhere?