DEV Community

Shahibur Rahman
Shahibur Rahman

Posted on

Building a Secure Home Search Wizard with WordPress REST API

In this tutorial, I'll walk through creating a complete home style search wizard for a construction company website using WordPress REST API. This solution handles form submissions, file uploads, email notifications, and includes proper security measures.

Overview

We'll build:

A multi-step search wizard frontend

Secure REST API endpoints

File upload handling

Email notification system

Comprehensive logging

Step 1: Setting Up the REST API Endpoint

First, we register our custom endpoint:

add_action('rest_api_init', function () {
    register_rest_route('fox-api/v1', '/send-search-data', [
        'methods' => 'POST',
        'callback' => 'handle_search_data',
        'permission_callback' => function($request) {
            $nonce = $request->get_header('X-WP-Nonce');
            return wp_verify_nonce($nonce, 'wp_rest');
        }
    ]);
});
Enter fullscreen mode Exit fullscreen mode

Key security features:

Nonce verification for all requests

Proper route namespace (fox-api/v1)

POST method only

Step 2: Handling Form Submissions

Our handler function processes the data:

function handle_search_data(WP_REST_Request $request) {
    try {
        // Verify nonce
        if (!wp_verify_nonce($request->get_header('X-WP-Nonce'), 'wp_rest')) {
            return new WP_REST_Response(['error' => 'Invalid token'], 403);
        }

        $data = $request->get_params();
        $files = $request->get_file_params();

        // Process data and files...

        return new WP_REST_Response(['success' => true]);
    } catch (Exception $e) {
        return new WP_REST_Response(['error' => $e->getMessage()], 500);
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 3: File Upload Handling

Secure file upload implementation:

if (!empty($files['survey_file'])) {
    require_once(ABSPATH . 'wp-admin/includes/file.php');

    $upload = wp_handle_upload($files['survey_file'], [
        'test_form' => false,
        'mimes' => [
            'pdf' => 'application/pdf',
            'dwg' => 'application/acad',
            'dxf' => 'application/dxf',
            'jpg|jpeg' => 'image/jpeg',
            'png' => 'image/png'
        ]
    ]);

    if ($upload && !isset($upload['error'])) {
        // Create attachment post
        $attachment_id = wp_insert_attachment([
            'post_mime_type' => $upload['type'],
            'post_title' => sanitize_file_name($files['survey_file']['name']),
            'post_status' => 'inherit'
        ], $upload['file']);
    }
}
Enter fullscreen mode Exit fullscreen mode

Key points:

Uses WordPress's secure file handling

Restricts allowed file types

Creates proper media library attachments

Step 4: Email Notifications

Here's our email function:

function send_data_to_email($submission_data) {
    $to = get_option('admin_email');
    $subject = 'New Home Style Search Submission';

    $body = "<h2>New Submission Details</h2>";
    $body .= "<p><strong>Date:</strong> " . date('F j, Y g:i a') . "</p>";

    // Build email content from submission data
    foreach ($submission_data as $section => $values) {
        $body .= "<h3>" . ucfirst($section) . "</h3>";
        if (is_array($values)) {
            $body .= "<ul>";
            foreach ($values as $value) {
                $body .= "<li>" . esc_html($value) . "</li>";
            }
            $body .= "</ul>";
        } else {
            $body .= "<p>" . esc_html($values) . "</p>";
        }
    }

    $headers = [
        'Content-Type: text/html; charset=UTF-8',
        'From: Website <noreply@' . $_SERVER['HTTP_HOST'] . '>'
    ];

    return wp_mail($to, $subject, $body, $headers);
}
Enter fullscreen mode Exit fullscreen mode

Features:

HTML formatted emails

Automatic content generation

Proper escaping of all output

Step 5: Frontend Implementation

JavaScript to handle the form submission:

async function submitForm() {
    const formData = new FormData();

    // Add form data
    formData.append('styles', JSON.stringify(selectedStyles));
    // Add other fields...

    try {
        const response = await fetch(foxApiSettings.root + 'fox-api/v1/send-search-data', {
            method: 'POST',
            headers: {
                'X-WP-Nonce': foxApiSettings.nonce
            },
            body: formData
        });

        if (!response.ok) throw new Error('Submission failed');
        const data = await response.json();

        // Handle success
    } catch (error) {
        console.error('Error:', error);
        // Show error to user
    }
}
Enter fullscreen mode Exit fullscreen mode

Security Considerations

Nonce Verification:

Required for all API requests

Prevents CSRF attacks

Works for both authenticated and non-authenticated users

Input Validation:

Validate all incoming data

Sanitize before processing

File Upload Security:

Restrict allowed file types

Use WordPress's built-in handlers

Store files outside web root when possible

Performance Optimizations

Logging System:

$log_dir = WP_CONTENT_DIR . '/fox-search-logs';
if (!file_exists($log_dir)) wp_mkdir_p($log_dir);

file_put_contents(
    $log_dir . '/search_' . date('Y-m-d') . '.log',
    print_r($data, true),
    FILE_APPEND
);
Enter fullscreen mode Exit fullscreen mode

Caching:

Cache API responses when appropriate

Consider transient for frequently accessed data

Conclusion

This implementation provides a complete solution for:

Multi-step form handling

Secure file uploads

Email notifications

Comprehensive logging

REST API best practices

The system is flexible enough to adapt to various use cases while maintaining security and performance standards.

Top comments (0)