asd
This commit is contained in:
381
igy8-wp-plugin/includes/class-igny8-webhooks.php
Normal file
381
igy8-wp-plugin/includes/class-igny8-webhooks.php
Normal file
@@ -0,0 +1,381 @@
|
||||
<?php
|
||||
/**
|
||||
* IGNY8 Webhooks Handler
|
||||
*
|
||||
* Handles incoming webhooks from IGNY8 SaaS
|
||||
*
|
||||
* @package Igny8Bridge
|
||||
*/
|
||||
|
||||
// Prevent direct access
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Igny8Webhooks Class
|
||||
*/
|
||||
class Igny8Webhooks {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action('rest_api_init', array($this, 'register_webhook_routes'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register webhook REST routes
|
||||
*/
|
||||
public function register_webhook_routes() {
|
||||
// Main webhook endpoint
|
||||
register_rest_route('igny8/v1', '/event', array(
|
||||
'methods' => 'POST',
|
||||
'callback' => array($this, 'handle_webhook'),
|
||||
'permission_callback' => array($this, 'verify_webhook_secret'),
|
||||
'args' => array(
|
||||
'event' => array(
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'description' => 'Event type'
|
||||
),
|
||||
'data' => array(
|
||||
'required' => true,
|
||||
'type' => 'object',
|
||||
'description' => 'Event data'
|
||||
)
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify webhook shared secret
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function verify_webhook_secret($request) {
|
||||
// First check if connection is enabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return new WP_Error(
|
||||
'rest_forbidden',
|
||||
__('IGNY8 connection is disabled', 'igny8-bridge'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
// Get shared secret from settings
|
||||
$shared_secret = igny8_get_webhook_secret();
|
||||
|
||||
if (empty($shared_secret)) {
|
||||
return new WP_Error(
|
||||
'rest_forbidden',
|
||||
__('Webhook secret not configured', 'igny8-bridge'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
// Check X-IGNY8-Signature header
|
||||
$signature = $request->get_header('X-IGNY8-Signature');
|
||||
|
||||
if (empty($signature)) {
|
||||
return new WP_Error(
|
||||
'rest_forbidden',
|
||||
__('Missing webhook signature', 'igny8-bridge'),
|
||||
array('status' => 401)
|
||||
);
|
||||
}
|
||||
|
||||
// Verify signature
|
||||
$body = $request->get_body();
|
||||
$expected_signature = hash_hmac('sha256', $body, $shared_secret);
|
||||
|
||||
if (!hash_equals($expected_signature, $signature)) {
|
||||
igny8_log_webhook_activity(array(
|
||||
'event' => 'authentication_failed',
|
||||
'ip' => $request->get_header('X-Forwarded-For') ?: $request->get_header('Remote-Addr'),
|
||||
'error' => 'Invalid signature'
|
||||
));
|
||||
|
||||
return new WP_Error(
|
||||
'rest_forbidden',
|
||||
__('Invalid webhook signature', 'igny8-bridge'),
|
||||
array('status' => 401)
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle incoming webhook
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error
|
||||
*/
|
||||
public function handle_webhook($request) {
|
||||
// Double-check connection is enabled
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return new WP_Error(
|
||||
'rest_forbidden',
|
||||
__('IGNY8 connection is disabled', 'igny8-bridge'),
|
||||
array('status' => 403)
|
||||
);
|
||||
}
|
||||
|
||||
$event = $request->get_param('event');
|
||||
$data = $request->get_param('data');
|
||||
|
||||
if (empty($event) || empty($data)) {
|
||||
return new WP_Error(
|
||||
'rest_invalid_param',
|
||||
__('Missing event or data parameter', 'igny8-bridge'),
|
||||
array('status' => 400)
|
||||
);
|
||||
}
|
||||
|
||||
// Log webhook receipt
|
||||
$log_id = igny8_log_webhook_activity(array(
|
||||
'event' => $event,
|
||||
'data' => $data,
|
||||
'ip' => $request->get_header('X-Forwarded-For') ?: $request->get_header('Remote-Addr'),
|
||||
'user_agent' => $request->get_header('User-Agent'),
|
||||
'status' => 'received'
|
||||
));
|
||||
|
||||
// Route to appropriate handler
|
||||
$result = null;
|
||||
|
||||
switch ($event) {
|
||||
case 'task_published':
|
||||
case 'task_completed':
|
||||
$result = $this->handle_task_published($data);
|
||||
break;
|
||||
|
||||
case 'link_recommendation':
|
||||
case 'insert_link':
|
||||
$result = $this->handle_link_recommendation($data);
|
||||
break;
|
||||
|
||||
case 'optimizer_request':
|
||||
case 'optimizer_job_completed':
|
||||
$result = $this->handle_optimizer_request($data);
|
||||
break;
|
||||
|
||||
default:
|
||||
$result = array(
|
||||
'success' => false,
|
||||
'error' => 'Unknown event type: ' . $event
|
||||
);
|
||||
}
|
||||
|
||||
// Update log with result
|
||||
if ($log_id) {
|
||||
igny8_update_webhook_log($log_id, array(
|
||||
'status' => $result['success'] ? 'processed' : 'failed',
|
||||
'response' => $result,
|
||||
'processed_at' => current_time('mysql')
|
||||
));
|
||||
}
|
||||
|
||||
return rest_ensure_response($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle task published event
|
||||
*
|
||||
* @param array $data Event data
|
||||
* @return array Result
|
||||
*/
|
||||
private function handle_task_published($data) {
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('success' => false, 'error' => 'Connection disabled');
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('writer')) {
|
||||
return array('success' => false, 'error' => 'Writer module disabled');
|
||||
}
|
||||
|
||||
$task_id = $data['task_id'] ?? null;
|
||||
|
||||
if (!$task_id) {
|
||||
return array('success' => false, 'error' => 'Missing task_id');
|
||||
}
|
||||
|
||||
// Check if post already exists
|
||||
$existing_posts = get_posts(array(
|
||||
'meta_key' => '_igny8_task_id',
|
||||
'meta_value' => $task_id,
|
||||
'post_type' => 'any',
|
||||
'posts_per_page' => 1
|
||||
));
|
||||
|
||||
if (!empty($existing_posts)) {
|
||||
// Post already exists, just update status if needed
|
||||
$post_id = $existing_posts[0]->ID;
|
||||
$status = $data['status'] ?? 'publish';
|
||||
|
||||
if ($status === 'publish' || $status === 'completed') {
|
||||
wp_update_post(array(
|
||||
'ID' => $post_id,
|
||||
'post_status' => 'publish'
|
||||
));
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => 'Post updated',
|
||||
'post_id' => $post_id
|
||||
);
|
||||
}
|
||||
|
||||
// Fetch full task data and create post
|
||||
$api = new Igny8API();
|
||||
$task_response = $api->get("/writer/tasks/{$task_id}/");
|
||||
|
||||
if (!$task_response['success']) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'error' => 'Failed to fetch task: ' . ($task_response['error'] ?? 'Unknown error')
|
||||
);
|
||||
}
|
||||
|
||||
$task = $task_response['data'];
|
||||
$enabled_post_types = igny8_get_enabled_post_types();
|
||||
|
||||
$content_data = array(
|
||||
'task_id' => $task['id'],
|
||||
'title' => $task['title'] ?? 'Untitled',
|
||||
'content' => $task['content'] ?? '',
|
||||
'status' => $task['status'] ?? 'draft',
|
||||
'cluster_id' => $task['cluster_id'] ?? null,
|
||||
'sector_id' => $task['sector_id'] ?? null,
|
||||
'keyword_ids' => $task['keyword_ids'] ?? array(),
|
||||
'content_type' => $task['content_type'] ?? 'post',
|
||||
'categories' => $task['categories'] ?? array(),
|
||||
'tags' => $task['tags'] ?? array(),
|
||||
'featured_image' => $task['featured_image'] ?? null,
|
||||
'gallery_images' => $task['gallery_images'] ?? array(),
|
||||
'meta_title' => $task['meta_title'] ?? null,
|
||||
'meta_description' => $task['meta_description'] ?? null
|
||||
);
|
||||
|
||||
$post_id = igny8_create_wordpress_post_from_task($content_data, $enabled_post_types);
|
||||
|
||||
if (is_wp_error($post_id)) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'error' => $post_id->get_error_message()
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => 'Post created',
|
||||
'post_id' => $post_id
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle link recommendation event
|
||||
*
|
||||
* @param array $data Event data
|
||||
* @return array Result
|
||||
*/
|
||||
private function handle_link_recommendation($data) {
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('success' => false, 'error' => 'Connection disabled');
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('linker')) {
|
||||
return array('success' => false, 'error' => 'Linker module disabled');
|
||||
}
|
||||
|
||||
$post_id = $data['post_id'] ?? null;
|
||||
$target_url = $data['target_url'] ?? null;
|
||||
$anchor = $data['anchor'] ?? $data['anchor_text'] ?? null;
|
||||
|
||||
if (!$post_id || !$target_url || !$anchor) {
|
||||
return array(
|
||||
'success' => false,
|
||||
'error' => 'Missing required parameters: post_id, target_url, anchor'
|
||||
);
|
||||
}
|
||||
|
||||
// Queue link insertion
|
||||
$queued = igny8_queue_link_insertion(array(
|
||||
'post_id' => intval($post_id),
|
||||
'target_url' => esc_url_raw($target_url),
|
||||
'anchor' => sanitize_text_field($anchor),
|
||||
'source' => 'igny8_linker',
|
||||
'priority' => $data['priority'] ?? 'normal',
|
||||
'created_at' => current_time('mysql')
|
||||
));
|
||||
|
||||
if ($queued) {
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => 'Link queued for insertion',
|
||||
'queue_id' => $queued
|
||||
);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => false,
|
||||
'error' => 'Failed to queue link insertion'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle optimizer request event
|
||||
*
|
||||
* @param array $data Event data
|
||||
* @return array Result
|
||||
*/
|
||||
private function handle_optimizer_request($data) {
|
||||
if (!igny8_is_connection_enabled()) {
|
||||
return array('success' => false, 'error' => 'Connection disabled');
|
||||
}
|
||||
|
||||
if (function_exists('igny8_is_module_enabled') && !igny8_is_module_enabled('optimizer')) {
|
||||
return array('success' => false, 'error' => 'Optimizer module disabled');
|
||||
}
|
||||
|
||||
$post_id = $data['post_id'] ?? null;
|
||||
$job_id = $data['job_id'] ?? null;
|
||||
$status = $data['status'] ?? null;
|
||||
$score_changes = $data['score_changes'] ?? null;
|
||||
$recommendations = $data['recommendations'] ?? null;
|
||||
|
||||
if (!$post_id) {
|
||||
return array('success' => false, 'error' => 'Missing post_id');
|
||||
}
|
||||
|
||||
// Update optimizer status if job_id provided
|
||||
if ($job_id) {
|
||||
update_post_meta($post_id, '_igny8_optimizer_job_id', $job_id);
|
||||
}
|
||||
|
||||
if ($status) {
|
||||
update_post_meta($post_id, '_igny8_optimizer_status', $status);
|
||||
}
|
||||
|
||||
if ($score_changes) {
|
||||
update_post_meta($post_id, '_igny8_optimizer_score_changes', $score_changes);
|
||||
}
|
||||
|
||||
if ($recommendations) {
|
||||
update_post_meta($post_id, '_igny8_optimizer_recommendations', $recommendations);
|
||||
}
|
||||
|
||||
return array(
|
||||
'success' => true,
|
||||
'message' => 'Optimizer data updated',
|
||||
'post_id' => $post_id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize webhooks
|
||||
new Igny8Webhooks();
|
||||
|
||||
Reference in New Issue
Block a user