Files
IQ-Dynamic-Google-Pricing/admin/class-informatiq-sp-admin.php

554 lines
17 KiB
PHP

<?php
/**
* Admin interface for plugin settings and manual sync.
*
* @package InformatiqSmartPricing
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Admin class.
*/
class Informatiq_SP_Admin {
/**
* Logger instance.
*
* @var Informatiq_SP_Logger
*/
private $logger;
/**
* Price updater instance.
*
* @var Informatiq_SP_Price_Updater
*/
private $price_updater;
/**
* Constructor.
*
* @param Informatiq_SP_Logger $logger Logger instance.
* @param Informatiq_SP_Price_Updater $price_updater Price updater instance.
*/
public function __construct( $logger, $price_updater ) {
$this->logger = $logger;
$this->price_updater = $price_updater;
// Add admin menu.
add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
// Register settings.
add_action( 'admin_init', array( $this, 'register_settings' ) );
// Handle AJAX requests.
add_action( 'wp_ajax_informatiq_sp_manual_sync', array( $this, 'handle_manual_sync' ) );
add_action( 'wp_ajax_informatiq_sp_test_connection', array( $this, 'handle_test_connection' ) );
// Enqueue admin assets.
add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_assets' ) );
}
/**
* Add admin menu under WooCommerce.
*/
public function add_admin_menu() {
add_submenu_page(
'woocommerce',
__( 'Smart Pricing', 'informatiq-smart-pricing' ),
__( 'Smart Pricing', 'informatiq-smart-pricing' ),
'manage_woocommerce',
'informatiq-smart-pricing',
array( $this, 'render_admin_page' )
);
}
/**
* Register plugin settings.
*/
public function register_settings() {
// Register settings.
register_setting( 'informatiq_sp_settings', 'informatiq_sp_merchant_id' );
register_setting( 'informatiq_sp_settings', 'informatiq_sp_service_account' );
register_setting( 'informatiq_sp_settings', 'informatiq_sp_minimum_margin' );
register_setting( 'informatiq_sp_settings', 'informatiq_sp_auto_update_enabled' );
register_setting( 'informatiq_sp_settings', 'informatiq_sp_update_frequency' );
// Add settings sections.
add_settings_section(
'informatiq_sp_google_settings',
__( 'Google Merchant Center Settings', 'informatiq-smart-pricing' ),
array( $this, 'render_google_settings_section' ),
'informatiq_sp_settings'
);
add_settings_section(
'informatiq_sp_pricing_settings',
__( 'Pricing Settings', 'informatiq-smart-pricing' ),
array( $this, 'render_pricing_settings_section' ),
'informatiq_sp_settings'
);
add_settings_section(
'informatiq_sp_automation_settings',
__( 'Automation Settings', 'informatiq-smart-pricing' ),
array( $this, 'render_automation_settings_section' ),
'informatiq_sp_settings'
);
// Add settings fields.
add_settings_field(
'informatiq_sp_merchant_id',
__( 'Google Merchant ID', 'informatiq-smart-pricing' ),
array( $this, 'render_merchant_id_field' ),
'informatiq_sp_settings',
'informatiq_sp_google_settings'
);
add_settings_field(
'informatiq_sp_service_account',
__( 'Service Account JSON', 'informatiq-smart-pricing' ),
array( $this, 'render_service_account_field' ),
'informatiq_sp_settings',
'informatiq_sp_google_settings'
);
add_settings_field(
'informatiq_sp_minimum_margin',
__( 'Minimum Margin (%)', 'informatiq-smart-pricing' ),
array( $this, 'render_minimum_margin_field' ),
'informatiq_sp_settings',
'informatiq_sp_pricing_settings'
);
add_settings_field(
'informatiq_sp_auto_update_enabled',
__( 'Enable Automatic Updates', 'informatiq-smart-pricing' ),
array( $this, 'render_auto_update_field' ),
'informatiq_sp_settings',
'informatiq_sp_automation_settings'
);
add_settings_field(
'informatiq_sp_update_frequency',
__( 'Update Frequency', 'informatiq-smart-pricing' ),
array( $this, 'render_update_frequency_field' ),
'informatiq_sp_settings',
'informatiq_sp_automation_settings'
);
}
/**
* Render admin page.
*/
public function render_admin_page() {
if ( ! current_user_can( 'manage_woocommerce' ) ) {
return;
}
// Check if form was submitted.
if ( isset( $_GET['settings-updated'] ) ) {
// Update cron schedule if frequency changed.
$frequency = get_option( 'informatiq_sp_update_frequency', 'daily' );
Informatiq_SP_Scheduler::reschedule( $frequency );
add_settings_error(
'informatiq_sp_messages',
'informatiq_sp_message',
__( 'Settings saved successfully.', 'informatiq-smart-pricing' ),
'success'
);
}
?>
<div class="wrap informatiq-sp-admin">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<?php settings_errors( 'informatiq_sp_messages' ); ?>
<div class="informatiq-sp-content">
<div class="informatiq-sp-main">
<form action="options.php" method="post">
<?php
settings_fields( 'informatiq_sp_settings' );
do_settings_sections( 'informatiq_sp_settings' );
submit_button( __( 'Save Settings', 'informatiq-smart-pricing' ) );
?>
</form>
<hr>
<div class="informatiq-sp-actions">
<h2><?php esc_html_e( 'Manual Actions', 'informatiq-smart-pricing' ); ?></h2>
<p>
<button type="button" class="button button-secondary" id="informatiq-sp-test-connection">
<?php esc_html_e( 'Test Google API Connection', 'informatiq-smart-pricing' ); ?>
</button>
<button type="button" class="button button-primary" id="informatiq-sp-manual-sync">
<?php esc_html_e( 'Run Manual Sync Now', 'informatiq-smart-pricing' ); ?>
</button>
</p>
<div id="informatiq-sp-sync-status" class="notice" style="display: none;"></div>
</div>
<hr>
<?php $this->render_schedule_info(); ?>
<hr>
<?php $this->render_logs_section(); ?>
</div>
<div class="informatiq-sp-sidebar">
<?php $this->render_sidebar(); ?>
</div>
</div>
</div>
<?php
}
/**
* Render Google settings section description.
*/
public function render_google_settings_section() {
echo '<p>' . esc_html__( 'Configure your Google Merchant Center API credentials.', 'informatiq-smart-pricing' ) . '</p>';
}
/**
* Render pricing settings section description.
*/
public function render_pricing_settings_section() {
echo '<p>' . esc_html__( 'Configure pricing rules and safeguards.', 'informatiq-smart-pricing' ) . '</p>';
}
/**
* Render automation settings section description.
*/
public function render_automation_settings_section() {
echo '<p>' . esc_html__( 'Configure automated price updates.', 'informatiq-smart-pricing' ) . '</p>';
}
/**
* Render merchant ID field.
*/
public function render_merchant_id_field() {
$value = get_option( 'informatiq_sp_merchant_id' );
?>
<input type="text" name="informatiq_sp_merchant_id" id="informatiq_sp_merchant_id"
value="<?php echo esc_attr( $value ); ?>" class="regular-text">
<p class="description">
<?php esc_html_e( 'Your Google Merchant Center ID.', 'informatiq-smart-pricing' ); ?>
</p>
<?php
}
/**
* Render service account field.
*/
public function render_service_account_field() {
$value = get_option( 'informatiq_sp_service_account' );
?>
<textarea name="informatiq_sp_service_account" id="informatiq_sp_service_account"
rows="10" class="large-text code"><?php echo esc_textarea( $value ); ?></textarea>
<p class="description">
<?php esc_html_e( 'Paste your Google Service Account JSON key here.', 'informatiq-smart-pricing' ); ?>
</p>
<?php
}
/**
* Render minimum margin field.
*/
public function render_minimum_margin_field() {
$value = get_option( 'informatiq_sp_minimum_margin', '10' );
?>
<input type="number" name="informatiq_sp_minimum_margin" id="informatiq_sp_minimum_margin"
value="<?php echo esc_attr( $value ); ?>" min="0" max="100" step="0.01" class="small-text">
<span>%</span>
<p class="description">
<?php esc_html_e( 'Minimum profit margin to maintain. Prices will never go below (Cost + Margin%).', 'informatiq-smart-pricing' ); ?>
</p>
<?php
}
/**
* Render auto update field.
*/
public function render_auto_update_field() {
$value = get_option( 'informatiq_sp_auto_update_enabled', '1' );
?>
<label>
<input type="checkbox" name="informatiq_sp_auto_update_enabled" value="1"
<?php checked( $value, '1' ); ?>>
<?php esc_html_e( 'Enable automatic daily price updates', 'informatiq-smart-pricing' ); ?>
</label>
<?php
}
/**
* Render update frequency field.
*/
public function render_update_frequency_field() {
$value = get_option( 'informatiq_sp_update_frequency', 'daily' );
?>
<select name="informatiq_sp_update_frequency" id="informatiq_sp_update_frequency">
<option value="every_6_hours" <?php selected( $value, 'every_6_hours' ); ?>>
<?php esc_html_e( 'Every 6 Hours', 'informatiq-smart-pricing' ); ?>
</option>
<option value="twice_daily" <?php selected( $value, 'twice_daily' ); ?>>
<?php esc_html_e( 'Twice Daily', 'informatiq-smart-pricing' ); ?>
</option>
<option value="daily" <?php selected( $value, 'daily' ); ?>>
<?php esc_html_e( 'Once Daily', 'informatiq-smart-pricing' ); ?>
</option>
</select>
<p class="description">
<?php esc_html_e( 'How often should prices be automatically updated?', 'informatiq-smart-pricing' ); ?>
</p>
<?php
}
/**
* Render schedule information.
*/
private function render_schedule_info() {
$next_run = Informatiq_SP_Scheduler::get_next_run_time();
$last_run = Informatiq_SP_Scheduler::get_last_run_info();
?>
<div class="informatiq-sp-schedule-info">
<h2><?php esc_html_e( 'Schedule Information', 'informatiq-smart-pricing' ); ?></h2>
<table class="widefat">
<tbody>
<tr>
<th><?php esc_html_e( 'Next Scheduled Run:', 'informatiq-smart-pricing' ); ?></th>
<td>
<?php
if ( $next_run ) {
echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $next_run ) );
} else {
esc_html_e( 'Not scheduled', 'informatiq-smart-pricing' );
}
?>
</td>
</tr>
<tr>
<th><?php esc_html_e( 'Last Run:', 'informatiq-smart-pricing' ); ?></th>
<td>
<?php
if ( ! empty( $last_run['end'] ) ) {
echo esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $last_run['end'] ) ) );
if ( ! empty( $last_run['results'] ) ) {
$results = $last_run['results'];
printf(
' - %s',
sprintf(
/* translators: %1$d: updated count, %2$d: processed count */
esc_html__( '%1$d of %2$d products updated', 'informatiq-smart-pricing' ),
$results['updated'],
$results['processed']
)
);
}
} else {
esc_html_e( 'Never', 'informatiq-smart-pricing' );
}
?>
</td>
</tr>
</tbody>
</table>
</div>
<?php
}
/**
* Render logs section.
*/
private function render_logs_section() {
$logs = $this->logger->get_todays_logs();
?>
<div class="informatiq-sp-logs">
<h2><?php esc_html_e( 'Today\'s Price Updates', 'informatiq-smart-pricing' ); ?></h2>
<?php if ( empty( $logs ) ) : ?>
<p><?php esc_html_e( 'No price updates today.', 'informatiq-smart-pricing' ); ?></p>
<?php else : ?>
<table class="widefat striped">
<thead>
<tr>
<th><?php esc_html_e( 'Time', 'informatiq-smart-pricing' ); ?></th>
<th><?php esc_html_e( 'Product', 'informatiq-smart-pricing' ); ?></th>
<th><?php esc_html_e( 'Old Price', 'informatiq-smart-pricing' ); ?></th>
<th><?php esc_html_e( 'New Price', 'informatiq-smart-pricing' ); ?></th>
<th><?php esc_html_e( 'Competitor Price', 'informatiq-smart-pricing' ); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ( $logs as $log ) : ?>
<tr>
<td><?php echo esc_html( date_i18n( get_option( 'time_format' ), strtotime( $log->created_at ) ) ); ?></td>
<td>
<a href="<?php echo esc_url( get_edit_post_link( $log->product_id ) ); ?>">
<?php echo esc_html( $log->product_name ); ?>
</a>
</td>
<td><?php echo wp_kses_post( wc_price( $log->old_price ) ); ?></td>
<td><?php echo wp_kses_post( wc_price( $log->new_price ) ); ?></td>
<td><?php echo wp_kses_post( wc_price( $log->competitor_price ) ); ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
<?php
}
/**
* Render sidebar.
*/
private function render_sidebar() {
?>
<div class="informatiq-sp-sidebar-box">
<h3><?php esc_html_e( 'How It Works', 'informatiq-smart-pricing' ); ?></h3>
<ol>
<li><?php esc_html_e( 'Configure Google Merchant Center credentials', 'informatiq-smart-pricing' ); ?></li>
<li><?php esc_html_e( 'Set your minimum profit margin', 'informatiq-smart-pricing' ); ?></li>
<li><?php esc_html_e( 'Enable automatic updates', 'informatiq-smart-pricing' ); ?></li>
<li><?php esc_html_e( 'Plugin automatically updates prices daily', 'informatiq-smart-pricing' ); ?></li>
</ol>
</div>
<div class="informatiq-sp-sidebar-box">
<h3><?php esc_html_e( 'Requirements', 'informatiq-smart-pricing' ); ?></h3>
<ul>
<li><?php esc_html_e( 'Products must be in stock', 'informatiq-smart-pricing' ); ?></li>
<li><?php esc_html_e( 'Products must have SKU set', 'informatiq-smart-pricing' ); ?></li>
<li><?php esc_html_e( 'Products must exist in Google Merchant Center', 'informatiq-smart-pricing' ); ?></li>
</ul>
</div>
<div class="informatiq-sp-sidebar-box">
<h3><?php esc_html_e( 'Support', 'informatiq-smart-pricing' ); ?></h3>
<p>
<?php
printf(
/* translators: %s: support URL */
wp_kses_post( __( 'Need help? Visit <a href="%s" target="_blank">informatiq.services</a>', 'informatiq-smart-pricing' ) ),
'https://informatiq.services'
);
?>
</p>
</div>
<?php
}
/**
* Handle manual sync AJAX request.
*/
public function handle_manual_sync() {
check_ajax_referer( 'informatiq_sp_admin', 'nonce' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'informatiq-smart-pricing' ) ) );
}
try {
$scheduler = new Informatiq_SP_Scheduler( $this->price_updater );
$results = $scheduler->trigger_manual_update();
wp_send_json_success(
array(
'message' => sprintf(
/* translators: %1$d: updated count, %2$d: processed count */
__( 'Sync completed! Updated %1$d of %2$d products.', 'informatiq-smart-pricing' ),
$results['updated'],
$results['processed']
),
'results' => $results,
)
);
} catch ( Exception $e ) {
wp_send_json_error( array( 'message' => $e->getMessage() ) );
}
}
/**
* Handle test connection AJAX request.
*/
public function handle_test_connection() {
check_ajax_referer( 'informatiq_sp_admin', 'nonce' );
if ( ! current_user_can( 'manage_woocommerce' ) ) {
wp_send_json_error( array( 'message' => __( 'Insufficient permissions', 'informatiq-smart-pricing' ) ) );
}
$merchant_id = get_option( 'informatiq_sp_merchant_id' );
$service_account = get_option( 'informatiq_sp_service_account' );
if ( empty( $merchant_id ) || empty( $service_account ) ) {
wp_send_json_error( array( 'message' => __( 'Please configure Google Merchant settings first.', 'informatiq-smart-pricing' ) ) );
}
try {
$google_api = new Informatiq_SP_Google_API( $merchant_id, $service_account, $this->logger );
$success = $google_api->test_connection();
if ( $success ) {
wp_send_json_success( array( 'message' => __( 'Connection successful!', 'informatiq-smart-pricing' ) ) );
} else {
wp_send_json_error( array( 'message' => __( 'Connection failed. Check your credentials.', 'informatiq-smart-pricing' ) ) );
}
} catch ( Exception $e ) {
wp_send_json_error( array( 'message' => $e->getMessage() ) );
}
}
/**
* Enqueue admin assets.
*
* @param string $hook Current admin page hook.
*/
public function enqueue_admin_assets( $hook ) {
if ( 'woocommerce_page_informatiq-smart-pricing' !== $hook ) {
return;
}
wp_enqueue_style(
'informatiq-sp-admin',
INFORMATIQ_SP_PLUGIN_URL . 'assets/css/admin.css',
array(),
INFORMATIQ_SP_VERSION
);
wp_enqueue_script(
'informatiq-sp-admin',
INFORMATIQ_SP_PLUGIN_URL . 'assets/js/admin.js',
array( 'jquery' ),
INFORMATIQ_SP_VERSION,
true
);
wp_localize_script(
'informatiq-sp-admin',
'informatiqSP',
array(
'ajaxUrl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'informatiq_sp_admin' ),
'strings' => array(
'syncInProgress' => __( 'Sync in progress...', 'informatiq-smart-pricing' ),
'testInProgress' => __( 'Testing connection...', 'informatiq-smart-pricing' ),
),
)
);
}
}