plugin fixes
This commit is contained in:
@@ -220,7 +220,6 @@ class Igny8Admin {
|
||||
*/
|
||||
private function handle_connection() {
|
||||
$api_key = sanitize_text_field($_POST['igny8_api_key'] ?? '');
|
||||
$site_id = sanitize_text_field($_POST['igny8_site_id'] ?? '');
|
||||
|
||||
// API key is required
|
||||
if (empty($api_key)) {
|
||||
@@ -233,12 +232,17 @@ class Igny8Admin {
|
||||
return;
|
||||
}
|
||||
|
||||
// Site ID is required
|
||||
// Extract site_id from API key format: igny8_site_{site_id}_{timestamp}_{random}
|
||||
$site_id = null;
|
||||
if (preg_match('/^igny8_site_(\d+)_/', $api_key, $matches)) {
|
||||
$site_id = (int) $matches[1];
|
||||
}
|
||||
|
||||
if (empty($site_id)) {
|
||||
add_settings_error(
|
||||
'igny8_settings',
|
||||
'igny8_error',
|
||||
__('Site ID is required. Create a site in IGNY8 app first.', 'igny8-bridge'),
|
||||
__('Invalid API key format. Please copy the complete API key from IGNY8 app.', 'igny8-bridge'),
|
||||
'error'
|
||||
);
|
||||
return;
|
||||
@@ -253,7 +257,7 @@ class Igny8Admin {
|
||||
$api = new Igny8API();
|
||||
|
||||
$test_response = $api->post('/v1/integration/integrations/test-connection/', array(
|
||||
'site_id' => (int) $site_id,
|
||||
'site_id' => $site_id,
|
||||
'api_key' => $api_key,
|
||||
'site_url' => $site_url
|
||||
));
|
||||
|
||||
365
igny8-wp-plugin/admin/class-post-meta-boxes.php
Normal file
365
igny8-wp-plugin/admin/class-post-meta-boxes.php
Normal file
@@ -0,0 +1,365 @@
|
||||
<?php
|
||||
/**
|
||||
* Post Meta Boxes
|
||||
*
|
||||
* Handles custom meta boxes for IGNY8-created posts.
|
||||
* Displays keywords, SEO fields, and sync data in WordPress post editor.
|
||||
*
|
||||
* @package IGNY8_Bridge
|
||||
* @since 1.1.0
|
||||
*/
|
||||
|
||||
if (!defined('ABSPATH')) {
|
||||
exit;
|
||||
}
|
||||
|
||||
class IGNY8_Post_Meta_Boxes {
|
||||
|
||||
/**
|
||||
* Initialize meta boxes
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
|
||||
add_action('save_post', array($this, 'save_meta_boxes'), 10, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register meta boxes
|
||||
*/
|
||||
public function add_meta_boxes() {
|
||||
// Only add meta boxes for posts that have IGNY8 content ID
|
||||
$screen = get_current_screen();
|
||||
if ($screen && $screen->post_type === 'post') {
|
||||
// Keywords meta box
|
||||
add_meta_box(
|
||||
'igny8_keywords',
|
||||
__('IGNY8 Keywords', 'igny8-bridge'),
|
||||
array($this, 'render_keywords_meta_box'),
|
||||
'post',
|
||||
'side',
|
||||
'high'
|
||||
);
|
||||
|
||||
// SEO meta box
|
||||
add_meta_box(
|
||||
'igny8_seo',
|
||||
__('IGNY8 SEO', 'igny8-bridge'),
|
||||
array($this, 'render_seo_meta_box'),
|
||||
'post',
|
||||
'normal',
|
||||
'high'
|
||||
);
|
||||
|
||||
// Sync data meta box (read-only info)
|
||||
add_meta_box(
|
||||
'igny8_sync_data',
|
||||
__('IGNY8 Sync Data', 'igny8-bridge'),
|
||||
array($this, 'render_sync_data_meta_box'),
|
||||
'post',
|
||||
'side',
|
||||
'default'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Keywords meta box
|
||||
*/
|
||||
public function render_keywords_meta_box($post) {
|
||||
wp_nonce_field('igny8_keywords_nonce', 'igny8_keywords_nonce');
|
||||
|
||||
$primary_keyword = get_post_meta($post->ID, '_igny8_primary_keyword', true);
|
||||
$secondary_keywords = get_post_meta($post->ID, '_igny8_secondary_keywords', true);
|
||||
|
||||
// Convert comma-separated string to array for display
|
||||
$secondary_keywords_array = !empty($secondary_keywords) ? explode(',', $secondary_keywords) : array();
|
||||
?>
|
||||
<div class="igny8-keywords-fields">
|
||||
<p>
|
||||
<label for="igny8_primary_keyword"><strong><?php _e('Primary Keyword:', 'igny8-bridge'); ?></strong></label><br>
|
||||
<input type="text" id="igny8_primary_keyword" name="igny8_primary_keyword"
|
||||
value="<?php echo esc_attr($primary_keyword); ?>"
|
||||
class="widefat"
|
||||
placeholder="<?php _e('Enter primary keyword', 'igny8-bridge'); ?>">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="igny8_secondary_keywords"><strong><?php _e('Secondary Keywords:', 'igny8-bridge'); ?></strong></label><br>
|
||||
<textarea id="igny8_secondary_keywords" name="igny8_secondary_keywords"
|
||||
rows="3" class="widefat"
|
||||
placeholder="<?php _e('Enter secondary keywords, one per line', 'igny8-bridge'); ?>"><?php
|
||||
echo esc_textarea(implode("\n", $secondary_keywords_array));
|
||||
?></textarea>
|
||||
<span class="description"><?php _e('Enter one keyword per line', 'igny8-bridge'); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.igny8-keywords-fields input[type="text"],
|
||||
.igny8-keywords-fields textarea {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.igny8-keywords-fields .description {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render SEO meta box
|
||||
*/
|
||||
public function render_seo_meta_box($post) {
|
||||
wp_nonce_field('igny8_seo_nonce', 'igny8_seo_nonce');
|
||||
|
||||
$meta_title = get_post_meta($post->ID, '_igny8_meta_title', true);
|
||||
$meta_description = get_post_meta($post->ID, '_igny8_meta_description', true);
|
||||
|
||||
?>
|
||||
<div class="igny8-seo-fields">
|
||||
<p>
|
||||
<label for="igny8_meta_title"><strong><?php _e('SEO Title:', 'igny8-bridge'); ?></strong></label><br>
|
||||
<input type="text" id="igny8_meta_title" name="igny8_meta_title"
|
||||
value="<?php echo esc_attr($meta_title); ?>"
|
||||
class="widefat"
|
||||
placeholder="<?php _e('Enter SEO title', 'igny8-bridge'); ?>"
|
||||
maxlength="60">
|
||||
<span class="description char-count">
|
||||
<?php
|
||||
$title_length = mb_strlen($meta_title);
|
||||
printf(__('%d characters (recommended: 50-60)', 'igny8-bridge'), $title_length);
|
||||
?>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<label for="igny8_meta_description"><strong><?php _e('Meta Description:', 'igny8-bridge'); ?></strong></label><br>
|
||||
<textarea id="igny8_meta_description" name="igny8_meta_description"
|
||||
rows="3" class="widefat"
|
||||
placeholder="<?php _e('Enter meta description', 'igny8-bridge'); ?>"
|
||||
maxlength="160"><?php echo esc_textarea($meta_description); ?></textarea>
|
||||
<span class="description char-count">
|
||||
<?php
|
||||
$desc_length = mb_strlen($meta_description);
|
||||
printf(__('%d characters (recommended: 150-160)', 'igny8-bridge'), $desc_length);
|
||||
?>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p class="description">
|
||||
<strong><?php _e('Note:', 'igny8-bridge'); ?></strong>
|
||||
<?php _e('These SEO fields are synchronized with Yoast SEO, Rank Math, and All in One SEO plugins.', 'igny8-bridge'); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.igny8-seo-fields input[type="text"],
|
||||
.igny8-seo-fields textarea {
|
||||
margin-top: 5px;
|
||||
}
|
||||
.igny8-seo-fields .description {
|
||||
display: block;
|
||||
margin-top: 5px;
|
||||
font-style: italic;
|
||||
color: #666;
|
||||
}
|
||||
.igny8-seo-fields .char-count {
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script>
|
||||
jQuery(document).ready(function($) {
|
||||
// Character counter for SEO title
|
||||
$('#igny8_meta_title').on('input', function() {
|
||||
var length = $(this).val().length;
|
||||
var color = length > 60 ? 'red' : (length < 50 ? 'orange' : 'green');
|
||||
$(this).next('.char-count').text(length + ' characters (recommended: 50-60)').css('color', color);
|
||||
});
|
||||
|
||||
// Character counter for meta description
|
||||
$('#igny8_meta_description').on('input', function() {
|
||||
var length = $(this).val().length;
|
||||
var color = length > 160 ? 'red' : (length < 150 ? 'orange' : 'green');
|
||||
$(this).next('.char-count').text(length + ' characters (recommended: 150-160)').css('color', color);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Render Sync Data meta box (read-only)
|
||||
*/
|
||||
public function render_sync_data_meta_box($post) {
|
||||
$content_id = get_post_meta($post->ID, '_igny8_content_id', true);
|
||||
$task_id = get_post_meta($post->ID, '_igny8_task_id', true);
|
||||
$last_sync = get_post_meta($post->ID, '_igny8_last_sync', true);
|
||||
$cluster_id = get_post_meta($post->ID, '_igny8_cluster_id', true);
|
||||
$sector_id = get_post_meta($post->ID, '_igny8_sector_id', true);
|
||||
|
||||
?>
|
||||
<div class="igny8-sync-data">
|
||||
<?php if ($content_id): ?>
|
||||
<p>
|
||||
<strong><?php _e('IGNY8 Content ID:', 'igny8-bridge'); ?></strong><br>
|
||||
<code><?php echo esc_html($content_id); ?></code>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($task_id): ?>
|
||||
<p>
|
||||
<strong><?php _e('IGNY8 Task ID:', 'igny8-bridge'); ?></strong><br>
|
||||
<code><?php echo esc_html($task_id); ?></code>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($cluster_id): ?>
|
||||
<p>
|
||||
<strong><?php _e('Cluster ID:', 'igny8-bridge'); ?></strong><br>
|
||||
<code><?php echo esc_html($cluster_id); ?></code>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($sector_id): ?>
|
||||
<p>
|
||||
<strong><?php _e('Sector ID:', 'igny8-bridge'); ?></strong><br>
|
||||
<code><?php echo esc_html($sector_id); ?></code>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ($last_sync): ?>
|
||||
<p>
|
||||
<strong><?php _e('Last Synced:', 'igny8-bridge'); ?></strong><br>
|
||||
<?php echo esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), strtotime($last_sync))); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if (!$content_id && !$task_id): ?>
|
||||
<p class="description">
|
||||
<?php _e('This post was not created by IGNY8.', 'igny8-bridge'); ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.igny8-sync-data p {
|
||||
margin: 10px 0;
|
||||
}
|
||||
.igny8-sync-data code {
|
||||
display: inline-block;
|
||||
background: #f0f0f0;
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 12px;
|
||||
}
|
||||
</style>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Save meta boxes
|
||||
*/
|
||||
public function save_meta_boxes($post_id, $post) {
|
||||
// Check if this is an autosave
|
||||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a revision
|
||||
if (wp_is_post_revision($post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check post type
|
||||
if ($post->post_type !== 'post') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check user permissions
|
||||
if (!current_user_can('edit_post', $post_id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Save keywords
|
||||
if (isset($_POST['igny8_keywords_nonce']) && wp_verify_nonce($_POST['igny8_keywords_nonce'], 'igny8_keywords_nonce')) {
|
||||
// Save primary keyword
|
||||
if (isset($_POST['igny8_primary_keyword'])) {
|
||||
$primary_keyword = sanitize_text_field($_POST['igny8_primary_keyword']);
|
||||
update_post_meta($post_id, '_igny8_primary_keyword', $primary_keyword);
|
||||
}
|
||||
|
||||
// Save secondary keywords
|
||||
if (isset($_POST['igny8_secondary_keywords'])) {
|
||||
$secondary_keywords_raw = sanitize_textarea_field($_POST['igny8_secondary_keywords']);
|
||||
// Convert newlines to commas for storage
|
||||
$secondary_keywords_array = array_filter(array_map('trim', explode("\n", $secondary_keywords_raw)));
|
||||
$secondary_keywords = implode(',', $secondary_keywords_array);
|
||||
update_post_meta($post_id, '_igny8_secondary_keywords', $secondary_keywords);
|
||||
}
|
||||
}
|
||||
|
||||
// Save SEO fields
|
||||
if (isset($_POST['igny8_seo_nonce']) && wp_verify_nonce($_POST['igny8_seo_nonce'], 'igny8_seo_nonce')) {
|
||||
// Save meta title
|
||||
if (isset($_POST['igny8_meta_title'])) {
|
||||
$meta_title = sanitize_text_field($_POST['igny8_meta_title']);
|
||||
update_post_meta($post_id, '_igny8_meta_title', $meta_title);
|
||||
|
||||
// Also update for SEO plugins
|
||||
$this->sync_seo_title($post_id, $meta_title);
|
||||
}
|
||||
|
||||
// Save meta description
|
||||
if (isset($_POST['igny8_meta_description'])) {
|
||||
$meta_description = sanitize_textarea_field($_POST['igny8_meta_description']);
|
||||
update_post_meta($post_id, '_igny8_meta_description', $meta_description);
|
||||
|
||||
// Also update for SEO plugins
|
||||
$this->sync_seo_description($post_id, $meta_description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync SEO title to popular SEO plugins
|
||||
*/
|
||||
private function sync_seo_title($post_id, $title) {
|
||||
if (empty($title)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Yoast SEO
|
||||
update_post_meta($post_id, '_yoast_wpseo_title', $title);
|
||||
|
||||
// Rank Math
|
||||
update_post_meta($post_id, 'rank_math_title', $title);
|
||||
|
||||
// All in One SEO
|
||||
update_post_meta($post_id, '_aioseo_title', $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync SEO description to popular SEO plugins
|
||||
*/
|
||||
private function sync_seo_description($post_id, $description) {
|
||||
if (empty($description)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Yoast SEO
|
||||
update_post_meta($post_id, '_yoast_wpseo_metadesc', $description);
|
||||
|
||||
// Rank Math
|
||||
update_post_meta($post_id, 'rank_math_description', $description);
|
||||
|
||||
// All in One SEO
|
||||
update_post_meta($post_id, '_aioseo_description', $description);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize
|
||||
new IGNY8_Post_Meta_Boxes();
|
||||
@@ -92,29 +92,6 @@ $default_post_status = get_option('igny8_default_post_status', 'draft');
|
||||
<form method="post" action="">
|
||||
<?php wp_nonce_field('igny8_settings_nonce'); ?>
|
||||
|
||||
<div class="igny8-api-form-group">
|
||||
<label for="igny8_site_id">
|
||||
<?php _e('Site ID', 'igny8-bridge'); ?>
|
||||
<span style="color: #EF4444;">*</span>
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="igny8_site_id"
|
||||
name="igny8_site_id"
|
||||
value=""
|
||||
placeholder="<?php _e('e.g., 123', 'igny8-bridge'); ?>"
|
||||
required
|
||||
/>
|
||||
<p class="igny8-api-form-description">
|
||||
<?php _e('The numeric Site ID from your IGNY8 app. You can find it in several ways:', 'igny8-bridge'); ?>
|
||||
</p>
|
||||
<ul style="margin-left: 20px; margin-top: 8px; color: #6B7280;">
|
||||
<li><?php _e('In the Site Settings page URL: look for a number after "/sites/" (e.g., https://app.igny8.com/sites/123/settings → Site ID is 123)', 'igny8-bridge'); ?></li>
|
||||
<li><?php _e('In your IGNY8 dashboard: navigate to Settings → Sites, and the Site ID is displayed next to each site', 'igny8-bridge'); ?></li>
|
||||
<li><?php _e('From your account admin: contact your IGNY8 account administrator if you need help finding your Site ID', 'igny8-bridge'); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="igny8-api-form-group">
|
||||
<label for="igny8_api_key">
|
||||
<?php _e('API Key', 'igny8-bridge'); ?>
|
||||
@@ -125,13 +102,13 @@ $default_post_status = get_option('igny8_default_post_status', 'draft');
|
||||
id="igny8_api_key"
|
||||
name="igny8_api_key"
|
||||
value=""
|
||||
placeholder="<?php _e('sk_live_xxxxxxxxxxxxx', 'igny8-bridge'); ?>"
|
||||
placeholder="<?php _e('igny8_site_5_1764575388582_u671q2e2mv', 'igny8-bridge'); ?>"
|
||||
required
|
||||
/>
|
||||
<p class="igny8-api-form-description">
|
||||
<?php printf(
|
||||
__('Get your API key from the <a href="%s" target="_blank">IGNY8 app integrations page</a>. It starts with "sk_live_" or "sk_test_".', 'igny8-bridge'),
|
||||
'https://app.igny8.com/sites/5/settings?tab=integrations'
|
||||
__('Get your API key from the <a href="%s" target="_blank">IGNY8 app integrations page</a>. The API key format includes your site ID.', 'igny8-bridge'),
|
||||
'https://app.igny8.com'
|
||||
); ?>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -682,18 +682,49 @@ function igny8_process_categories($categories, $post_id) {
|
||||
}
|
||||
// If it's a string (name or slug)
|
||||
elseif (is_string($category)) {
|
||||
$term = get_term_by('slug', $category, 'category');
|
||||
if (!$term) {
|
||||
$term = get_term_by('name', $category, 'category');
|
||||
}
|
||||
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$term_id = $term->term_id;
|
||||
// Check if it's a hierarchical category (e.g., "Gardening > Plant Care")
|
||||
if (strpos($category, ' > ') !== false) {
|
||||
$parts = array_map('trim', explode(' > ', $category));
|
||||
$parent_id = 0;
|
||||
|
||||
// Process each level of the hierarchy
|
||||
foreach ($parts as $part) {
|
||||
$term = get_term_by('name', $part, 'category');
|
||||
|
||||
if (!$term || is_wp_error($term)) {
|
||||
// Create term with parent
|
||||
$term_result = wp_insert_term($part, 'category', array(
|
||||
'parent' => $parent_id,
|
||||
'slug' => sanitize_title($part)
|
||||
));
|
||||
if (!is_wp_error($term_result)) {
|
||||
$parent_id = $term_result['term_id'];
|
||||
$term_id = $term_result['term_id']; // Last one is what we assign
|
||||
}
|
||||
} else {
|
||||
// Update parent if it doesn't match
|
||||
if ($parent_id > 0 && $term->parent != $parent_id) {
|
||||
wp_update_term($term->term_id, 'category', array('parent' => $parent_id));
|
||||
}
|
||||
$parent_id = $term->term_id;
|
||||
$term_id = $term->term_id; // Last one is what we assign
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create new category
|
||||
$term_result = wp_insert_term($category, 'category');
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
// Simple category (no hierarchy)
|
||||
$term = get_term_by('slug', $category, 'category');
|
||||
if (!$term) {
|
||||
$term = get_term_by('name', $category, 'category');
|
||||
}
|
||||
|
||||
if ($term && !is_wp_error($term)) {
|
||||
$term_id = $term->term_id;
|
||||
} else {
|
||||
// Create new category
|
||||
$term_result = wp_insert_term($category, 'category');
|
||||
if (!is_wp_error($term_result)) {
|
||||
$term_id = $term_result['term_id'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user