v1.5.0: extend theme with navigation dropdowns, 9 page templates, auth UI, newsletter, contact panel
Major theme extension adding full-featured navigation with dropdown submenus (Tools, My Data, Resources), 9 new page templates (Calculator, Protocol Builder, Tracker, Subject Log, Documentation, Directory, Science Feed, Profile, Sign In/Register), documentation page with sidebar ToC and scroll spy, branded AJAX authentication forms, newsletter signup with admin export, slide-out contact/support panel, Research Modules 6-card grid on front page, and comprehensive footer update. Split functions.php (554→206 lines) into 6 focused inc/ modules: helpers, customizer, auth-handlers, contact-handler, page-setup, newsletter-admin. All new components include dark mode support, CSRF protection, input sanitization, output escaping, and graceful plugin degradation via shortcode_exists(). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
94
inc/contact-handler.php
Normal file
94
inc/contact-handler.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Contact Form AJAX Handler
|
||||
*
|
||||
* Processes the contact/support form from the settings panel.
|
||||
* Sends email via wp_mail() to the site admin.
|
||||
*
|
||||
* @see template-parts/settings-panel.php — renders the contact form
|
||||
* @see assets/js/settings-panel.js — submits form via XMLHttpRequest
|
||||
* @see functions.php — includes this file
|
||||
*
|
||||
* What: AJAX endpoint for the support contact form.
|
||||
* Who calls it: WordPress admin-ajax.php via settings-panel.js.
|
||||
* Dependencies: wp_mail() for email delivery.
|
||||
*
|
||||
* @package peptide-starter
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle AJAX contact form submission.
|
||||
*
|
||||
* Validates nonce, sanitizes all inputs, sends email to admin.
|
||||
* Works for both authenticated and unauthenticated users.
|
||||
*
|
||||
* @return void Sends JSON response and exits.
|
||||
*/
|
||||
function peptide_starter_ajax_contact() {
|
||||
// Verify CSRF nonce.
|
||||
if ( ! isset( $_POST['ps_contact_nonce'] ) ||
|
||||
! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['ps_contact_nonce'] ) ), 'ps_contact_form' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Security check failed. Please refresh and try again.', 'peptide-starter' ) ) );
|
||||
}
|
||||
|
||||
$name = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : '';
|
||||
$email = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : '';
|
||||
$topic = isset( $_POST['topic'] ) ? sanitize_text_field( wp_unslash( $_POST['topic'] ) ) : '';
|
||||
$message = isset( $_POST['message'] ) ? sanitize_textarea_field( wp_unslash( $_POST['message'] ) ) : '';
|
||||
|
||||
// Validate required fields.
|
||||
if ( empty( $name ) || empty( $email ) || empty( $topic ) || empty( $message ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'All fields are required.', 'peptide-starter' ) ) );
|
||||
}
|
||||
|
||||
if ( ! is_email( $email ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Please enter a valid email address.', 'peptide-starter' ) ) );
|
||||
}
|
||||
|
||||
// Allowed topics — reject anything unexpected.
|
||||
$allowed_topics = array( 'bug', 'feature', 'data', 'other' );
|
||||
if ( ! in_array( $topic, $allowed_topics, true ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Invalid topic selected.', 'peptide-starter' ) ) );
|
||||
}
|
||||
|
||||
// Build the email.
|
||||
$topic_labels = array(
|
||||
'bug' => __( 'Bug Report', 'peptide-starter' ),
|
||||
'feature' => __( 'Feature Request', 'peptide-starter' ),
|
||||
'data' => __( 'Data Correction', 'peptide-starter' ),
|
||||
'other' => __( 'Other', 'peptide-starter' ),
|
||||
);
|
||||
|
||||
$subject = sprintf(
|
||||
/* translators: 1: topic label, 2: sender name */
|
||||
__( '[Peptide Repo] %1$s from %2$s', 'peptide-starter' ),
|
||||
$topic_labels[ $topic ],
|
||||
$name
|
||||
);
|
||||
|
||||
$body = sprintf( __( 'Name: %s', 'peptide-starter' ), $name ) . "\n";
|
||||
$body .= sprintf( __( 'Email: %s', 'peptide-starter' ), $email ) . "\n";
|
||||
$body .= sprintf( __( 'Topic: %s', 'peptide-starter' ), $topic_labels[ $topic ] ) . "\n\n";
|
||||
$body .= __( 'Message:', 'peptide-starter' ) . "\n";
|
||||
$body .= $message;
|
||||
|
||||
$headers = array(
|
||||
'Reply-To: ' . $name . ' <' . $email . '>',
|
||||
'Content-Type: text/plain; charset=UTF-8',
|
||||
);
|
||||
|
||||
$sent = wp_mail( get_option( 'admin_email' ), $subject, $body, $headers );
|
||||
|
||||
if ( $sent ) {
|
||||
wp_send_json_success( array( 'message' => __( 'Message sent successfully. We will respond within 48 hours.', 'peptide-starter' ) ) );
|
||||
} else {
|
||||
wp_send_json_error( array( 'message' => __( 'Failed to send message. Please try again later.', 'peptide-starter' ) ) );
|
||||
}
|
||||
}
|
||||
add_action( 'wp_ajax_ps_contact_submit', 'peptide_starter_ajax_contact' );
|
||||
add_action( 'wp_ajax_nopriv_ps_contact_submit', 'peptide_starter_ajax_contact' );
|
||||
Reference in New Issue
Block a user