WP Manifestindependent plugin directory
manifest / utilities / neon-chess

Neon Chess

A neon-themed chess game with AI and multiplayer support

by Your Name · github.com/conjureganja/neon-chess

0stars
1forks

Install

No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:

wp plugin install https://github.com/conjureganja/neon-chess/archive/refs/heads/main.zip

A modern, neon-themed chess game built with vanilla JavaScript, featuring AI opponents and multiplayer support. This project can be integrated into any website, including WordPress sites using 2025 best practices.

Overview

Neon Chess is a standalone JavaScript chess engine with beautiful neon-themed styling. It includes:

  • Full chess game logic and move validation
  • AI opponent with adjustable difficulty levels
  • Neon-themed visual styling with multiple color schemes
  • User management capabilities
  • Online multiplayer framework
  • Responsive design for mobile and desktop

WordPress Integration Guide (2025 Best Practices)

This guide demonstrates how to properly integrate Neon Chess into a WordPress website in 2025 using modern WordPress development standards. This is NOT a plugin - it's a JavaScript application that you integrate directly into your WordPress theme or child theme.

Prerequisites

  • WordPress 6.4 or higher
  • PHP 8.0 or higher
  • Basic knowledge of WordPress theme development
  • Access to your theme's files (recommended: use a child theme)

This method integrates the chess game directly into your WordPress theme following WordPress Coding Standards and best practices for 2025.

Step 1: Add Game Files to Your Theme

  1. Create a dedicated directory in your theme for the chess game:

    mkdir -p wp-content/themes/your-theme/assets/neon-chess/js
    mkdir -p wp-content/themes/your-theme/assets/neon-chess/css
  2. Copy the game files:

    • Copy assets/js/neon-chess.js to wp-content/themes/your-theme/assets/neon-chess/js/
    • Copy assets/css/neon-chess.css to wp-content/themes/your-theme/assets/neon-chess/css/

Step 2: Enqueue Scripts and Styles Properly

In your theme's functions.php (or create a separate file and require it), add the following code to properly enqueue the chess game assets:

<?php
/**
 * Enqueue Neon Chess assets
 * Following WordPress 2025 best practices
 */
function neon_chess_enqueue_assets() {
    // Only load on pages that need the chess game
    if (is_page('chess') || is_page('play-chess') || has_shortcode(get_post()->post_content, 'neon_chess')) {

        // Enqueue CSS with proper versioning
        wp_enqueue_style(
            'neon-chess-styles',
            get_theme_file_uri('assets/neon-chess/css/neon-chess.css'),
            array(),
            filemtime(get_theme_file_path('assets/neon-chess/css/neon-chess.css')),
            'all'
        );

        // Enqueue JavaScript with proper dependencies
        wp_enqueue_script(
            'neon-chess-game',
            get_theme_file_uri('assets/neon-chess/js/neon-chess.js'),
            array(), // No jQuery dependency - vanilla JS
            filemtime(get_theme_file_path('assets/neon-chess/js/neon-chess.js')),
            true // Load in footer for better performance
        );

        // Pass WordPress data to JavaScript securely
        wp_localize_script('neon-chess-game', 'neonChessWP', array(
            'ajaxUrl' => esc_url(admin_url('admin-ajax.php')),
            'nonce' => wp_create_nonce('neon_chess_nonce'),
            'userId' => get_current_user_id(),
            'userName' => wp_get_current_user()->display_name,
            'isLoggedIn' => is_user_logged_in(),
            'restUrl' => esc_url_raw(rest_url('neon-chess/v1/')),
            'restNonce' => wp_create_nonce('wp_rest')
        ));
    }
}
add_action('wp_enqueue_scripts', 'neon_chess_enqueue_assets');

Important Notes:

  • Uses get_theme_file_uri() and get_theme_file_path() for child theme compatibility
  • filemtime() for cache-busting ensures users get updated files
  • Scripts load in footer for better performance
  • wp_localize_script() safely passes PHP data to JavaScript
  • Conditional loading only on pages that need the game

Step 3: Create a Shortcode for Easy Embedding

Add this shortcode function to your functions.php:

<?php
/**
 * Neon Chess shortcode
 * Usage: [neon_chess theme="blue-pink" ai_level="medium"]
 */
function neon_chess_shortcode($atts) {
    // Parse attributes with defaults
    $atts = shortcode_atts(array(
        'theme' => 'blue-pink',
        'ai_level' => 'medium',
        'width' => '100%',
        'height' => 'auto',
    ), $atts, 'neon_chess');

    // Sanitize attributes
    $theme = sanitize_text_field($atts['theme']);
    $ai_level = sanitize_text_field($atts['ai_level']);
    $width = sanitize_text_field($atts['width']);
    $height = sanitize_text_field($atts['height']);

    // Build the output HTML
    ob_start();
    ?>
    <div id="neon-chess-container" 
         class="neon-chess-wrapper"
         data-theme="<?php echo esc_attr($theme); ?>" 
         data-ai-level="<?php echo esc_attr($ai_level); ?>"
         style="width: <?php echo esc_attr($width); ?>; height: <?php echo esc_attr($height); ?>;">
    </div>
    <script>
    document.addEventListener('DOMContentLoaded', function() {
        const container = document.getElementById('neon-chess-container');
        if (container && typeof Game !== 'undefined') {
            const theme = container.dataset.theme;
            const aiLevel = container.dataset.aiLevel;

            let difficulty = window.DIFFICULTY ? window.DIFFICULTY.MEDIUM : 2;
            if (window.DIFFICULTY) {
                switch(aiLevel) {
                    case 'easy': difficulty = window.DIFFICULTY.EASY; break;
                    case 'hard': difficulty = window.DIFFICULTY.HARD; break;
                    case 'master': difficulty = window.DIFFICULTY.MASTER; break;
                }
            }

            const game = new Game({
                gameMode: 'player-vs-ai',
                aiDifficulty: difficulty,
                theme: window.THEMES && window.THEMES[theme.toUpperCase().replace('-', '_')] || theme
            });

            game.initialize(container);
        }
    });
    </script>
    <?php
    return ob_get_clean();
}
add_shortcode('neon_chess', 'neon_chess_shortcode');

Step 4: Using the Shortcode

Add the chess game to any page or post using the shortcode:

[neon_chess theme="blue-pink" ai_level="medium"]

Available parameters:

  • theme: "blue-pink", "green-yellow", "purple-orange", or "custom"
  • ai_level: "easy", "medium", "hard", or "master"
  • width: Any valid CSS width (e.g., "100%", "800px")
  • height: Any valid CSS height (e.g., "auto", "600px")

Method 2: Gutenberg Block Integration (Modern Approach)

For sites using the Block Editor (Gutenberg), create a custom block for better integration.

Step 1: Register the Block

Create a new file: wp-content/themes/your-theme/blocks/neon-chess-block.php

<?php
/**
 * Register Neon Chess Gutenberg Block
 * WordPress 2025 Block API
 */
function neon_chess_register_block() {
    // Register block script
    wp_register_script(
        'neon-chess-block-editor',
        get_theme_file_uri('assets/neon-chess/js/block-editor.js'),
        array('wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n'),
        filemtime(get_theme_file_path('assets/neon-chess/js/block-editor.js')),
        true
    );

    // Register the block
    register_block_type('neon-chess/game-block', array(
        'editor_script' => 'neon-chess-block-editor',
        'render_callback' => 'neon_chess_block_render',
        'attributes' => array(
            'theme' => array(
                'type' => 'string',
                'default' => 'blue-pink',
            ),
            'aiLevel' => array(
                'type' => 'string',
                'default' => 'medium',
            ),
        ),
    ));
}
add_action('init', 'neon_chess_register_block');

/**
 * Render callback for the block
 */
function neon_chess_block_render($attributes) {
    $theme = isset($attributes['theme']) ? sanitize_text_field($attributes['theme']) : 'blue-pink';
    $ai_level = isset($attributes['aiLevel']) ? sanitize_text_field($attributes['aiLevel']) : 'medium';

    return neon_chess_shortcode(array(
        'theme' => $theme,
        'ai_level' => $ai_level,
    ));
}

Step 2: Add Block Editor JavaScript

Create: wp-content/themes/your-theme/assets/neon-chess/js/block-editor.js

(function(blocks, element, blockEditor, components, i18n) {
    const el = element.createElement;
    const __ = i18n.__;

    blocks.registerBlockType('neon-chess/game-block', {
        title: __('Neon Chess Game', 'your-theme'),
        icon: 'games',
        category: 'widgets',
        attributes: {
            theme: {
                type: 'string',
                default: 'blue-pink'
            },
            aiLevel: {
                type: 'string',
                default: 'medium'
            }
        },

        edit: function(props) {
            const { attributes, setAttributes } = props;

            return el('div', { className: 'neon-chess-block-editor' },
                el(components.PanelBody, { title: __('Game Settings', 'your-theme') },
                    el(components.SelectControl, {
                        label: __('Theme', 'your-theme'),
                        value: attributes.theme,
                        options: [
                            { label: 'Blue-Pink', value: 'blue-pink' },
                            { label: 'Green-Yellow', value: 'green-yellow' },
                            { label: 'Purple-Orange', value: 'purple-orange' }
                        ],
                        onChange: function(value) {
                            setAttributes({ theme: value });
                        }
                    }),
                    el(components.SelectControl, {
                        label: __('AI Level', 'your-theme'),
                        value: attributes.aiLevel,
                        options: [
                            { label: 'Easy', value: 'easy' },
                            { label: 'Medium', value: 'medium' },
                            { label: 'Hard', value: 'hard' },
                            { label: 'Master', value: 'master' }
                        ],
                        onChange: function(value) {
                            setAttributes({ aiLevel: value });
                        }
                    })
                ),
                el('div', { 
                    className: 'neon-chess-placeholder',
                    style: { padding: '20px', background: '#f0f0f0', textAlign: 'center' }
                }, __('Neon Chess Game - Preview in frontend', 'your-theme'))
            );
        },

        save: function() {
            return null; // Dynamic block - rendered via PHP
        }
    });
})(
    window.wp.blocks,
    window.wp.element,
    window.wp.blockEditor,
    window.wp.components,
    window.wp.i18n
);

Method 3: WordPress REST API Integration

For advanced features like saving game state and user statistics, integrate with WordPress REST API.

Step 1: Register Custom REST Endpoints

Add to your functions.php:

<?php
/**
 * Register custom REST API endpoints for Neon Chess
 * WordPress 2025 REST API best practices
 */
function neon_chess_register_rest_routes() {
    register_rest_route('neon-chess/v1', '/save-game', array(
        'methods' => 'POST',
        'callback' => 'neon_chess_save_game',
        'permission_callback' => 'is_user_logged_in',
        'args' => array(
            'game_state' => array(
                'required' => true,
                'validate_callback' => function($param) {
                    return is_string($param);
                },
                'sanitize_callback' => 'sanitize_textarea_field',
            ),
        ),
    ));

    register_rest_route('neon-chess/v1', '/load-game', array(
        'methods' => 'GET',
        'callback' => 'neon_chess_load_game',
        'permission_callback' => 'is_user_logged_in',
    ));

    register_rest_route('neon-chess/v1', '/save-stats', array(
        'methods' => 'POST',
        'callback' => 'neon_chess_save_stats',
        'permission_callback' => 'is_user_logged_in',
        'args' => array(
            'result' => array(
                'required' => true,
                'enum' => array('win', 'loss', 'draw'),
            ),
            'opponent_type' => array(
                'required' => true,
                'enum' => array('ai', 'human'),
            ),
        ),
    ));
}
add_action('rest_api_init', 'neon_chess_register_rest_routes');

/**
 * Save game state to user meta
 */
function neon_chess_save_game(WP_REST_Request $request) {
    $user_id = get_current_user_id();
    $game_state = $request->get_param('game_state');

    // Verify nonce for security
    if (!wp_verify_nonce($request->get_header('X-WP-Nonce'), 'wp_rest')) {
        return new WP_Error('invalid_nonce', 'Invalid security token', array('status' => 403));
    }

    $saved = update_user_meta($user_id, 'neon_chess_saved_game', $game_state);

    if ($saved !== false) {
        return new WP_REST_Response(array(
            'success' => true,
            'message' => 'Game saved successfully',
        ), 200);
    }

    return new WP_Error('save_failed', 'Failed to save game', array('status' => 500));
}

/**
 * Load game state from user meta
 */
function neon_chess_load_game(WP_REST_Request $request) {
    $user_id = get_current_user_id();
    $game_state = get_user_meta($user_id, 'neon_chess_saved_game', true);

    return new WP_REST_Response(array(
        'success' => true,
        'game_state' => $game_state ?: null,
    ), 200);
}

/**
 * Save game statistics
 */
function neon_chess_save_stats(WP_REST_Request $request) {
    $user_id = get_current_user_id();
    $result = $request->get_param('result');
    $opponent_type = $request->get_param('opponent_type');

    // Get current stats
    $stats = get_user_meta($user_id, 'neon_chess_stats', true);
    if (!is_array($stats)) {
        $stats = array('wins' => 0, 'losses' => 0, 'draws' => 0);
    }

    // Update stats
    if ($result === 'win') {
        $stats['wins']++;
    } elseif ($result === 'loss') {
        $stats['losses']++;
    } else {
        $stats['draws']++;
    }

    update_user_meta($user_id, 'neon_chess_stats', $stats);

    return new WP_REST_Response(array(
        'success' => true,
        'stats' => $stats,
    ), 200);
}

Step 2: Call REST API from JavaScript

Modify your game initialization to use the REST API:

// Save game state
async function saveGame(gameState) {
    try {
        const response = await fetch(neonChessWP.restUrl + 'save-game', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                'X-WP-Nonce': neonChessWP.restNonce
            },
            body: JSON.stringify({
                game_state: JSON.stringify(gameState)
            })
        });

        const data = await response.json();
        return data.success;
    } catch (error) {
        console.error('Failed to save game:', error);
        return false;
    }
}

// Load game state
async function loadGame() {
    try {
        const response = await fetch(neonChessWP.restUrl + 'load-game', {
            headers: {
                'X-WP-Nonce': neonChessWP.restNonce
            }
        });

        const data = await response.json();
        return data.game_state ? JSON.parse(data.game_state) : null;
    } catch (error) {
        console.error('Failed to load game:', error);
        return null;
    }
}

Security Best Practices (2025 Standards)

1. Always Sanitize and Escape Output

// Sanitize input
$theme = sanitize_text_field($_POST['theme']);
$user_input = sanitize_textarea_field($_POST['comment']);

// Escape output
echo esc_html($user_name);
echo esc_attr($theme);
echo esc_url($game_url);

2. Use Nonces for All Forms and AJAX

// Generate nonce
$nonce = wp_create_nonce('neon_chess_action');

// Verify nonce
if (!wp_verify_nonce($_POST['nonce'], 'neon_chess_action')) {
    wp_die('Security check failed');
}

3. Check User Capabilities

// Check if user can perform action
if (!current_user_can('edit_posts')) {
    wp_die('You do not have permission to do this');
}

4. Validate and Sanitize REST API Input

// Use built-in validation
'args' => array(
    'game_state' => array(
        'required' => true,
        'validate_callback' => function($param) {
            return is_string($param) && strlen($param) < 10000;
        },
        'sanitize_callback' => 'sanitize_textarea_field',
    ),
),

Performance Optimization

1. Conditional Loading

Only load assets on pages that need them:

function neon_chess_enqueue_assets() {
    // Only on specific pages
    if (is_page('chess') || has_shortcode(get_post()->post_content, 'neon_chess')) {
        wp_enqueue_script('neon-chess-game');
    }
}

2. Defer JavaScript Loading

function neon_chess_defer_scripts($tag, $handle) {
    if ('neon-chess-game' === $handle) {
        return str_replace(' src', ' defer src', $tag);
    }
    return $tag;
}
add_filter('script_loader_tag', 'neon_chess_defer_scripts', 10, 2);

3. Minimize HTTP Requests

  • Combine CSS files when possible
  • Use sprite sheets for images
  • Enable browser caching with proper headers

4. Use Object Caching

function neon_chess_get_leaderboard() {
    $cache_key = 'neon_chess_leaderboard';
    $leaderboard = wp_cache_get($cache_key);

    if (false === $leaderboard) {
        // Expensive database query
        $leaderboard = /* ... fetch from database ... */;
        wp_cache_set($cache_key, $leaderboard, '', 3600); // Cache for 1 hour
    }

    return $leaderboard;
}

Accessibility (a11y) Best Practices

1. Keyboard Navigation

Ensure all game controls are keyboard accessible:

// Add keyboard event listeners
document.addEventListener('keydown', function(e) {
    if (e.key === 'Tab') {
        // Handle tab navigation
    }
    if (e.key === 'Enter' || e.key === ' ') {
        // Activate selected piece/square
    }
});

2. ARIA Labels and Roles

<div id="chess-board" 
     role="application" 
     aria-label="Chess game board">
    <div class="square" 
         role="button" 
         tabindex="0"
         aria-label="Square A1, White Rook">
    </div>
</div>

3. Screen Reader Support

Announce game moves and states:

function announceMove(move) {
    const announcement = document.createElement('div');
    announcement.className = 'sr-only';
    announcement.setAttribute('role', 'status');
    announcement.setAttribute('aria-live', 'polite');
    announcement.textContent = `${move.piece} moves from ${move.from} to ${move.to}`;
    document.body.appendChild(announcement);

    setTimeout(() => announcement.remove(), 1000);
}

4. Color Contrast

Ensure sufficient color contrast for users with visual impairments:

/* WCAG AAA compliant contrast ratios */
.chess-square.light {
    background: #f0d9b5; /* Contrast ratio: 4.5:1 minimum */
}

.chess-square.dark {
    background: #b58863;
}

Responsive Design

Mobile-First Approach

/* Base styles for mobile */
.neon-chess-wrapper {
    width: 100%;
    max-width: 100vw;
    padding: 10px;
}

/* Tablet and up */
@media (min-width: 768px) {
    .neon-chess-wrapper {
        max-width: 600px;
        margin: 0 auto;
    }
}

/* Desktop */
@media (min-width: 1024px) {
    .neon-chess-wrapper {
        max-width: 800px;
    }
}

Touch-Friendly Controls

// Support both mouse and touch events
element.addEventListener('click', handleSquareClick);
element.addEventListener('touchstart', handleSquareTouch, { passive: true });

Testing and Debugging

1. Enable WordPress Debug Mode

In wp-config.php:

define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
define('SCRIPT_DEBUG', true); // Use non-minified scripts

2. Browser Console Testing

// Check if WordPress data is available
console.log('WordPress Data:', neonChessWP);

// Test game initialization
if (typeof Game === 'undefined') {
    console.error('Game class not loaded!');
}

3. REST API Testing

Use tools like Postman or browser DevTools to test your REST endpoints:

# Test save game endpoint
curl -X POST https://yoursite.com/wp-json/neon-chess/v1/save-game \
  -H "X-WP-Nonce: YOUR_NONCE" \
  -H "Content-Type: application/json" \
  -d '{"game_state":"..."}'

Multisite Compatibility

For WordPress Multisite installations:

function neon_chess_network_activate() {
    global $wpdb;

    // Get all blog ids
    $blog_ids = $wpdb->get_col("SELECT blog_id FROM $wpdb->blogs");

    foreach ($blog_ids as $blog_id) {
        switch_to_blog($blog_id);
        // Activation code for each site
        neon_chess_single_activate();
        restore_current_blog();
    }
}
register_activation_hook(__FILE__, 'neon_chess_network_activate');

Internationalization (i18n)

Make your chess game translation-ready:

// In functions.php
function neon_chess_load_textdomain() {
    load_theme_textdomain('your-theme', get_template_directory() . '/languages');
}
add_action('after_setup_theme', 'neon_chess_load_textdomain');

// Use translation functions
echo esc_html__('New Game', 'your-theme');
esc_html_e('Your Move', 'your-theme');
printf(esc_html__('Time remaining: %s', 'your-theme'), $time);

Troubleshooting Common Issues

Issue 1: Scripts Not Loading

Solution: Check file paths and ensure files exist

// Debug script paths
error_log('Chess JS Path: ' . get_theme_file_path('assets/neon-chess/js/neon-chess.js'));
error_log('File exists: ' . (file_exists(get_theme_file_path('assets/neon-chess/js/neon-chess.js')) ? 'Yes' : 'No'));

Issue 2: CORS Errors with REST API

Solution: Ensure proper headers are set

function neon_chess_cors_headers() {
    header('Access-Control-Allow-Origin: ' . get_site_url());
    header('Access-Control-Allow-Credentials: true');
}
add_action('rest_api_init', 'neon_chess_cors_headers');

Issue 3: Styles Conflicting with Theme

Solution: Add specificity and use CSS isolation

/* Increase specificity */
.neon-chess-wrapper .chess-board {
    /* Your styles */
}

/* Or use CSS custom properties for easy theming */
.neon-chess-wrapper {
    --board-bg: #1a1a1a;
    --piece-color: #00ffff;
}

Support and Contributing

  • Issues: Report bugs on GitHub Issues
  • Documentation: Full documentation at project repository
  • Contributing: Pull requests are welcome! Please follow WordPress Coding Standards

License

This project follows standard open-source licensing. Check the repository for specific license details.

Changelog

Version 1.0.0

  • Initial release with core chess functionality
  • AI opponent with multiple difficulty levels
  • Neon-themed styling
  • WordPress integration guide for 2025 best practices