| Current File : /home/digitaw/www/wp-content/plugins/simple-history/inc/services/class-channels-settings-page.php |
<?php
namespace Simple_History\Services;
use Simple_History\Helpers;
use Simple_History\Channels\Channels_Manager;
use Simple_History\Menu_Page;
/**
* Settings page for channels, where users can configure
* log forwarding to external systems.
*
* @since 4.4.0
*/
class Channels_Settings_Page extends Service {
/**
* The channels manager instance.
*
* @var Channels_Manager|null
*/
private ?Channels_Manager $channels_manager = null;
private const SETTINGS_PAGE_SLUG = 'simple_history_settings_menu_slug_log_forwarding';
public const SETTINGS_OPTION_GROUP = 'simple_history_settings_group_log_forwarding';
/**
* @inheritdoc
*/
public function loaded() {
// Get the channels manager from the channels service.
$channels_service = $this->simple_history->get_service( Channels_Service::class );
if ( ! $channels_service instanceof Channels_Service ) {
return;
}
$this->channels_manager = $channels_service->get_channels_manager();
if ( ! $this->channels_manager ) {
return;
}
// Add settings page after init.
add_action( 'init', [ $this, 'on_init_add_settings' ], 20 );
// Add menu page.
add_action( 'admin_menu', [ $this, 'add_settings_menu_tab' ], 15 );
}
/**
* Add settings after plugins have loaded.
*/
public function on_init_add_settings() {
add_action( 'admin_menu', [ $this, 'register_and_add_settings' ] );
}
/**
* Add integrations settings tab as a subtab to main settings tab.
*/
public function add_settings_menu_tab() {
$menu_manager = $this->simple_history->get_menu_manager();
// Bail if parent settings page does not exist (due to Stealth Mode or similar).
if ( ! $menu_manager->page_exists( Setup_Settings_Page::SETTINGS_GENERAL_SUBTAB_SLUG ) ) {
return;
}
// Build menu title with Beta badge.
$menu_title = __( 'Log Forwarding', 'simple-history' )
. ' <span class="sh-Badge sh-Badge--new">' . esc_html__( 'Beta', 'simple-history' ) . '</span>';
( new Menu_Page() )
->set_page_title( __( 'Log Forwarding', 'simple-history' ) )
->set_menu_title( $menu_title )
->set_menu_slug( 'general_settings_subtab_log_forwarding' )
->set_callback( [ $this, 'settings_output_channels' ] )
->set_order( 40 ) // After general settings but before licenses.
->set_parent( Setup_Settings_Page::SETTINGS_GENERAL_SUBTAB_SLUG )
->add();
}
/**
* Register settings and add settings fields.
*/
public function register_and_add_settings() {
// Add main integrations settings section with intro text.
// Use WordPress core function directly without card wrapper for the intro section.
add_settings_section(
'simple_history_settings_section_tab_integrations',
Helpers::get_settings_section_title_output( __( 'Log Forwarding', 'simple-history' ), 'extension' ),
[ $this, 'settings_section_output' ],
self::SETTINGS_PAGE_SLUG
);
// Add a settings section for each channel.
foreach ( $this->channels_manager->get_channels() as $channel ) {
$this->add_channel_settings_section( $channel );
}
// Add premium channel teasers when premium is not active.
$this->add_premium_channel_teasers();
}
/**
* Add teaser sections for premium-only channels.
*
* Shows promotional cards for premium channels when the premium add-on is not active.
*/
private function add_premium_channel_teasers() {
// Skip if premium is active (the real channels will be shown instead).
if ( Helpers::is_premium_add_on_active() ) {
return;
}
// Premium badge HTML for section titles.
$premium_badge = '<span class="sh-Badge sh-Badge--premium">' . esc_html__( 'Premium', 'simple-history' ) . '</span>';
// Add Syslog channel teaser.
// Title format: [title, icon-slug, html-id, suffix].
Helpers::add_settings_section(
'simple_history_channel_syslog_teaser',
[ __( 'Syslog', 'simple-history' ), null, '', $premium_badge ],
[ $this, 'render_syslog_teaser' ],
self::SETTINGS_PAGE_SLUG
);
// Add External Database channel teaser.
// Title format: [title, icon-slug, html-id, suffix].
Helpers::add_settings_section(
'simple_history_channel_external_database_teaser',
[ __( 'Remote Database', 'simple-history' ), null, '', $premium_badge ],
[ $this, 'render_external_database_teaser' ],
self::SETTINGS_PAGE_SLUG
);
}
/**
* Render the Syslog channel teaser content.
*
* Shows a disabled form that mimics the real Syslog channel settings,
* creating FOMO and demonstrating the value of the premium feature.
*/
public function render_syslog_teaser() {
?>
<div class="sh-SettingsSectionIntroduction">
<p><?php esc_html_e( 'Stream events to syslog for centralized monitoring and SIEM integration.', 'simple-history' ); ?></p>
</div>
<div class="sh-PremiumTeaser-disabledForm" inert>
<table class="form-table" role="presentation">
<tbody>
<!-- Status -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Status', 'simple-history' ) ) ); ?>
</th>
<td>
<label>
<input type="checkbox" />
<?php esc_html_e( 'Enable Syslog forwarding', 'simple-history' ); ?>
</label>
</td>
</tr>
<!-- Mode (radio buttons) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Mode', 'simple-history' ) ) ); ?>
</th>
<td>
<fieldset class="sh-RadioOptions sh-RadioOptions--disabled">
<label class="sh-RadioOption">
<input type="radio" checked />
<?php esc_html_e( 'Local syslog', 'simple-history' ); ?>
<span class="sh-RadioOptionDescription description">
<?php esc_html_e( 'Writes to this server\'s system log', 'simple-history' ); ?>
</span>
</label>
<label class="sh-RadioOption">
<input type="radio" />
<?php esc_html_e( 'Remote syslog (UDP)', 'simple-history' ); ?>
<span class="sh-RadioOptionDescription description">
<?php esc_html_e( 'Send to a central log server – fastest, no delivery confirmation', 'simple-history' ); ?>
</span>
</label>
<label class="sh-RadioOption">
<input type="radio" />
<?php esc_html_e( 'Remote syslog (TCP)', 'simple-history' ); ?>
<span class="sh-RadioOptionDescription description">
<?php esc_html_e( 'Send to a central log server – reliable, confirms delivery', 'simple-history' ); ?>
</span>
</label>
</fieldset>
</td>
</tr>
<!-- Server (combined: host, port, timeout) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Server', 'simple-history' ) ) ); ?>
</th>
<td>
<div class="sh-InlineFields">
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Address', 'simple-history' ); ?></span>
<input type="text" class="regular-text" placeholder="syslog.example.com" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Port', 'simple-history' ); ?></span>
<input type="number" class="small-text" value="514" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Timeout', 'simple-history' ); ?></span>
<span class="sh-InlineFieldInputWithSuffix">
<input type="number" class="small-text" value="5" />
<span class="sh-InlineFieldSuffix"><?php esc_html_e( 'sec', 'simple-history' ); ?></span>
</span>
</label>
</div>
<p class="description">
<?php esc_html_e( 'Required for TCP and UDP transport modes.', 'simple-history' ); ?>
</p>
</td>
</tr>
<!-- Advanced (combined: facility, identity) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Advanced', 'simple-history' ) ) ); ?>
</th>
<td>
<div class="sh-InlineFields">
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Facility', 'simple-history' ); ?></span>
<select>
<option selected>user - User-level messages</option>
</select>
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Identity', 'simple-history' ); ?></span>
<input type="text" class="regular-text" value="SimpleHistory" />
</label>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<?php
echo wp_kses_post(
Helpers::get_premium_feature_teaser(
__( 'Unlock Syslog Integration', 'simple-history' ),
[
__( 'Local syslog via PHP syslog() function', 'simple-history' ),
__( 'Remote rsyslog via UDP or TCP', 'simple-history' ),
__( 'RFC 5424 format for SIEM integration', 'simple-history' ),
__( 'Test connection button to verify setup', 'simple-history' ),
],
'syslog_channel_teaser',
__( 'Unlock Syslog with Premium', 'simple-history' )
)
);
}
/**
* Render the External Database channel teaser content.
*
* Shows a disabled form that mimics the real External Database channel settings,
* creating FOMO and demonstrating the value of the premium feature.
*/
public function render_external_database_teaser() {
?>
<div class="sh-SettingsSectionIntroduction">
<p><?php esc_html_e( 'Store events in a separate MySQL/MariaDB database for tamper-proof auditing and compliance.', 'simple-history' ); ?></p>
</div>
<div class="sh-PremiumTeaser-disabledForm" inert>
<table class="form-table" role="presentation">
<tbody>
<!-- Enabled checkbox -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Status', 'simple-history' ) ) ); ?>
</th>
<td>
<label>
<input type="checkbox" />
<?php esc_html_e( 'Enable External Database forwarding', 'simple-history' ); ?>
</label>
</td>
</tr>
<!-- Server (combined: host, port, timeout) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Server', 'simple-history' ) ) ); ?>
</th>
<td>
<div class="sh-InlineFields">
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Address', 'simple-history' ); ?></span>
<input type="text" class="regular-text" placeholder="example.com" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Port', 'simple-history' ); ?></span>
<input type="number" class="small-text" value="3306" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Timeout', 'simple-history' ); ?></span>
<span class="sh-InlineFieldInputWithSuffix">
<input type="number" class="small-text" value="5" />
<span class="sh-InlineFieldSuffix"><?php esc_html_e( 'sec', 'simple-history' ); ?></span>
</span>
</label>
</div>
<p class="description">
<?php esc_html_e( 'Host, port, and connection timeout for the external server.', 'simple-history' ); ?>
</p>
</td>
</tr>
<!-- Auth (combined: username, password) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Auth', 'simple-history' ) ) ); ?>
</th>
<td>
<div class="sh-InlineFields">
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Username', 'simple-history' ); ?></span>
<input type="text" class="regular-text" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Password', 'simple-history' ); ?></span>
<input type="password" class="regular-text" />
</label>
</div>
<p class="description">
<?php esc_html_e( 'Requires INSERT and CREATE TABLE privileges.', 'simple-history' ); ?>
</p>
</td>
</tr>
<!-- Database (combined: name, table) -->
<tr>
<th scope="row">
<?php echo wp_kses_post( Helpers::get_settings_field_title_output( __( 'Database', 'simple-history' ) ) ); ?>
</th>
<td>
<div class="sh-InlineFields">
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Name', 'simple-history' ); ?></span>
<input type="text" class="regular-text" placeholder="audit_logs" />
</label>
<label class="sh-InlineField">
<span class="sh-InlineFieldLabel"><?php esc_html_e( 'Table', 'simple-history' ); ?></span>
<input type="text" class="regular-text" value="simple_history_events" />
</label>
</div>
<p class="description">
<?php esc_html_e( 'Table will be created automatically if it does not exist.', 'simple-history' ); ?>
</p>
</td>
</tr>
</tbody>
</table>
</div>
<?php
echo wp_kses_post(
Helpers::get_premium_feature_teaser(
__( 'Unlock External Database Integration', 'simple-history' ),
[
__( 'Store audit logs in a separate MySQL/MariaDB database', 'simple-history' ),
__( 'Off-site backup for compliance (SOC 2, GDPR, HIPAA)', 'simple-history' ),
__( 'Encrypted password storage for security', 'simple-history' ),
__( 'Automatic table creation with optimized indexes', 'simple-history' ),
__( 'Test connection button to verify setup', 'simple-history' ),
],
'external_database_channel_teaser',
__( 'Unlock External Database with Premium', 'simple-history' )
)
);
}
/**
* Add a settings section for a specific channel.
*
* @param \Simple_History\Channels\Interfaces\Channel_Interface $channel The channel.
*/
private function add_channel_settings_section( $channel ) {
$channel_slug = $channel->get_slug();
$option_name = $channel->get_settings_option_name();
$section_id = 'simple_history_channel_' . $channel_slug;
// Register the settings option for this channel.
register_setting(
self::SETTINGS_OPTION_GROUP,
$option_name,
[
'sanitize_callback' => [ $channel, 'sanitize_settings' ],
]
);
// Add a settings section for this channel (wrapped in sh-SettingsCard by helper).
Helpers::add_settings_section(
$section_id,
$channel->get_name(),
function () use ( $channel ) {
$this->render_channel_section_intro( $channel );
},
self::SETTINGS_PAGE_SLUG,
[
'callback_last' => [ $channel, 'settings_output_after_fields' ],
]
);
// Let the channel add its own settings fields.
$channel->add_settings_fields( self::SETTINGS_PAGE_SLUG, $section_id );
}
/**
* Output for the main settings section intro.
*/
public function settings_section_output() {
?>
<div class="sh-SettingsSectionIntroduction">
<p><?php esc_html_e( 'Store events outside the WordPress database for backup, monitoring, or compliance.', 'simple-history' ); ?></p>
</div>
<?php
$this->render_beta_notice();
}
/**
* Render the intro for a channel's settings section.
*
* @param \Simple_History\Channels\Interfaces\Channel_Interface $channel The channel.
*/
private function render_channel_section_intro( $channel ) {
if ( ! empty( $channel->get_description() ) ) {
?>
<div class="sh-SettingsSectionIntroduction">
<p><?php echo esc_html( $channel->get_description() ); ?></p>
</div>
<?php
}
$channel->settings_output_intro();
}
/**
* Output for the integrations settings page.
*/
public function settings_output_channels() {
?>
<div class="wrap sh-Page-content">
<form method="post" action="options.php">
<?php
// Prints out all settings sections added to a particular settings page.
do_settings_sections( self::SETTINGS_PAGE_SLUG );
// Output nonce, action, and option_page fields.
settings_fields( self::SETTINGS_OPTION_GROUP );
submit_button();
?>
</form>
</div>
<?php
}
/**
* Render new feature notice banner at the top of the settings page.
*/
private function render_beta_notice() {
?>
<div class="sh-BetaNotice">
<p>
<strong><?php esc_html_e( 'Beta feature – your feedback matters!', 'simple-history' ); ?></strong>
<?php
printf(
/* translators: %s: email address link */
esc_html__( 'Let us know what\'s working and what could be better at %s.', 'simple-history' ),
'<a href="mailto:contact@simple-history.com">contact@simple-history.com</a>'
);
?>
</p>
</div>
<?php
}
}