Files
igny8/igny8-wp-plugin/includes/functions.php
alorig 3580acf61e 1
2025-11-22 08:07:56 +05:00

527 lines
14 KiB
PHP

<?php
/**
* Helper Functions
*
* WordPress integration functions for IGNY8 Bridge
*
* @package Igny8Bridge
*/
// Prevent direct access
if (!defined('ABSPATH')) {
exit;
}
/**
* Get encryption key for secure option storage
*
* @return string Binary key
*/
function igny8_get_encryption_key() {
$salt = wp_salt('auth');
return hash('sha256', 'igny8_bridge_' . $salt, true);
}
/**
* Encrypt a value for storage
*
* @param string $value Plain text value
* @return string Encrypted value with prefix or original value on failure
*/
function igny8_encrypt_value($value) {
if ($value === '' || $value === null) {
return '';
}
if (!function_exists('openssl_encrypt')) {
return $value;
}
$iv = openssl_random_pseudo_bytes(16);
$cipher = openssl_encrypt($value, 'AES-256-CBC', igny8_get_encryption_key(), OPENSSL_RAW_DATA, $iv);
if ($cipher === false) {
return $value;
}
return 'igny8|' . base64_encode($iv . $cipher);
}
/**
* Decrypt a stored value
*
* @param string $value Stored value
* @return string Decrypted value or original on failure
*/
function igny8_decrypt_value($value) {
if (!is_string($value) || strpos($value, 'igny8|') !== 0) {
return $value;
}
if (!function_exists('openssl_decrypt')) {
return $value;
}
$encoded = substr($value, 6);
$data = base64_decode($encoded, true);
if ($data === false || strlen($data) <= 16) {
return $value;
}
$iv = substr($data, 0, 16);
$cipher = substr($data, 16);
$plain = openssl_decrypt($cipher, 'AES-256-CBC', igny8_get_encryption_key(), OPENSSL_RAW_DATA, $iv);
return ($plain === false) ? $value : $plain;
}
/**
* Store an option securely
*
* @param string $option Option name
* @param string $value Value to store
*/
function igny8_store_secure_option($option, $value) {
if ($value === null || $value === '') {
delete_option($option);
return;
}
update_option($option, igny8_encrypt_value($value));
}
/**
* Retrieve secure option (with legacy fallback)
*
* @param string $option Option name
* @return string Value
*/
function igny8_get_secure_option($option) {
$stored = get_option($option);
if (!$stored) {
return '';
}
$value = igny8_decrypt_value($stored);
return is_string($value) ? $value : '';
}
/**
* Get supported post types for automation
*
* @return array Key => label
*/
function igny8_get_supported_post_types() {
$types = array(
'post' => __('Posts', 'igny8-bridge'),
'page' => __('Pages', 'igny8-bridge'),
);
if (post_type_exists('product')) {
$types['product'] = __('Products', 'igny8-bridge');
}
/**
* Filter the list of selectable post types.
*
* @param array $types
*/
return apply_filters('igny8_supported_post_types', $types);
}
/**
* Get enabled post types
*
* @return array
*/
function igny8_get_enabled_post_types() {
$saved = get_option('igny8_enabled_post_types');
if (is_array($saved) && !empty($saved)) {
return $saved;
}
return array_keys(igny8_get_supported_post_types());
}
/**
* Get configured control mode
*
* @return string mirror|hybrid
*/
function igny8_get_control_mode() {
$mode = get_option('igny8_control_mode', 'mirror');
return in_array($mode, array('mirror', 'hybrid'), true) ? $mode : 'mirror';
}
/**
* Get available automation modules
*
* @return array Key => label
*/
function igny8_get_available_modules() {
$modules = array(
'sites' => __('Sites (Data & Semantic Map)', 'igny8-bridge'),
'planner' => __('Planner (Keywords & Briefs)', 'igny8-bridge'),
'writer' => __('Writer (Tasks & Posts)', 'igny8-bridge'),
'linker' => __('Linker (Internal Links)', 'igny8-bridge'),
'optimizer' => __('Optimizer (Audits & Scores)', 'igny8-bridge'),
);
/**
* Filter the list of IGNY8 modules that can be toggled.
*
* @param array $modules
*/
return apply_filters('igny8_available_modules', $modules);
}
/**
* Get enabled modules
*
* @return array
*/
function igny8_get_enabled_modules() {
$saved = get_option('igny8_enabled_modules');
if (is_array($saved) && !empty($saved)) {
return $saved;
}
return array_keys(igny8_get_available_modules());
}
/**
* Check if a module is enabled
*
* @param string $module Module key
* @return bool
*/
function igny8_is_module_enabled($module) {
$modules = igny8_get_enabled_modules();
return in_array($module, $modules, true);
}
/**
* Check if a post type is enabled for automation
*
* @param string $post_type Post type key
* @return bool
*/
function igny8_is_post_type_enabled($post_type) {
$post_types = igny8_get_enabled_post_types();
return in_array($post_type, $post_types, true);
}
/**
* Check if IGNY8 connection is enabled
* This is a master switch that disables all sync operations while preserving credentials
*
* @return bool True if connection is enabled
*/
function igny8_is_connection_enabled() {
$enabled = get_option('igny8_connection_enabled', 1);
return (bool) $enabled;
}
/**
* Get webhook shared secret
*
* @return string Webhook secret
*/
function igny8_get_webhook_secret() {
$secret = get_option('igny8_webhook_secret');
if (empty($secret)) {
// Generate secret if not exists
$secret = wp_generate_password(64, false);
update_option('igny8_webhook_secret', $secret);
}
return $secret;
}
/**
* Regenerate webhook secret
*
* @return string New secret
*/
function igny8_regenerate_webhook_secret() {
$secret = wp_generate_password(64, false);
update_option('igny8_webhook_secret', $secret);
return $secret;
}
/**
* Get configuration for site scans
*
* @param array $overrides Override defaults
* @return array
*/
function igny8_get_site_scan_settings($overrides = array()) {
$defaults = array(
'post_types' => igny8_get_enabled_post_types(),
'include_products' => (bool) get_option('igny8_enable_woocommerce', class_exists('WooCommerce') ? 1 : 0),
'per_page' => 100,
'since' => null,
'mode' => 'full',
);
$settings = wp_parse_args($overrides, $defaults);
return apply_filters('igny8_site_scan_settings', $settings);
}
/**
* Register IGNY8 post meta fields
*/
function igny8_register_post_meta() {
$post_types = array('post', 'page', 'product');
// Define all meta fields with proper schema for REST API
$meta_fields = array(
'_igny8_taxonomy_id' => array(
'type' => 'integer',
'description' => 'IGNY8 taxonomy ID linked to this post',
'single' => true,
'show_in_rest' => true,
),
'_igny8_attribute_id' => array(
'type' => 'integer',
'description' => 'IGNY8 attribute ID linked to this post',
'single' => true,
'show_in_rest' => true,
),
'_igny8_last_synced' => array(
'type' => 'string',
'description' => 'Last sync timestamp',
'single' => true,
'show_in_rest' => true,
)
);
// Register each meta field for all relevant post types
foreach ($meta_fields as $meta_key => $config) {
foreach ($post_types as $post_type) {
register_post_meta($post_type, $meta_key, $config);
}
}
}
/**
* Register IGNY8 taxonomies
*/
function igny8_register_taxonomies() {
// Register sectors taxonomy (hierarchical) - only if not exists
if (!taxonomy_exists('igny8_sectors')) {
register_taxonomy('igny8_sectors', array('post', 'page', 'product'), array(
'hierarchical' => true,
'labels' => array(
'name' => 'IGNY8 Sectors',
'singular_name' => 'Sector',
'menu_name' => 'Sectors',
'all_items' => 'All Sectors',
'edit_item' => 'Edit Sector',
'view_item' => 'View Sector',
'update_item' => 'Update Sector',
'add_new_item' => 'Add New Sector',
'new_item_name' => 'New Sector Name',
'parent_item' => 'Parent Sector',
'parent_item_colon' => 'Parent Sector:',
'search_items' => 'Search Sectors',
'not_found' => 'No sectors found',
),
'public' => true,
'show_ui' => true,
'show_admin_column' => false,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'show_in_rest' => true,
'rewrite' => array(
'slug' => 'sectors',
'with_front' => false,
),
'capabilities' => array(
'manage_terms' => 'manage_categories',
'edit_terms' => 'manage_categories',
'delete_terms' => 'manage_categories',
'assign_terms' => 'edit_posts',
),
));
}
// Register clusters taxonomy (hierarchical) - only if not exists
if (!taxonomy_exists('igny8_clusters')) {
register_taxonomy('igny8_clusters', array('post', 'page', 'product'), array(
'hierarchical' => true,
'labels' => array(
'name' => 'IGNY8 Clusters',
'singular_name' => 'Cluster',
'menu_name' => 'Clusters',
'all_items' => 'All Clusters',
'edit_item' => 'Edit Cluster',
'view_item' => 'View Cluster',
'update_item' => 'Update Cluster',
'add_new_item' => 'Add New Cluster',
'new_item_name' => 'New Cluster Name',
'parent_item' => 'Parent Cluster',
'parent_item_colon' => 'Parent Cluster:',
'search_items' => 'Search Clusters',
'not_found' => 'No clusters found',
),
'public' => true,
'show_ui' => true,
'show_admin_column' => false,
'show_in_nav_menus' => true,
'show_tagcloud' => false,
'show_in_rest' => true,
'rewrite' => array(
'slug' => 'clusters',
'with_front' => false,
),
'capabilities' => array(
'manage_terms' => 'manage_categories',
'edit_terms' => 'manage_categories',
'delete_terms' => 'manage_categories',
'assign_terms' => 'edit_posts',
),
));
}
}
/**
* Map WordPress post status to IGNY8 task status
*
* @param string $wp_status WordPress post status
* @return string IGNY8 task status
*/
function igny8_map_wp_status_to_igny8($wp_status) {
$status_map = array(
'publish' => 'completed',
'draft' => 'draft',
'pending' => 'pending',
'private' => 'completed',
'trash' => 'archived',
'future' => 'scheduled'
);
return isset($status_map[$wp_status]) ? $status_map[$wp_status] : 'draft';
}
/**
* Check if post is managed by IGNY8
*
* @param int $post_id Post ID
* @return bool True if IGNY8 managed
*/
function igny8_is_igny8_managed_post($post_id) {
$task_id = get_post_meta($post_id, '_igny8_task_id', true);
return !empty($task_id);
}
/**
* Get post data for IGNY8 sync
*
* @param int $post_id Post ID
* @return array|false Post data or false on failure
*/
function igny8_get_post_data_for_sync($post_id) {
$post = get_post($post_id);
if (!$post) {
return false;
}
return array(
'id' => $post_id,
'title' => $post->post_title,
'status' => $post->post_status,
'url' => get_permalink($post_id),
'modified' => $post->post_modified,
'published' => $post->post_date,
'author' => get_the_author_meta('display_name', $post->post_author),
'word_count' => str_word_count(strip_tags($post->post_content)),
'meta' => array(
'task_id' => get_post_meta($post_id, '_igny8_task_id', true),
'content_id' => get_post_meta($post_id, '_igny8_content_id', true),
'cluster_id' => get_post_meta($post_id, '_igny8_cluster_id', true),
'sector_id' => get_post_meta($post_id, '_igny8_sector_id', true),
)
);
}
/**
* Schedule cron jobs
*/
function igny8_schedule_cron_jobs() {
// Schedule daily post status sync (WordPress → IGNY8)
if (!wp_next_scheduled('igny8_sync_post_statuses')) {
wp_schedule_event(time(), 'daily', 'igny8_sync_post_statuses');
}
// Schedule daily site data sync (incremental)
if (!wp_next_scheduled('igny8_sync_site_data')) {
wp_schedule_event(time(), 'daily', 'igny8_sync_site_data');
}
// Schedule periodic full site scan (runs at most once per week)
if (!wp_next_scheduled('igny8_full_site_scan')) {
wp_schedule_event(time(), 'daily', 'igny8_full_site_scan');
}
// Schedule hourly sync from IGNY8 (IGNY8 → WordPress)
if (!wp_next_scheduled('igny8_sync_from_igny8')) {
wp_schedule_event(time(), 'hourly', 'igny8_sync_from_igny8');
}
// Schedule taxonomy sync
if (!wp_next_scheduled('igny8_sync_taxonomies')) {
wp_schedule_event(time(), 'twicedaily', 'igny8_sync_taxonomies');
}
// Schedule keyword sync
if (!wp_next_scheduled('igny8_sync_keywords')) {
wp_schedule_event(time(), 'daily', 'igny8_sync_keywords');
}
}
/**
* Unschedule cron jobs
*/
function igny8_unschedule_cron_jobs() {
$timestamp = wp_next_scheduled('igny8_sync_post_statuses');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_sync_post_statuses');
}
$timestamp = wp_next_scheduled('igny8_sync_site_data');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_sync_site_data');
}
$timestamp = wp_next_scheduled('igny8_sync_from_igny8');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_sync_from_igny8');
}
$timestamp = wp_next_scheduled('igny8_full_site_scan');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_full_site_scan');
}
$timestamp = wp_next_scheduled('igny8_sync_taxonomies');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_sync_taxonomies');
}
$timestamp = wp_next_scheduled('igny8_sync_keywords');
if ($timestamp) {
wp_unschedule_event($timestamp, 'igny8_sync_keywords');
}
}