VOOZH about

URL: https://deepwiki.com/pcescato/ajc-bridge/5.2-settings-page

⇱ Settings Page | pcescato/ajc-bridge | DeepWiki


Loading...
Menu

Settings Page

This document covers the Settings class, which manages the plugin's configuration interface, secure credential storage, and tabbed settings organization. The Settings page provides a two-tab interface (General and Credentials) for configuring publishing strategies, SSG types, API credentials, and system behavior.

For information about how settings are consumed during synchronization, see Sync Runner. For admin menu coordination, see Admin Coordination. For per-post syndication controls, see Post Meta Box.


Architecture Overview

The Settings class serves as the configuration hub for the entire plugin, providing user-facing forms for all system parameters while implementing secure storage mechanisms for sensitive credentials.

Settings Component in System Context


Sources: admin/class-settings.php24-56 admin/class-settings.php154-349


Tabbed Interface Implementation

The Settings page uses a two-tab architecture to organize configuration options by category: General settings (strategy, SSG configuration) and Credentials (API tokens).

Tab State Management


Sources: admin/class-settings.php122-147 admin/class-settings.php164-349

Tab-Aware Field Registration

The register_settings() method conditionally registers settings sections based on the active tab, preventing unnecessary field processing:

TabSections RegisteredFields Included
generalajc_bridge_posttypes_section
ajc_bridge_ssg_section
ajc_bridge_debug_section
enabled_post_types, publishing_strategy, github_site_url, devto_site_url, ssg_type, hugo_content_dir, astro_content_dir, debug_mode, delete_data_on_uninstall
credentialsajc_bridge_github_section
ajc_bridge_devto_section
github_repo, github_branch, github_token, devto_api_key

Sources: admin/class-settings.php164-349

The conditional registration logic:


Sources: admin/class-settings.php166-349


Settings Sanitization and Merge Logic

The sanitize_settings() method implements a critical merge-based architecture that prevents data loss when saving from one tab while preserving fields from other tabs.

Merge Architecture


Sources: admin/class-settings.php361-577

Critical Token Preservation Logic

The sanitization method includes explicit preservation logic for sensitive credentials to prevent accidental deletion:

GitHub Token Preservation:

Lines 391-428: GitHub token handling
- Check if 'github_token' is in $input
 - If present and not empty/masked:
 - Detect if plain text (starts with 'ghp_' or 'github_pat_')
 - Plain text → encrypt with encrypt_token()
 - Already encrypted → preserve as-is
 - If empty or masked ('••••••••••••••••'):
 - Preserve existing_settings['github_token']
- If 'github_token' not in $input (different tab):
 - Preserve existing_settings['github_token']

Dev.to API Key Preservation:

Lines 551-569: Dev.to API key handling
- Check if 'devto_api_key' is in $input
 - If present and not empty:
 - Update with sanitized value
 - If empty:
 - Preserve existing_settings['devto_api_key']
- If 'devto_api_key' not in $input (different tab):
 - Preserve existing_settings['devto_api_key']

Sources: admin/class-settings.php391-569

Final Merge Operation

Line 574: $merged_settings = array_merge( $existing_settings, $sanitized );
Line 576: return $merged_settings;

This merge ensures that:

  1. Fields present in $input are updated with sanitized values
  2. Fields not present in $input retain their existing values
  3. No data is lost when saving from a specific tab

Sources: admin/class-settings.php574-576


Token Encryption and Decryption

The Settings class implements AES-256-CBC encryption for GitHub Personal Access Tokens using WordPress salts as cryptographic keys.

Encryption Implementation


Sources: admin/class-settings.php588-596 admin/class-settings.php399-414

Encryption Method Details

The encryption uses WordPress-native salt functions to derive cryptographic keys:

Method: encrypt_token(string $token): string

Line 589: $method = 'AES-256-CBC';
Line 590: $key = hash('sha256', wp_salt('auth'), true);
Line 591: $iv = substr(hash('sha256', wp_salt('nonce'), true), 0, 16);
Line 593: $encrypted = openssl_encrypt($token, $method, $key, 0, $iv);
Line 595: return base64_encode($encrypted);

Key Derivation:

  • Encryption key: SHA-256 hash of wp_salt('auth') (32 bytes)
  • Initialization vector: First 16 bytes of SHA-256 hash of wp_salt('nonce')
  • Salts are site-specific, stored in wp-config.php

Sources: admin/class-settings.php588-596

Decryption Method

Method: decrypt_token(string $encrypted_token): string

Line 606: $method = 'AES-256-CBC';
Line 607: $key = hash('sha256', wp_salt('auth'), true);
Line 608: $iv = substr(hash('sha256', wp_salt('nonce'), true), 0, 16);
Line 610: $decoded = base64_decode($encrypted_token);
Line 611: $decrypted = openssl_decrypt($decoded, $method, $key, 0, $iv);
Line 613: return $decrypted ? $decrypted : '';

This method is called by Git_API when instantiating to retrieve the plain text token for API requests.

Sources: admin/class-settings.php605-614

Double-Encryption Prevention

The sanitization logic includes detection to prevent double-encryption when re-saving settings:

Lines 399-414: Token format detection
- Check if token starts with 'ghp_' (classic token) or 'github_pat_' (fine-grained token)
- If matches: Treat as plain text, encrypt
- If doesn't match: Already encrypted, preserve without re-encryption
- Log warning if already-encrypted token detected

This prevents corruption that would occur if an already-encrypted token were encrypted again.

Sources: admin/class-settings.php399-414


AJAX Handlers

The Settings class provides several AJAX endpoints for asynchronous operations, primarily connection testing and bulk synchronization.

AJAX Handler Registration


Sources: admin/class-settings.php46-55

Connection Test Handlers

GitHub Connection Test:

Method: ajax_test_connection()

Line 1620: check_ajax_referer('ajc-bridge-test-connection', 'nonce');
Line 1622-1624: Verify manage_options capability
Line 1626: Instantiate Git_API
Line 1627: $result = $git_api->test_connection();
Lines 1629-1632: Handle WP_Error response
Lines 1634-1635: Log success and return JSON

Dev.to Connection Test:

Method: ajax_test_devto_connection()

Line 1675: check_ajax_referer('ajc-bridge-test-connection', 'nonce');
Lines 1677-1679: Verify manage_options capability
Lines 1681-1685: Extract and validate api_key from POST
Lines 1692-1701: Temporarily override settings using option filter
Line 1703: Instantiate DevTo_API
Line 1704: $result = $devto_api->test_connection();
Lines 1706-1709: Handle WP_Error response
Lines 1711-1712: Log success and return JSON

Critical Note: The Dev.to test handler uses a filter to temporarily override settings rather than saving to the database, preventing accidental double-encryption of the GitHub token that would occur if update_option() triggered sanitize_settings().

Sources: admin/class-settings.php1619-1636 admin/class-settings.php1674-1713

Bulk Operations Handlers

Bulk Sync:

Method: ajax_bulk_sync()

Line 1573: check_ajax_referer('atomic-jamstack-bulk-sync', 'nonce');
Lines 1575-1577: Verify manage_options capability
Line 1579: $result = Queue_Manager::bulk_enqueue();
Lines 1581-1594: Return success with enqueue statistics

Queue Statistics:

Method: ajax_get_stats()

Line 1603: check_ajax_referer('atomic-jamstack-get-stats', 'nonce');
Lines 1605-1607: Verify manage_options capability
Line 1609: $stats = Queue_Manager::get_queue_stats();
Line 1611: wp_send_json_success($stats);

Single Post Sync:

Method: ajax_sync_single()

Line 1644: check_ajax_referer('atomic-jamstack-sync-single', 'nonce');
Lines 1646-1648: Verify publish_posts capability
Lines 1650-1654: Extract and validate post_id from POST
Line 1658: Queue_Manager::enqueue($post_id, 5); // High priority
Lines 1660-1663: Return success response

Sources: admin/class-settings.php1572-1595 admin/class-settings.php1602-1612 admin/class-settings.php1643-1664


Field Rendering Methods

The Settings class implements a render method for each settings field, generating the appropriate HTML form controls.

Field Rendering Architecture


Sources: admin/class-settings.php632-1214

Key Field Implementations

Repository Field:

Lines 632-648: render_repo_field()
- Input type: text
- Name: ajc_bridge_settings[github_repo]
- Validation: owner/repository format
- Placeholder: owner/repository

Token Field with Masking:

Lines 677-710: render_token_field()
- Input type: password
- Shows '••••••••••••••••' if token exists
- Placeholder: 'Token already saved' or 'ghp_xxxxxxxxxxxx'
- Includes "Test Connection" button with AJAX handler

Publishing Strategy Field:

Lines 858-921: render_publishing_strategy_field()
- Input type: radio (5 options)
- Options: wordpress_only, wordpress_devto, github_only, devto_only, dual_github_devto
- Each option includes description of behavior
- Supports migration from old adapter_type settings

SSG Type Dropdown:

Lines 984-1002: render_ssg_type_field()
- Input type: select
- Options: hugo, astro, jekyll (disabled), eleventy (disabled)
- Default: hugo

Front Matter Template:

Lines 1135-1164: render_front_matter_template_field()
- Input type: textarea (15 rows)
- Displays default YAML template with placeholders
- Available placeholders documented in description

Sources: admin/class-settings.php632-648 admin/class-settings.php677-710 admin/class-settings.php858-921 admin/class-settings.php984-1002 admin/class-settings.php1135-1164


Settings Page Rendering

The main page rendering method assembles the tabbed interface and delegates to WordPress Settings API.

Page Rendering Flow


Sources: admin/class-settings.php1221-1266

Page Structure

Method: render_settings_page()

Lines 1224-1228: Capability check for manage_options
Lines 1231-1232: Determine active tab from $_GET['settings_tab']
Lines 1234-1235: Output page header
Lines 1238-1249: Output tab navigation (General/Credentials)
Line 1251: Output settings_errors()
Lines 1254-1261: Output settings form
 - settings_fields(PAGE_SLUG)
 - do_settings_sections(PAGE_SLUG)
 - submit_button()
 - Hidden field to preserve active tab

Sources: admin/class-settings.php1221-1266


Integration with Other Components

The Settings class serves as a data provider for multiple system components.

Settings Data Flow


Sources: admin/class-settings.php605-614 core/class-git-api.php core/class-sync-runner.php

Settings Constants

OPTION_NAME = 'ajc_bridge_settings'
 - WordPress option name for all settings
 - Stored in wp_options table
 - Array structure with all configuration fields

PAGE_SLUG = 'atomic-jamstack-settings'
 - Settings page slug for WordPress Settings API
 - Used in register_setting() and menu registration

HISTORY_PAGE_SLUG = 'atomic-jamstack-history'
 - Slug for standalone history page

Sources: admin/class-settings.php29-39


Settings Schema

The complete settings array structure stored in wp_options:

Field NameTypeTabDescription
enabled_post_typesarrayGeneralPost types to sync (post, page)
publishing_strategystringGeneralOne of: wordpress_only, wordpress_devto, github_only, devto_only, dual_github_devto
github_site_urlstringGeneralDeployed static site URL for canonical links
devto_site_urlstringGeneralDev.to profile or WordPress URL for canonical links
ssg_typestringGeneralSSG type: hugo, astro, jekyll, eleventy
hugo_content_dirstringGeneralHugo content directory path
hugo_images_dirstringGeneralHugo images directory path
hugo_front_matter_templatestringGeneralCustom front matter template with placeholders
astro_content_dirstringGeneralAstro content directory path
astro_images_dirstringGeneralAstro images directory path
astro_file_extensionstringGeneralAstro file extension (.mdx or .md)
debug_modeboolGeneralEnable debug logging
delete_data_on_uninstallboolGeneralDelete all data on plugin uninstall
github_repostringCredentialsRepository in owner/repo format
github_branchstringCredentialsTarget branch for commits
github_tokenstringCredentialsEncrypted GitHub PAT (AES-256-CBC)
devto_api_keystringCredentialsDev.to API key (not encrypted)

Sources: admin/class-settings.php361-577


Asset Loading

The Settings class enqueues CSS and JavaScript assets for interactive functionality.

Asset Enqueue Logic

Method: enqueue_admin_assets(string $hook)

Lines 65-74: Check if current page is plugin settings page
 - Allowed hooks: toplevel_page_ajc-bridge, ajc-bridge_page_ajc-bridge-settings,
 ajc-bridge_page_ajc-bridge-bulk, ajc-bridge_page_ajc-bridge-history

Lines 77-82: Enqueue CSS
 - Handle: ajc-bridge-settings
 - Path: admin/assets/css/settings.css

Lines 85-91: Enqueue JavaScript
 - Handle: ajc-bridge-settings
 - Path: admin/assets/js/settings.js
 - Dependency: jquery

Lines 94-114: Localize script with AJAX parameters
 - ajaxurl: admin_url('admin-ajax.php')
 - Nonces for all AJAX actions
 - Translatable UI strings

Sources: admin/class-settings.php63-115

Localized Script Data

The JavaScript file receives the following configuration via wp_localize_script():


Sources: admin/class-settings.php94-114


Summary

The Settings class implements a sophisticated configuration management system with these key characteristics:

Architecture:

  • Two-tab interface (General/Credentials) with conditional field registration
  • Merge-based sanitization preventing data loss across tab saves
  • WordPress Settings API integration for standard form handling

Security:

  • AES-256-CBC encryption for GitHub tokens using WordPress salts
  • Double-encryption prevention via token format detection
  • Nonce verification for all AJAX operations
  • Capability checks (manage_options, publish_posts)

Data Flow:

  • Centralized configuration storage in wp_options (ajc_bridge_settings)
  • Consumed by Git_API, DevTo_API, Sync_Runner, adapters, and Redirect component
  • Token decryption delegated to dedicated method

User Experience:

  • Test Connection buttons with AJAX validation
  • Active tab preservation after form submission
  • Bulk operations with progress feedback
  • Sync history with per-post actions

Sources: admin/class-settings.php24-1714 docs/configuration.md1-261