Changeset 3249839
- Timestamp:
- 03/03/2025 04:50:27 PM (12 months ago)
- Location:
- one-click-seo-optimizer/trunk
- Files:
-
- 4 edited
-
includes/class-oneclickseo-admin.php (modified) (27 diffs)
-
includes/class-oneclickseo-api.php (modified) (14 diffs)
-
oneclickseo.php (modified) (5 diffs)
-
readme.txt (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
one-click-seo-optimizer/trunk/includes/class-oneclickseo-admin.php
r3249837 r3249839 3 3 class OneClickSEO_Admin { 4 4 public function __construct() { 5 add_action( 'admin_menu', array($this, 'add_admin_menu'));6 add_action( 'admin_init', array($this, 'register_settings'));7 add_action( 'admin_enqueue_scripts', array($this, 'enqueue_scripts'));8 add_action( 'add_meta_boxes', array($this, 'add_seo_meta_box'));9 add_action( 'save_post', array($this, 'save_seo_meta_box'));10 add_filter( 'admin_body_class', array($this, 'add_pro_body_class'));5 add_action( 'admin_menu', array($this, 'add_admin_menu') ); 6 add_action( 'admin_init', array($this, 'register_settings') ); 7 add_action( 'admin_enqueue_scripts', array($this, 'enqueue_scripts') ); 8 add_action( 'add_meta_boxes', array($this, 'add_seo_meta_box') ); 9 add_action( 'save_post', array($this, 'save_seo_meta_box') ); 10 add_filter( 'admin_body_class', array($this, 'add_pro_body_class') ); 11 11 } 12 12 13 13 public function add_admin_menu() { 14 14 add_menu_page( 15 __( 'OneClick SEO', 'one-click-seo-optimizer'),16 __( 'OneClick SEO', 'one-click-seo-optimizer'),15 __( 'OneClick SEO', 'one-click-seo-optimizer' ), 16 __( 'OneClick SEO', 'one-click-seo-optimizer' ), 17 17 'manage_options', 18 18 'oneclickseo', … … 22 22 ); 23 23 } 24 25 public function add_pro_body_class($classes) { 26 if(is_array($classes)) { 27 if (oneoneclickseo_fs()->is__premium_only()) { 28 $classes[] = 'oneclickseo-pro'; 29 } else { 30 $classes[] = 'oneclickseo-free'; 31 } 24 25 public function add_pro_body_class( $classes ) { 26 if ( is_array( $classes ) ) { 27 $classes[] = 'oneclickseo-free'; 32 28 } else { 33 if (oneoneclickseo_fs()->is__premium_only()) { 34 $classes = 'oneclickseo-pro'; 35 } else { 36 $classes = 'oneclickseo-free'; 37 } 29 $classes = 'oneclickseo-free'; 38 30 } 39 31 return $classes; … … 41 33 42 34 public function register_settings() { 43 register_setting( 'oneclickseo_settings', 'oneclickseo_api_key', array(44 'type' => 'string',45 'description' => 'API Key for OneClick SEO',46 'sanitize_callback' => function ($input) {47 if ( !is_string($input)) {35 register_setting( 'oneclickseo_settings', 'oneclickseo_api_key', array( 36 'type' => 'string', 37 'description' => 'API Key for OneClick SEO', 38 'sanitize_callback' => function ( $input ) { 39 if ( !is_string( $input ) ) { 48 40 return ''; 49 41 } 50 return sanitize_text_field( $input);42 return sanitize_text_field( $input ); 51 43 }, 52 'show_in_rest' => false,53 'default' => ''54 ) );55 register_setting( 'oneclickseo_settings', 'oneclickseo_model', array(56 'type' => 'string',57 'description' => 'OpenAI model to use',58 'sanitize_callback' => function ($input) {59 if ( !is_string($input)) {44 'show_in_rest' => false, 45 'default' => '', 46 ) ); 47 register_setting( 'oneclickseo_settings', 'oneclickseo_model', array( 48 'type' => 'string', 49 'description' => 'OpenAI model to use', 50 'sanitize_callback' => function ( $input ) { 51 if ( !is_string( $input ) ) { 60 52 return 'gpt-4'; 61 53 } 62 54 $allowed_models = array('gpt-4o', 'gpt-3.5-turbo', 'gpt-4.5-preview'); 63 $sanitized = sanitize_text_field( $input);64 return in_array($sanitized, $allowed_models) ? $sanitized : 'gpt-4o';55 $sanitized = sanitize_text_field( $input ); 56 return ( in_array( $sanitized, $allowed_models ) ? $sanitized : 'gpt-4o' ); 65 57 }, 66 'show_in_rest' => false,67 'default' => 'gpt-4'68 ) );58 'show_in_rest' => false, 59 'default' => 'gpt-4', 60 ) ); 69 61 } 70 62 71 63 public function render_admin_page() { 72 $nonce = isset($_GET['_tabnonce']) ? sanitize_text_field(wp_unslash($_GET['_tabnonce'])) : '';73 if ( empty($nonce) || !wp_verify_nonce($nonce, 'oneclickseo_tab_nonce')) {64 $nonce = ( isset( $_GET['_tabnonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_tabnonce'] ) ) : '' ); 65 if ( empty( $nonce ) || !wp_verify_nonce( $nonce, 'oneclickseo_tab_nonce' ) ) { 74 66 $current_tab = 'optimization'; 75 67 } else { 76 $current_tab = isset($_GET['tab']) ? sanitize_text_field(wp_unslash($_GET['tab'])) : 'optimization'; 77 } 78 79 $tab_nonce = wp_create_nonce('oneclickseo_tab_nonce'); 68 $current_tab = ( isset( $_GET['tab'] ) ? sanitize_text_field( wp_unslash( $_GET['tab'] ) ) : 'optimization' ); 69 } 70 $tab_nonce = wp_create_nonce( 'oneclickseo_tab_nonce' ); 80 71 ?> 81 72 <div class="wrap oneclickseo-admin"> 82 <h1><?php esc_html_e('OneClick SEO - Configuration', 'one-click-seo-optimizer'); ?></h1> 73 <h1><?php 74 esc_html_e( 'OneClick SEO - Configuration', 'one-click-seo-optimizer' ); 75 ?></h1> 83 76 84 77 <nav class="oneclickseo-tabs"> 85 <a href="?page=oneclickseo&tab=optimization&_tabnonce=<?php echo esc_attr($tab_nonce); ?>" class="<?php echo $current_tab === 'optimization' ? 'active' : ''; ?>"> 78 <a href="?page=oneclickseo&tab=optimization&_tabnonce=<?php 79 echo esc_attr( $tab_nonce ); 80 ?>" class="<?php 81 echo ( $current_tab === 'optimization' ? 'active' : '' ); 82 ?>"> 86 83 <span class="dashicons dashicons-analytics"></span> 87 <?php esc_html_e('Optimization', 'one-click-seo-optimizer'); ?> 84 <?php 85 esc_html_e( 'Optimization', 'one-click-seo-optimizer' ); 86 ?> 88 87 </a> 89 <a href="?page=oneclickseo&tab=settings&_tabnonce=<?php echo esc_attr($tab_nonce); ?>" class="<?php echo $current_tab === 'settings' ? 'active' : ''; ?>"> 88 <a href="?page=oneclickseo&tab=settings&_tabnonce=<?php 89 echo esc_attr( $tab_nonce ); 90 ?>" class="<?php 91 echo ( $current_tab === 'settings' ? 'active' : '' ); 92 ?>"> 90 93 <span class="dashicons dashicons-admin-generic"></span> 91 <?php esc_html_e('Settings', 'one-click-seo-optimizer'); ?> 94 <?php 95 esc_html_e( 'Settings', 'one-click-seo-optimizer' ); 96 ?> 92 97 </a> 93 <a href="?page=oneclickseo&tab=website&_tabnonce=<?php echo esc_attr($tab_nonce); ?>" class="<?php echo $current_tab === 'website' ? 'active' : ''; ?>"> 98 <a href="?page=oneclickseo&tab=website&_tabnonce=<?php 99 echo esc_attr( $tab_nonce ); 100 ?>" class="<?php 101 echo ( $current_tab === 'website' ? 'active' : '' ); 102 ?>"> 94 103 <span class="dashicons dashicons-admin-site"></span> 95 <?php esc_html_e('My website', 'one-click-seo-optimizer'); ?> 104 <?php 105 esc_html_e( 'My website', 'one-click-seo-optimizer' ); 106 ?> 96 107 </a> 97 108 </nav> 98 109 99 110 <div class="oneclickseo-container"> 100 <?php 101 switch ($current_tab) {102 case 'settings':103 $this->render_settings_tab();104 break;105 case 'website':106 $this->render_website_tab();107 break;108 case 'optimization':109 $this->render_optimization_tab();110 break;111 }112 ?>111 <?php 112 switch ( $current_tab ) { 113 case 'settings': 114 $this->render_settings_tab(); 115 break; 116 case 'website': 117 $this->render_website_tab(); 118 break; 119 case 'optimization': 120 $this->render_optimization_tab(); 121 break; 122 } 123 ?> 113 124 </div> 114 125 </div> 115 <?php 126 <?php 116 127 } 117 128 … … 121 132 122 133 <form method="post" action="options.php"> 123 <?php 124 settings_fields('oneclickseo_settings'); 125 do_settings_sections('oneclickseo_settings'); 126 ?> 127 128 <?php submit_button(); ?> 134 <?php 135 settings_fields( 'oneclickseo_settings' ); 136 do_settings_sections( 'oneclickseo_settings' ); 137 ?> 138 139 <?php 140 submit_button(); 141 ?> 129 142 </form> 130 143 </div> 131 <?php 144 <?php 132 145 } 133 146 134 147 private function render_website_tab() { 135 $analysis = get_option('oneclickseo_site_analysis'); 136 137 if (!empty($analysis) && is_string($analysis)) { 138 $analysis = json_decode($analysis, true); 139 } 140 141 if (!is_array($analysis)) { 148 $analysis = get_option( 'oneclickseo_site_analysis' ); 149 if ( !empty( $analysis ) && is_string( $analysis ) ) { 150 $analysis = json_decode( $analysis, true ); 151 } 152 if ( !is_array( $analysis ) ) { 142 153 $analysis = array(); 143 154 } 144 145 155 $upload_dir = wp_upload_dir(); 146 156 $sitemap_url = $upload_dir['baseurl'] . '/sitemaps/sitemap.xml'; 147 157 $sitemap_path = $upload_dir['basedir'] . '/sitemaps/sitemap.xml'; 148 $sitemap_exists = file_exists($sitemap_path); 149 // $analysis = array(); 150 151 if (isset($_POST['oneclickseo_save_analysis']) && check_admin_referer('oneclickseo_edit_analysis')) { 152 if(isset($_POST['description_site']) 153 && isset($_POST['objectif']) 154 && isset($_POST['audience_cible']) 155 && isset($_POST['thematique']) 156 && isset($_POST['mots_clefs'])) { 157 $analysis = array( 158 'description_site' => sanitize_textarea_field(wp_unslash($_POST['description_site'])), 159 'objectif' => sanitize_textarea_field(wp_unslash($_POST['objectif'])), 160 'audience_cible' => sanitize_textarea_field(wp_unslash($_POST['audience_cible'])), 161 'thematique' => sanitize_textarea_field(wp_unslash($_POST['thematique'])), 162 'mots_clefs' => array_map('sanitize_text_field', array_map('trim', explode(',', sanitize_text_field(wp_unslash($_POST['mots_clefs']))))) 163 ); 164 165 update_option('oneclickseo_site_analysis', $analysis); 166 echo '<div class="notice notice-success"><p>' . esc_html__('Changes saved successfully.', 'one-click-seo-optimizer') . '</p></div>'; 167 } 158 $sitemap_exists = file_exists( $sitemap_path ); 159 // $analysis = array(); 160 if ( isset( $_POST['oneclickseo_save_analysis'] ) && check_admin_referer( 'oneclickseo_edit_analysis' ) ) { 161 if ( isset( $_POST['description_site'] ) && isset( $_POST['objectif'] ) && isset( $_POST['audience_cible'] ) && isset( $_POST['thematique'] ) && isset( $_POST['mots_clefs'] ) ) { 162 $analysis = array( 163 'description_site' => sanitize_textarea_field( wp_unslash( $_POST['description_site'] ) ), 164 'objectif' => sanitize_textarea_field( wp_unslash( $_POST['objectif'] ) ), 165 'audience_cible' => sanitize_textarea_field( wp_unslash( $_POST['audience_cible'] ) ), 166 'thematique' => sanitize_textarea_field( wp_unslash( $_POST['thematique'] ) ), 167 'mots_clefs' => array_map( 'sanitize_text_field', array_map( 'trim', explode( ',', sanitize_text_field( wp_unslash( $_POST['mots_clefs'] ) ) ) ) ), 168 ); 169 update_option( 'oneclickseo_site_analysis', $analysis ); 170 echo '<div class="notice notice-success"><p>' . esc_html__( 'Changes saved successfully.', 'one-click-seo-optimizer' ) . '</p></div>'; 171 } 168 172 } 169 173 ?> … … 171 175 <div class="oneclickseo-card oneclickseo-header-card"> 172 176 <div class="site-status"> 173 <div class="status-icon <?php echo !empty($analysis) ? 'active' : 'inactive'; ?>"> 174 <span class="dashicons <?php echo !empty($analysis) ? 'dashicons-yes-alt' : 'dashicons-warning'; ?>"></span> 177 <div class="status-icon <?php 178 echo ( !empty( $analysis ) ? 'active' : 'inactive' ); 179 ?>"> 180 <span class="dashicons <?php 181 echo ( !empty( $analysis ) ? 'dashicons-yes-alt' : 'dashicons-warning' ); 182 ?>"></span> 175 183 </div> 176 184 <div class="status-info"> 177 <h2><?php esc_html_e('Site Status', 'one-click-seo-optimizer'); ?></h2> 178 <p><?php echo !empty($analysis) ? 179 esc_html__('Your site has been analyzed and is being optimized.', 'one-click-seo-optimizer') : 180 esc_html__('Your site has not been analyzed yet.', 'one-click-seo-optimizer'); ?></p> 181 </div> 182 </div> 183 <?php if (empty($analysis)) : ?> 185 <h2><?php 186 esc_html_e( 'Site Status', 'one-click-seo-optimizer' ); 187 ?></h2> 188 <p><?php 189 echo ( !empty( $analysis ) ? esc_html__( 'Your site has been analyzed and is being optimized.', 'one-click-seo-optimizer' ) : esc_html__( 'Your site has not been analyzed yet.', 'one-click-seo-optimizer' ) ); 190 ?></p> 191 </div> 192 </div> 193 <?php 194 if ( empty( $analysis ) ) { 195 ?> 184 196 <div class="oneclickseo-cta-buttons"> 185 197 <a href="?page=oneclickseo&tab=optimization" class="oneclickseo-button"> 186 <?php esc_html_e('Start Analysis Now', 'one-click-seo-optimizer'); ?> 198 <?php 199 esc_html_e( 'Start Analysis Now', 'one-click-seo-optimizer' ); 200 ?> 187 201 <span class="dashicons dashicons-arrow-right-alt"></span> 188 202 </a> 189 203 </div> 190 <?php endif; ?> 191 </div> 192 193 <?php if (!empty($analysis)) : ?> 204 <?php 205 } 206 ?> 207 </div> 208 209 <?php 210 if ( !empty( $analysis ) ) { 211 ?> 194 212 <form method="post" action="" class="oneclickseo-edit-form"> 195 <?php wp_nonce_field('oneclickseo_edit_analysis'); ?> 213 <?php 214 wp_nonce_field( 'oneclickseo_edit_analysis' ); 215 ?> 196 216 197 217 <div class="oneclickseo-card oneclickseo-main-info"> 198 218 <div class="info-header"> 199 <h2><?php esc_html_e('General Overview', 'one-click-seo-optimizer'); ?></h2> 219 <h2><?php 220 esc_html_e( 'General Overview', 'one-click-seo-optimizer' ); 221 ?></h2> 200 222 <span class="last-update"> 201 223 <?php 202 $last_update = get_option('oneclickseo_last_analysis', current_time('timestamp'));203 printf(204 /* translators: %s: date and time */205 esc_html__('Last updated: %s', 'one-click-seo-optimizer'),206 esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $last_update))207 );208 ?>224 $last_update = get_option( 'oneclickseo_last_analysis', current_time( 'timestamp' ) ); 225 printf( 226 /* translators: %s: date and time */ 227 esc_html__( 'Last updated: %s', 'one-click-seo-optimizer' ), 228 esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $last_update ) ) 229 ); 230 ?> 209 231 </span> 210 232 </div> … … 214 236 <div class="item-header"> 215 237 <span class="item-icon">🎯</span> 216 <h3><?php esc_html_e('Site Description', 'one-click-seo-optimizer'); ?></h3> 238 <h3><?php 239 esc_html_e( 'Site Description', 'one-click-seo-optimizer' ); 240 ?></h3> 217 241 </div> 218 242 <textarea name="description_site" class="widefat" rows="4"><?php 219 echo isset($analysis['description_site']) ? esc_textarea($analysis['description_site']) : '';220 ?></textarea>243 echo ( isset( $analysis['description_site'] ) ? esc_textarea( $analysis['description_site'] ) : '' ); 244 ?></textarea> 221 245 </div> 222 246 … … 224 248 <div class="item-header"> 225 249 <span class="item-icon">🎯</span> 226 <h3><?php esc_html_e('Objective', 'one-click-seo-optimizer'); ?></h3> 250 <h3><?php 251 esc_html_e( 'Objective', 'one-click-seo-optimizer' ); 252 ?></h3> 227 253 </div> 228 254 <textarea name="objectif" class="widefat" rows="4"><?php 229 echo isset($analysis['objectif']) ? esc_textarea($analysis['objectif']) : '';230 ?></textarea>255 echo ( isset( $analysis['objectif'] ) ? esc_textarea( $analysis['objectif'] ) : '' ); 256 ?></textarea> 231 257 </div> 232 258 </div> … … 236 262 <div class="item-header"> 237 263 <span class="item-icon">👥</span> 238 <h3><?php esc_html_e('Target Audience', 'one-click-seo-optimizer'); ?></h3> 264 <h3><?php 265 esc_html_e( 'Target Audience', 'one-click-seo-optimizer' ); 266 ?></h3> 239 267 </div> 240 268 <textarea name="audience_cible" class="widefat" rows="4"><?php 241 echo isset($analysis['audience_cible']) ? esc_textarea($analysis['audience_cible']) : '';242 ?></textarea>269 echo ( isset( $analysis['audience_cible'] ) ? esc_textarea( $analysis['audience_cible'] ) : '' ); 270 ?></textarea> 243 271 </div> 244 272 … … 246 274 <div class="item-header"> 247 275 <span class="item-icon">📚</span> 248 <h3><?php esc_html_e('Theme', 'one-click-seo-optimizer'); ?></h3> 276 <h3><?php 277 esc_html_e( 'Theme', 'one-click-seo-optimizer' ); 278 ?></h3> 249 279 </div> 250 280 <textarea name="thematique" class="widefat" rows="4"><?php 251 echo isset($analysis['thematique']) ? esc_textarea($analysis['thematique']) : '';252 ?></textarea>281 echo ( isset( $analysis['thematique'] ) ? esc_textarea( $analysis['thematique'] ) : '' ); 282 ?></textarea> 253 283 </div> 254 284 </div> … … 258 288 <div class="item-header"> 259 289 <span class="item-icon">🔑</span> 260 <h3><?php esc_html_e('Main Keywords', 'one-click-seo-optimizer'); ?></h3> 290 <h3><?php 291 esc_html_e( 'Main Keywords', 'one-click-seo-optimizer' ); 292 ?></h3> 261 293 </div> 262 294 <div class="oneclickseo-keywords-edit"> 263 295 <textarea name="mots_clefs" class="widefat" rows="2" placeholder="<?php 264 esc_attr_e('Enter your keywords separated by commas', 'one-click-seo-optimizer');265 ?>"><?php266 echo isset($analysis['mots_clefs']) ? esc_textarea(implode(', ', $analysis['mots_clefs'])) : '';267 ?></textarea>296 esc_attr_e( 'Enter your keywords separated by commas', 'one-click-seo-optimizer' ); 297 ?>"><?php 298 echo ( isset( $analysis['mots_clefs'] ) ? esc_textarea( implode( ', ', $analysis['mots_clefs'] ) ) : '' ); 299 ?></textarea> 268 300 </div> 269 301 </div> … … 272 304 <div class="item-header"> 273 305 <span class="item-icon">🗺️</span> 274 <h3><?php esc_html_e('Sitemap XML', 'one-click-seo-optimizer'); ?></h3> 306 <h3><?php 307 esc_html_e( 'Sitemap XML', 'one-click-seo-optimizer' ); 308 ?></h3> 275 309 </div> 276 310 <div class="oneclickseo-sitemap-info"> 277 <?php if ($sitemap_exists) : ?> 278 <p><?php esc_html_e('Your sitemap is available at:', 'one-click-seo-optimizer'); ?></p> 311 <?php 312 if ( $sitemap_exists ) { 313 ?> 314 <p><?php 315 esc_html_e( 'Your sitemap is available at:', 'one-click-seo-optimizer' ); 316 ?></p> 279 317 <div class="sitemap-url"> 280 <a href="<?php echo esc_url($sitemap_url); ?>" target="_blank"> 281 <?php echo esc_html($sitemap_url); ?> 318 <a href="<?php 319 echo esc_url( $sitemap_url ); 320 ?>" target="_blank"> 321 <?php 322 echo esc_html( $sitemap_url ); 323 ?> 282 324 <span class="dashicons dashicons-external"></span> 283 325 </a> 284 326 </div> 285 <?php else : ?> 286 <p class="no-sitemap"><?php esc_html_e('No sitemap has been generated yet. Use the optimization options to generate one.', 'one-click-seo-optimizer'); ?></p> 287 <?php endif; ?> 327 <?php 328 } else { 329 ?> 330 <p class="no-sitemap"><?php 331 esc_html_e( 'No sitemap has been generated yet. Use the optimization options to generate one.', 'one-click-seo-optimizer' ); 332 ?></p> 333 <?php 334 } 335 ?> 288 336 </div> 289 337 </div> … … 293 341 <button type="submit" name="oneclickseo_save_analysis" class="oneclickseo-button"> 294 342 <span class="dashicons dashicons-saved"></span> 295 <?php esc_html_e('Save Changes', 'one-click-seo-optimizer'); ?> 343 <?php 344 esc_html_e( 'Save Changes', 'one-click-seo-optimizer' ); 345 ?> 296 346 </button> 297 347 … … 299 349 </div> 300 350 </form> 301 <?php endif; ?> 351 <?php 352 } 353 ?> 302 354 303 355 304 356 </div> 305 <?php 357 <?php 306 358 } 307 359 … … 309 361 ?> 310 362 <div class="oneclickseo-card"> 311 <h2><?php esc_html_e('Global Optimization', 'one-click-seo-optimizer'); ?></h2> 312 <p><?php esc_html_e('Click the button below to start the complete SEO optimization of your site.', 'one-click-seo-optimizer'); ?></p> 363 <h2><?php 364 esc_html_e( 'Global Optimization', 'one-click-seo-optimizer' ); 365 ?></h2> 366 <p><?php 367 esc_html_e( 'Click the button below to start the complete SEO optimization of your site.', 'one-click-seo-optimizer' ); 368 ?></p> 313 369 314 370 <div class="oneclickseo-options-toggle"> 315 371 <button class="oneclickseo-toggle-button"> 316 372 <span class="dashicons dashicons-admin-generic"></span> 317 <?php esc_html_e('Optimization Options', 'one-click-seo-optimizer'); ?> 373 <?php 374 esc_html_e( 'Optimization Options', 'one-click-seo-optimizer' ); 375 ?> 318 376 <span class="dashicons dashicons-arrow-down-alt2"></span> 319 377 </button> … … 324 382 <label> 325 383 <input type="checkbox" name="optimize_page_details" checked> 326 <?php esc_html_e('Pages objectives and audiences', 'one-click-seo-optimizer'); ?> 384 <?php 385 esc_html_e( 'Pages objectives and audiences', 'one-click-seo-optimizer' ); 386 ?> 327 387 </label> 328 388 </div> 329 389 <div class="oneclickseo-option oneclickseo-pro-option"> 330 390 <label> 331 <input type="checkbox" name="generate_structured_data" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 332 <?php esc_html_e('Generate Structured Data (Schema.org)', 'one-click-seo-optimizer'); ?> 391 <input type="checkbox" name="generate_structured_data" <?php 392 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 393 ?>> 394 <?php 395 esc_html_e( 'Generate Structured Data (Schema.org)', 'one-click-seo-optimizer' ); 396 ?> 333 397 <span class="pro-badge">PRO</span> 334 398 </label> … … 336 400 <div class="oneclickseo-option oneclickseo-pro-option"> 337 401 <label> 338 <input type="checkbox" name="optimize_images" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 339 <?php esc_html_e('Optimize images SEO (alt text, title, description)', 'one-click-seo-optimizer'); ?> 402 <input type="checkbox" name="optimize_images" <?php 403 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 404 ?>> 405 <?php 406 esc_html_e( 'Optimize images SEO (alt text, title, description)', 'one-click-seo-optimizer' ); 407 ?> 340 408 <span class="pro-badge">PRO</span> 341 409 … … 345 413 <label> 346 414 <input type="checkbox" name="optimize_metas" checked> 347 <?php esc_html_e('Optimize meta titles and descriptions', 'one-click-seo-optimizer'); ?> 415 <?php 416 esc_html_e( 'Optimize meta titles and descriptions', 'one-click-seo-optimizer' ); 417 ?> 348 418 </label> 349 419 </div> 350 420 <div class="oneclickseo-option oneclickseo-pro-option"> 351 421 <label> 352 <input type="checkbox" name="optimize_headings" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 353 <?php esc_html_e('Heading tags structure (H1-H6) suggestions', 'one-click-seo-optimizer'); ?> 422 <input type="checkbox" name="optimize_headings" <?php 423 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 424 ?>> 425 <?php 426 esc_html_e( 'Heading tags structure (H1-H6) suggestions', 'one-click-seo-optimizer' ); 427 ?> 354 428 <span class="pro-badge">PRO</span> 355 429 … … 359 433 <div class="oneclickseo-option oneclickseo-pro-option"> 360 434 <label> 361 <input type="checkbox" name="internal_link_suggestions" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 362 <?php esc_html_e('Internal links suggestions', 'one-click-seo-optimizer'); ?> 435 <input type="checkbox" name="internal_link_suggestions" <?php 436 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 437 ?>> 438 <?php 439 esc_html_e( 'Internal links suggestions', 'one-click-seo-optimizer' ); 440 ?> 363 441 <span class="pro-badge">PRO</span> 364 442 </label> … … 368 446 <label> 369 447 <input type="checkbox" name="generate_sitemap" checked> 370 <?php esc_html_e('Generate a sitemap.xml file', 'one-click-seo-optimizer'); ?> 448 <?php 449 esc_html_e( 'Generate a sitemap.xml file', 'one-click-seo-optimizer' ); 450 ?> 371 451 </label> 372 452 </div> 373 453 <div class="oneclickseo-option oneclickseo-pro-option "> 374 454 <label> 375 <input type="checkbox" name="content_suggestions" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 376 <?php esc_html_e('Content suggestions', 'one-click-seo-optimizer'); ?> 455 <input type="checkbox" name="content_suggestions" <?php 456 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 457 ?>> 458 <?php 459 esc_html_e( 'Content suggestions', 'one-click-seo-optimizer' ); 460 ?> 377 461 <span class="pro-badge">PRO</span> 378 462 </label> … … 380 464 <div class="oneclickseo-option oneclickseo-pro-option"> 381 465 <label> 382 <input type="checkbox" name="optimize_scores" <?php echo oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled'; ?>> 383 <?php esc_html_e('Readability & Content Scores', 'one-click-seo-optimizer'); ?> 466 <input type="checkbox" name="optimize_scores" <?php 467 echo ( oneoneclickseo_fs()->is__premium_only() ? 'checked' : 'disabled' ); 468 ?>> 469 <?php 470 esc_html_e( 'Readability & Content Scores', 'one-click-seo-optimizer' ); 471 ?> 384 472 <span class="pro-badge">PRO</span> 385 473 </label> … … 390 478 <button id="oneclickseo-optimize-all" class=""> 391 479 <span role="img" aria-label="rocket emoji">🔨</span> 392 <?php esc_html_e('Do all the SEO work buddy', 'one-click-seo-optimizer'); ?> 480 <?php 481 esc_html_e( 'Do all the SEO work buddy', 'one-click-seo-optimizer' ); 482 ?> 393 483 </button> 394 484 395 485 <button id="oneclickseo-stop-optimize" class=""> 396 <?php esc_html_e('Stop Optimization', 'one-click-seo-optimizer'); ?> 486 <?php 487 esc_html_e( 'Stop Optimization', 'one-click-seo-optimizer' ); 488 ?> 397 489 </button> 398 490 … … 403 495 </div> 404 496 </div> 405 <?php 497 <?php 406 498 } 407 499 408 500 public function enqueue_scripts() { 409 wp_enqueue_script('jquery'); 410 wp_enqueue_script('jquery-ui-core'); 411 wp_enqueue_script('jquery-ui-widget'); 412 wp_enqueue_script('jquery-ui-mouse'); 413 wp_enqueue_script('jquery-ui-sortable'); 414 wp_enqueue_script('jquery-ui-draggable'); 415 wp_enqueue_script('jquery-ui-droppable'); 416 wp_enqueue_script('jquery-ui-sortable'); 417 wp_enqueue_style('wp-jquery-ui-dialog'); 418 419 wp_enqueue_style('oneclickseo-admin', ONECLICKSEO_PLUGIN_URL . 'assets/css/admin.min.css', array(), ONECLICKSEO_VERSION); 420 wp_enqueue_script('oneclickseo-admin', ONECLICKSEO_PLUGIN_URL . 'assets/js/admin.min.js', array( 421 'jquery', 422 'jquery-ui-core', 423 'jquery-ui-sortable', 424 'jquery-ui-draggable', 425 'jquery-ui-droppable' 426 ), ONECLICKSEO_VERSION, true); 427 428 wp_localize_script('oneclickseo-admin', 'oneClickSEO', array( 429 'ajaxurl' => admin_url('admin-ajax.php'), 430 'nonce' => wp_create_nonce('oneclickseo-nonce'), 431 'api_key' => get_option('oneclickseo_api_key'), 432 'i18n' => array( 433 'analyzing' => __('Analyzing...', 'one-click-seo-optimizer'), 434 'error' => __('An error occurred', 'one-click-seo-optimizer'), 435 'success' => __('Optimization completed successfully!', 'one-click-seo-optimizer'), 436 'analysis_complete' => __('Analysis complete', 'one-click-seo-optimizer'), 437 'site_description' => __('Site description', 'one-click-seo-optimizer'), 438 'site_objective' => __('Site objective', 'one-click-seo-optimizer'), 439 'target_audience' => __('Target audience', 'one-click-seo-optimizer'), 440 'keywords' => __('Keywords', 'one-click-seo-optimizer'), 441 'theme' => __('Theme', 'one-click-seo-optimizer'), 442 'stopping' => __('Stopping the process...', 'one-click-seo-optimizer'), 443 'stopped' => __('Process stopped by the user.', 'one-click-seo-optimizer'), 444 'optimizing_page' => __('Optimizing: ', 'one-click-seo-optimizer'), 445 'error_optimizing' => __('Error optimizing: ', 'one-click-seo-optimizer'), 446 'api_key_valid' => __('API key is valid!', 'one-click-seo-optimizer'), 447 'api_key_invalid' => __('API key is invalid.', 'one-click-seo-optimizer'), 448 'image_optimized' => __('Image optimized: ', 'one-click-seo-optimizer'), 449 'page_optimized' => __('Page optimized ', 'one-click-seo-optimizer'), 450 'readability_score' => __('Readability ', 'one-click-seo-optimizer'), 451 'content_score' => __('Content: ', 'one-click-seo-optimizer'), 452 'api_key_required' => __('API key required', 'one-click-seo-optimizer'), 453 'api_key_description' => __('Please enter your API key to continue.', 'one-click-seo-optimizer'), 454 'enter_api_key' => __('Enter your API key', 'one-click-seo-optimizer'), 455 'save' => __('Save', 'one-click-seo-optimizer'), 456 'cancel' => __('Cancel', 'one-click-seo-optimizer'), 457 'optimizing' => __('Optimizing...', 'one-click-seo-optimizer'), 458 'sitemap_generated' => __('Sitemap generated', 'one-click-seo-optimizer'), 459 ) 460 )); 501 wp_enqueue_script( 'jquery' ); 502 wp_enqueue_script( 'jquery-ui-core' ); 503 wp_enqueue_script( 'jquery-ui-widget' ); 504 wp_enqueue_script( 'jquery-ui-mouse' ); 505 wp_enqueue_script( 'jquery-ui-sortable' ); 506 wp_enqueue_script( 'jquery-ui-draggable' ); 507 wp_enqueue_script( 'jquery-ui-droppable' ); 508 wp_enqueue_script( 'jquery-ui-sortable' ); 509 wp_enqueue_style( 'wp-jquery-ui-dialog' ); 510 wp_enqueue_style( 511 'oneclickseo-admin', 512 ONECLICKSEO_PLUGIN_URL . 'assets/css/admin.min.css', 513 array(), 514 ONECLICKSEO_VERSION 515 ); 516 wp_enqueue_script( 517 'oneclickseo-admin', 518 ONECLICKSEO_PLUGIN_URL . 'assets/js/admin.min.js', 519 array( 520 'jquery', 521 'jquery-ui-core', 522 'jquery-ui-sortable', 523 'jquery-ui-draggable', 524 'jquery-ui-droppable' 525 ), 526 ONECLICKSEO_VERSION, 527 true 528 ); 529 wp_localize_script( 'oneclickseo-admin', 'oneClickSEO', array( 530 'ajaxurl' => admin_url( 'admin-ajax.php' ), 531 'nonce' => wp_create_nonce( 'oneclickseo-nonce' ), 532 'api_key' => get_option( 'oneclickseo_api_key' ), 533 'i18n' => array( 534 'analyzing' => __( 'Analyzing...', 'one-click-seo-optimizer' ), 535 'error' => __( 'An error occurred', 'one-click-seo-optimizer' ), 536 'success' => __( 'Optimization completed successfully!', 'one-click-seo-optimizer' ), 537 'analysis_complete' => __( 'Analysis complete', 'one-click-seo-optimizer' ), 538 'site_description' => __( 'Site description', 'one-click-seo-optimizer' ), 539 'site_objective' => __( 'Site objective', 'one-click-seo-optimizer' ), 540 'target_audience' => __( 'Target audience', 'one-click-seo-optimizer' ), 541 'keywords' => __( 'Keywords', 'one-click-seo-optimizer' ), 542 'theme' => __( 'Theme', 'one-click-seo-optimizer' ), 543 'stopping' => __( 'Stopping the process...', 'one-click-seo-optimizer' ), 544 'stopped' => __( 'Process stopped by the user.', 'one-click-seo-optimizer' ), 545 'optimizing_page' => __( 'Optimizing: ', 'one-click-seo-optimizer' ), 546 'error_optimizing' => __( 'Error optimizing: ', 'one-click-seo-optimizer' ), 547 'api_key_valid' => __( 'API key is valid!', 'one-click-seo-optimizer' ), 548 'api_key_invalid' => __( 'API key is invalid.', 'one-click-seo-optimizer' ), 549 'image_optimized' => __( 'Image optimized: ', 'one-click-seo-optimizer' ), 550 'page_optimized' => __( 'Page optimized ', 'one-click-seo-optimizer' ), 551 'readability_score' => __( 'Readability ', 'one-click-seo-optimizer' ), 552 'content_score' => __( 'Content: ', 'one-click-seo-optimizer' ), 553 'api_key_required' => __( 'API key required', 'one-click-seo-optimizer' ), 554 'api_key_description' => __( 'Please enter your API key to continue.', 'one-click-seo-optimizer' ), 555 'enter_api_key' => __( 'Enter your API key', 'one-click-seo-optimizer' ), 556 'save' => __( 'Save', 'one-click-seo-optimizer' ), 557 'cancel' => __( 'Cancel', 'one-click-seo-optimizer' ), 558 'optimizing' => __( 'Optimizing...', 'one-click-seo-optimizer' ), 559 'sitemap_generated' => __( 'Sitemap generated', 'one-click-seo-optimizer' ), 560 ), 561 ) ); 461 562 } 462 563 463 564 public function add_seo_meta_box() { 464 $post_types = get_option('oneclickseo_post_types', array('post', 'page')); 465 466 foreach ($post_types as $post_type) { 467 if (get_post_meta(get_the_ID(), '_elementor_edit_mode', true)) { 565 $post_types = get_option( 'oneclickseo_post_types', array('post', 'page') ); 566 foreach ( $post_types as $post_type ) { 567 if ( get_post_meta( get_the_ID(), '_elementor_edit_mode', true ) ) { 468 568 continue; 469 569 } 470 570 $post_id = get_the_ID(); 471 if ( 'auto-draft' === get_post_status($post_id)) {571 if ( 'auto-draft' === get_post_status( $post_id ) ) { 472 572 continue; 473 573 } 474 475 574 add_meta_box( 476 575 'oneclickseo_meta_box', 477 __( 'OneClick SEO', 'one-click-seo-optimizer'),576 __( 'OneClick SEO', 'one-click-seo-optimizer' ), 478 577 array($this, 'render_seo_meta_box'), 479 578 $post_type, … … 484 583 } 485 584 486 public function render_seo_meta_box($post) { 487 wp_nonce_field('oneclickseo_meta_box', 'oneclickseo_meta_box_nonce'); 488 489 $meta_title = get_post_meta($post->ID, '_oneclickseo_meta_title', true); 490 $meta_description = get_post_meta($post->ID, '_oneclickseo_meta_description', true); 491 $h1 = get_post_meta($post->ID, '_oneclickseo_h1', true); 492 $keywords = get_post_meta($post->ID, '_oneclickseo_keywords', true); 493 $keywords = is_array($keywords) ? $keywords : explode(',', (string)$keywords); 494 $keywords = array_map('trim', $keywords); 495 496 $page_objective = get_post_meta($post->ID, '_oneclickseo_page_objective', true); 497 $target_audience = get_post_meta($post->ID, '_oneclickseo_target_audience', true); 498 $content_suggestions = get_post_meta($post->ID, '_oneclickseo_content_suggestions', true); 499 $internal_linking = get_post_meta($post->ID, '_oneclickseo_internal_linking', true); 500 $internal_linking = is_array($internal_linking) ? $internal_linking : array(); 501 $schema_type = get_post_meta($post->ID, '_oneclickseo_schema_type', true); 502 $schema_data = get_post_meta($post->ID, '_oneclickseo_schema_data', true); 503 $readability_score = get_post_meta($post->ID, '_oneclickseo_readability_score', true); 504 $content_score = get_post_meta($post->ID, '_oneclickseo_content_score', true); 505 $last_analysis = get_post_meta($post->ID, '_oneclickseo_last_analysis', true); 585 public function render_seo_meta_box( $post ) { 586 wp_nonce_field( 'oneclickseo_meta_box', 'oneclickseo_meta_box_nonce' ); 587 $meta_title = get_post_meta( $post->ID, '_oneclickseo_meta_title', true ); 588 $meta_description = get_post_meta( $post->ID, '_oneclickseo_meta_description', true ); 589 $h1 = get_post_meta( $post->ID, '_oneclickseo_h1', true ); 590 $keywords = get_post_meta( $post->ID, '_oneclickseo_keywords', true ); 591 $keywords = ( is_array( $keywords ) ? $keywords : explode( ',', (string) $keywords ) ); 592 $keywords = array_map( 'trim', $keywords ); 593 $page_objective = get_post_meta( $post->ID, '_oneclickseo_page_objective', true ); 594 $target_audience = get_post_meta( $post->ID, '_oneclickseo_target_audience', true ); 595 $content_suggestions = get_post_meta( $post->ID, '_oneclickseo_content_suggestions', true ); 596 $internal_linking = get_post_meta( $post->ID, '_oneclickseo_internal_linking', true ); 597 $internal_linking = ( is_array( $internal_linking ) ? $internal_linking : array() ); 598 $schema_type = get_post_meta( $post->ID, '_oneclickseo_schema_type', true ); 599 $schema_data = get_post_meta( $post->ID, '_oneclickseo_schema_data', true ); 600 $readability_score = get_post_meta( $post->ID, '_oneclickseo_readability_score', true ); 601 $content_score = get_post_meta( $post->ID, '_oneclickseo_content_score', true ); 602 $last_analysis = get_post_meta( $post->ID, '_oneclickseo_last_analysis', true ); 506 603 ?> 507 604 <div class="oneclickseo-meta-box"> 508 605 <div class="oneclickseo-scores"> 509 <?php if ($last_analysis) : ?> 606 <?php 607 if ( $last_analysis ) { 608 ?> 510 609 <p class="oneclickseo-last-analysis"> 511 610 <?php 512 printf(513 /* translators: %s: date and time */514 esc_html__('Last analysis: %s', 'one-click-seo-optimizer'),515 esc_html(date_i18n(get_option('date_format') . ' ' . get_option('time_format'), $last_analysis))516 );517 ?>611 printf( 612 /* translators: %s: date and time */ 613 esc_html__( 'Last analysis: %s', 'one-click-seo-optimizer' ), 614 esc_html( date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $last_analysis ) ) 615 ); 616 ?> 518 617 </p> 519 <?php endif; ?> 618 <?php 619 } 620 ?> 520 621 521 622 <div class="oneclickseo-score-grid"> 522 <?php 523 $this->render_score(__('Readability', 'one-click-seo-optimizer'), $readability_score, 'book');524 $this->render_score(__('Content', 'one-click-seo-optimizer'), $content_score, 'edit');525 ?>623 <?php 624 $this->render_score( __( 'Readability', 'one-click-seo-optimizer' ), $readability_score, 'book' ); 625 $this->render_score( __( 'Content', 'one-click-seo-optimizer' ), $content_score, 'edit' ); 626 ?> 526 627 </div> 527 628 </div> 528 629 529 630 <div class="oneclickseo-field"> 530 <label for="oneclickseo_page_objective"><?php esc_html_e('Page Objective', 'one-click-seo-optimizer'); ?></label> 531 <textarea id="oneclickseo_page_objective" name="oneclickseo_page_objective" rows="3"><?php echo esc_textarea($page_objective); ?></textarea> 631 <label for="oneclickseo_page_objective"><?php 632 esc_html_e( 'Page Objective', 'one-click-seo-optimizer' ); 633 ?></label> 634 <textarea id="oneclickseo_page_objective" name="oneclickseo_page_objective" rows="3"><?php 635 echo esc_textarea( $page_objective ); 636 ?></textarea> 532 637 </div> 533 638 534 639 <div class="oneclickseo-field"> 535 <label for="oneclickseo_target_audience"><?php esc_html_e('Target Audience', 'one-click-seo-optimizer'); ?></label> 536 <textarea id="oneclickseo_target_audience" name="oneclickseo_target_audience" rows="3"><?php echo esc_textarea($target_audience); ?></textarea> 640 <label for="oneclickseo_target_audience"><?php 641 esc_html_e( 'Target Audience', 'one-click-seo-optimizer' ); 642 ?></label> 643 <textarea id="oneclickseo_target_audience" name="oneclickseo_target_audience" rows="3"><?php 644 echo esc_textarea( $target_audience ); 645 ?></textarea> 537 646 </div> 538 647 539 648 <div class="oneclickseo-optimize-container"> 540 <button type="button" class="button button-primary button-hero" id="oneclickseo-optimize" data-post-id="<?php echo esc_attr($post->ID); ?>"> 541 <?php esc_html_e('Optimisation Auto', 'one-click-seo-optimizer'); ?> 649 <button type="button" class="button button-primary button-hero" id="oneclickseo-optimize" data-post-id="<?php 650 echo esc_attr( $post->ID ); 651 ?>"> 652 <?php 653 esc_html_e( 'Optimisation Auto', 'one-click-seo-optimizer' ); 654 ?> 542 655 </button> 543 656 <div class="oneclickseo-optimize-status"></div> … … 547 660 <div class="oneclickseo-meta-column"> 548 661 <div class="oneclickseo-field"> 549 <label for="oneclickseo_meta_title"><?php esc_html_e('SEO Title', 'one-click-seo-optimizer'); ?></label> 550 <input type="text" id="oneclickseo_meta_title" name="oneclickseo_meta_title" value="<?php echo esc_attr($meta_title); ?>" /> 662 <label for="oneclickseo_meta_title"><?php 663 esc_html_e( 'SEO Title', 'one-click-seo-optimizer' ); 664 ?></label> 665 <input type="text" id="oneclickseo_meta_title" name="oneclickseo_meta_title" value="<?php 666 echo esc_attr( $meta_title ); 667 ?>" /> 551 668 </div> 552 669 553 670 <div class="oneclickseo-field"> 554 <label for="oneclickseo_meta_description"><?php esc_html_e('SEO Description', 'one-click-seo-optimizer'); ?></label> 555 <textarea id="oneclickseo_meta_description" name="oneclickseo_meta_description" rows="3"><?php echo esc_textarea($meta_description); ?></textarea> 671 <label for="oneclickseo_meta_description"><?php 672 esc_html_e( 'SEO Description', 'one-click-seo-optimizer' ); 673 ?></label> 674 <textarea id="oneclickseo_meta_description" name="oneclickseo_meta_description" rows="3"><?php 675 echo esc_textarea( $meta_description ); 676 ?></textarea> 556 677 </div> 557 678 558 679 <div class="oneclickseo-field"> 559 <label for="oneclickseo_h1"><?php esc_html_e('H1 Title', 'one-click-seo-optimizer'); ?></label> 560 <input type="text" id="oneclickseo_h1" name="oneclickseo_h1" value="<?php echo esc_attr($h1); ?>" /> 680 <label for="oneclickseo_h1"><?php 681 esc_html_e( 'H1 Title', 'one-click-seo-optimizer' ); 682 ?></label> 683 <input type="text" id="oneclickseo_h1" name="oneclickseo_h1" value="<?php 684 echo esc_attr( $h1 ); 685 ?>" /> 561 686 </div> 562 687 563 688 <div class="oneclickseo-field"> 564 <label for="oneclickseo_keywords"><?php esc_html_e('Keywords', 'one-click-seo-optimizer'); ?></label> 565 <input type="text" id="oneclickseo_keywords" name="oneclickseo_keywords" value="<?php echo esc_attr(implode(', ', $keywords)); ?>" /> 566 <p class="description"><?php esc_html_e('Separate keywords with commas', 'one-click-seo-optimizer'); ?></p> 689 <label for="oneclickseo_keywords"><?php 690 esc_html_e( 'Keywords', 'one-click-seo-optimizer' ); 691 ?></label> 692 <input type="text" id="oneclickseo_keywords" name="oneclickseo_keywords" value="<?php 693 echo esc_attr( implode( ', ', $keywords ) ); 694 ?>" /> 695 <p class="description"><?php 696 esc_html_e( 'Separate keywords with commas', 'one-click-seo-optimizer' ); 697 ?></p> 567 698 </div> 568 699 </div> … … 570 701 <div class="oneclickseo-meta-column"> 571 702 <div class="oneclickseo-field"> 572 <label><?php esc_html_e('Content Suggestions', 'one-click-seo-optimizer'); ?></label> 703 <label><?php 704 esc_html_e( 'Content Suggestions', 'one-click-seo-optimizer' ); 705 ?></label> 573 706 <div class="oneclickseo-suggestions"> 574 <?php if (!empty($content_suggestions)) : ?> 575 <?php foreach ((array)$content_suggestions as $suggestion) : ?> 707 <?php 708 if ( !empty( $content_suggestions ) ) { 709 ?> 710 <?php 711 foreach ( (array) $content_suggestions as $suggestion ) { 712 ?> 576 713 <div class="suggestion-item"> 577 714 <span class="dashicons dashicons-yes"></span> 578 <?php echo esc_html($suggestion); ?> 715 <?php 716 echo esc_html( $suggestion ); 717 ?> 579 718 </div> 580 <?php endforeach; ?> 581 <?php else : ?> 582 <p class="oneclickseo-no-data"><?php esc_html_e('No suggestions available', 'one-click-seo-optimizer'); ?></p> 583 <?php endif; ?> 719 <?php 720 } 721 ?> 722 <?php 723 } else { 724 ?> 725 <p class="oneclickseo-no-data"><?php 726 esc_html_e( 'No suggestions available', 'one-click-seo-optimizer' ); 727 ?></p> 728 <?php 729 } 730 ?> 584 731 </div> 585 732 </div> 586 733 587 734 <div class="oneclickseo-field"> 588 <label><?php esc_html_e('Internal Link Suggestions', 'one-click-seo-optimizer'); ?></label> 735 <label><?php 736 esc_html_e( 'Internal Link Suggestions', 'one-click-seo-optimizer' ); 737 ?></label> 589 738 <div class="oneclickseo-internal-links"> 590 <?php if (!empty($internal_linking) && is_array($internal_linking)) : ?> 591 <?php foreach ($internal_linking as $link) : ?> 739 <?php 740 if ( !empty( $internal_linking ) && is_array( $internal_linking ) ) { 741 ?> 742 <?php 743 foreach ( $internal_linking as $link ) { 744 ?> 592 745 593 746 <div class="suggestion-item"> 594 747 <span class="dashicons dashicons-admin-links"></span> 595 <?php echo esc_html($link); ?> 748 <?php 749 echo esc_html( $link ); 750 ?> 596 751 </div> 597 <?php endforeach; ?> 598 <?php else : ?> 599 <p class="oneclickseo-no-data"><?php esc_html_e('No suggestions available', 'one-click-seo-optimizer'); ?></p> 600 <?php endif; ?> 752 <?php 753 } 754 ?> 755 <?php 756 } else { 757 ?> 758 <p class="oneclickseo-no-data"><?php 759 esc_html_e( 'No suggestions available', 'one-click-seo-optimizer' ); 760 ?></p> 761 <?php 762 } 763 ?> 601 764 </div> 602 765 </div> … … 606 769 <div class="oneclickseo-schema"> 607 770 <div class="oneclickseo-field"> 608 <label for="oneclickseo_schema_type"><?php esc_html_e('Schema Type', 'one-click-seo-optimizer'); ?></label> 771 <label for="oneclickseo_schema_type"><?php 772 esc_html_e( 'Schema Type', 'one-click-seo-optimizer' ); 773 ?></label> 609 774 <select id="oneclickseo_schema_type" name="oneclickseo_schema_type"> 610 <option value=""><?php esc_html_e('Select a type', 'one-click-seo-optimizer'); ?></option> 611 <option value="Article" <?php selected($schema_type, 'Article'); ?>>Article</option> 612 <option value="BlogPosting" <?php selected($schema_type, 'BlogPosting'); ?>>Blog Post</option> 613 <option value="WebPage" <?php selected($schema_type, 'WebPage'); ?>>Page Web</option> 614 <option value="Product" <?php selected($schema_type, 'Product'); ?>>Produit</option> 615 <option value="FAQPage" <?php selected($schema_type, 'FAQPage'); ?>>FAQ</option> 616 <option value="HowTo" <?php selected($schema_type, 'HowTo'); ?>>Guide</option> 617 <option value="Organization" <?php selected($schema_type, 'Organization'); ?>>Organisation</option> 618 <option value="LocalBusiness" <?php selected($schema_type, 'LocalBusiness'); ?>>Entreprise locale</option> 775 <option value=""><?php 776 esc_html_e( 'Select a type', 'one-click-seo-optimizer' ); 777 ?></option> 778 <option value="Article" <?php 779 selected( $schema_type, 'Article' ); 780 ?>>Article</option> 781 <option value="BlogPosting" <?php 782 selected( $schema_type, 'BlogPosting' ); 783 ?>>Blog Post</option> 784 <option value="WebPage" <?php 785 selected( $schema_type, 'WebPage' ); 786 ?>>Page Web</option> 787 <option value="Product" <?php 788 selected( $schema_type, 'Product' ); 789 ?>>Produit</option> 790 <option value="FAQPage" <?php 791 selected( $schema_type, 'FAQPage' ); 792 ?>>FAQ</option> 793 <option value="HowTo" <?php 794 selected( $schema_type, 'HowTo' ); 795 ?>>Guide</option> 796 <option value="Organization" <?php 797 selected( $schema_type, 'Organization' ); 798 ?>>Organisation</option> 799 <option value="LocalBusiness" <?php 800 selected( $schema_type, 'LocalBusiness' ); 801 ?>>Entreprise locale</option> 619 802 </select> 620 803 </div> 621 804 622 805 <div class="oneclickseo-field"> 623 <label for="oneclickseo_schema_data"><?php esc_html_e('Structured Data', 'one-click-seo-optimizer'); ?></label> 806 <label for="oneclickseo_schema_data"><?php 807 esc_html_e( 'Structured Data', 'one-click-seo-optimizer' ); 808 ?></label> 624 809 <textarea id="oneclickseo_schema_data" name="oneclickseo_schema_data" rows="10" class="code"><?php 625 echo esc_textarea( 626 is_array($schema_data) ? json_encode($schema_data, JSON_PRETTY_PRINT) : $schema_data 627 ); 628 ?></textarea> 810 echo esc_textarea( ( is_array( $schema_data ) ? json_encode( $schema_data, JSON_PRETTY_PRINT ) : $schema_data ) ); 811 ?></textarea> 629 812 </div> 630 813 </div> 631 814 </div> 632 <?php 633 } 634 635 public function save_seo_meta_box( $post_id) {636 if ( !isset($_POST['oneclickseo_meta_box_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['oneclickseo_meta_box_nonce'])), 'oneclickseo_meta_box')) {815 <?php 816 } 817 818 public function save_seo_meta_box( $post_id ) { 819 if ( !isset( $_POST['oneclickseo_meta_box_nonce'] ) || !wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['oneclickseo_meta_box_nonce'] ) ), 'oneclickseo_meta_box' ) ) { 637 820 return; 638 821 } 639 640 if (!current_user_can('edit_post', $post_id)) { 822 if ( !current_user_can( 'edit_post', $post_id ) ) { 641 823 return; 642 824 } 643 644 825 $meta_fields = [ 645 826 'meta_title', … … 652 833 'schema_data' 653 834 ]; 654 655 foreach ($meta_fields as $field) { 656 if (isset($_POST['oneclickseo_' . $field])) { 657 update_post_meta( 658 $post_id, 659 '_oneclickseo_' . $field, 660 sanitize_text_field(wp_unslash($_POST['oneclickseo_' . $field])) 661 ); 835 foreach ( $meta_fields as $field ) { 836 if ( isset( $_POST['oneclickseo_' . $field] ) ) { 837 update_post_meta( $post_id, '_oneclickseo_' . $field, sanitize_text_field( wp_unslash( $_POST['oneclickseo_' . $field] ) ) ); 662 838 } 663 839 } 664 665 if (isset($_POST['oneclickseo_schema_data'])) { 666 $schema_data = sanitize_textarea_field(wp_unslash($_POST['oneclickseo_schema_data'])); 667 $decoded_data = json_decode($schema_data, true); 668 update_post_meta( 669 $post_id, 670 '_oneclickseo_schema_data', 671 $decoded_data !== null ? $decoded_data : $schema_data 672 ); 673 } 674 } 675 676 private function render_score($label, $score, $icon) { 840 if ( isset( $_POST['oneclickseo_schema_data'] ) ) { 841 $schema_data = sanitize_textarea_field( wp_unslash( $_POST['oneclickseo_schema_data'] ) ); 842 $decoded_data = json_decode( $schema_data, true ); 843 update_post_meta( $post_id, '_oneclickseo_schema_data', ( $decoded_data !== null ? $decoded_data : $schema_data ) ); 844 } 845 } 846 847 private function render_score( $label, $score, $icon ) { 677 848 $class = 'poor'; 678 if ( $score >= 90) {849 if ( $score >= 90 ) { 679 850 $class = 'excellent'; 680 } elseif ( $score >= 70) {851 } elseif ( $score >= 70 ) { 681 852 $class = 'good'; 682 } elseif ( $score >= 50) {853 } elseif ( $score >= 50 ) { 683 854 $class = 'fair'; 684 855 } 685 856 ?> 686 <div class="oneclickseo-score <?php echo esc_attr($class); ?>"> 687 <span class="dashicons dashicons-<?php echo esc_attr($icon); ?>"></span> 857 <div class="oneclickseo-score <?php 858 echo esc_attr( $class ); 859 ?>"> 860 <span class="dashicons dashicons-<?php 861 echo esc_attr( $icon ); 862 ?>"></span> 688 863 <div class="score-details"> 689 <span class="score-label"><?php echo esc_html($label); ?></span> 690 <span class="score-value"><?php echo esc_html(intval($score)); ?>/100</span> 864 <span class="score-label"><?php 865 echo esc_html( $label ); 866 ?></span> 867 <span class="score-value"><?php 868 echo esc_html( intval( $score ) ); 869 ?>/100</span> 691 870 </div> 692 871 </div> 693 <?php 694 } 695 } 872 <?php 873 } 874 875 } -
one-click-seo-optimizer/trunk/includes/class-oneclickseo-api.php
r3249837 r3249839 3 3 class OneClickSEO_API { 4 4 private $api_base_url = 'https://api.openai.com/v1'; 5 5 6 private $api_key; 7 6 8 private $model; 9 7 10 private $is_optimizing = false; 11 8 12 private $current_options = []; 9 13 10 14 public function __construct() { 11 $this->api_key = get_option('oneclickseo_api_key'); 12 $this->model = get_option('oneclickseo_model', 'gpt-4'); 13 } 14 15 public function optimize_page($post_id, $skip_directives = false, $page_objective = null, $target_audience = null, $options = []) { 16 if ($this->is_optimizing) { 15 $this->api_key = get_option( 'oneclickseo_api_key' ); 16 $this->model = get_option( 'oneclickseo_model', 'gpt-4' ); 17 } 18 19 public function optimize_page( 20 $post_id, 21 $skip_directives = false, 22 $page_objective = null, 23 $target_audience = null, 24 $options = [] 25 ) { 26 if ( $this->is_optimizing ) { 17 27 return; 18 28 } 19 20 29 $this->is_optimizing = true; 21 $this->current_options = $options; 22 23 24 $post = get_post($post_id); 25 if (!$post) { 26 throw new Exception(esc_html__('Page not found', 'one-click-seo-optimizer')); 27 } 28 30 $this->current_options = $options; 31 $post = get_post( $post_id ); 32 if ( !$post ) { 33 throw new Exception(esc_html__( 'Page not found', 'one-click-seo-optimizer' )); 34 } 29 35 $mustUseAI = true; 30 if(!isset($options['optimize_metas']) || !isset($options['generate_structured_data']) || 31 !isset($options['optimize_headings']) || !isset($options['optimize_page_details']) || 32 !isset($options['content_suggestions']) || !isset($options['internal_link_suggestions']) || 33 !isset($options['optimize_scores'])) { 34 $options = array_merge([ 35 'optimize_metas' => true, 36 'generate_structured_data' => true, 37 'optimize_headings' => false, 38 'optimize_page_details' => true, 39 'content_suggestions' => true, 36 if ( !isset( $options['optimize_metas'] ) || !isset( $options['generate_structured_data'] ) || !isset( $options['optimize_headings'] ) || !isset( $options['optimize_page_details'] ) || !isset( $options['content_suggestions'] ) || !isset( $options['internal_link_suggestions'] ) || !isset( $options['optimize_scores'] ) ) { 37 $options = array_merge( [ 38 'optimize_metas' => true, 39 'generate_structured_data' => true, 40 'optimize_headings' => false, 41 'optimize_page_details' => true, 42 'content_suggestions' => true, 40 43 'internal_link_suggestions' => true, 41 'optimize_scores' => true, 42 'optimize_images' => false, 43 'generate_sitemap' => false 44 ], $options); 45 } 46 47 if($options['optimize_metas'] == false 48 && $options['generate_structured_data'] == false 49 && $options['optimize_headings'] == false 50 && $options['optimize_page_details'] == false 51 && $options['content_suggestions'] == false 52 && $options['internal_link_suggestions'] == false 53 && $options['optimize_scores'] == false){ 44 'optimize_scores' => true, 45 'optimize_images' => false, 46 'generate_sitemap' => false, 47 ], $options ); 48 } 49 if ( $options['optimize_metas'] == false && $options['generate_structured_data'] == false && $options['optimize_headings'] == false && $options['optimize_page_details'] == false && $options['content_suggestions'] == false && $options['internal_link_suggestions'] == false && $options['optimize_scores'] == false ) { 54 50 $mustUseAI = false; 55 51 } 56 52 try { 57 if($mustUseAI){ 58 $site_analysis = get_option('oneclickseo_site_analysis', []); 59 $main_pages = get_posts([ 60 'post_type' => ['page', 'post'], 61 'posts_per_page' => 20, 62 'orderby' => 'menu_order date', 63 'order' => 'ASC', 64 'post__not_in' => [$post_id], 65 ]); 66 67 $site_pages = []; 68 foreach ($main_pages as $exPage) { 69 $site_pages[] = [ 70 'title' => $exPage->post_title, 71 'url' => str_replace(home_url(), '', get_permalink($exPage)), 72 'excerpt' => wp_strip_all_tags(get_the_excerpt($exPage)) 73 ]; 74 } 75 76 $content = $post->post_content; 77 78 79 80 81 $elements =[]; 82 83 if (class_exists('\Elementor\Plugin')) { 84 $document = \Elementor\Plugin::$instance->documents->get($post_id); 85 if ($document) { 86 $data = $document->get_elements_data(); 87 $elements = $data; 88 $contentElementor = $this->extract_elementor_content($data); 89 } 90 91 foreach ($elements as $element) { 92 if (!empty($element['elements'])) { 93 $contentElementor .= $this->extract_elementor_content($element['elements']); 53 if ( $mustUseAI ) { 54 $site_analysis = get_option( 'oneclickseo_site_analysis', [] ); 55 $main_pages = get_posts( [ 56 'post_type' => ['page', 'post'], 57 'posts_per_page' => 20, 58 'orderby' => 'menu_order date', 59 'order' => 'ASC', 60 'post__not_in' => [$post_id], 61 ] ); 62 $site_pages = []; 63 foreach ( $main_pages as $exPage ) { 64 $site_pages[] = [ 65 'title' => $exPage->post_title, 66 'url' => str_replace( home_url(), '', get_permalink( $exPage ) ), 67 'excerpt' => wp_strip_all_tags( get_the_excerpt( $exPage ) ), 68 ]; 69 } 70 $content = $post->post_content; 71 $elements = []; 72 if ( class_exists( '\\Elementor\\Plugin' ) ) { 73 $document = \Elementor\Plugin::$instance->documents->get( $post_id ); 74 if ( $document ) { 75 $data = $document->get_elements_data(); 76 $elements = $data; 77 $contentElementor = $this->extract_elementor_content( $data ); 94 78 } 95 96 if (!isset($element['widgetType'])) { 97 if ($element['widgetType'] === 'heading') { 98 $contentElementor .= $element['settings']['title'] . "\n\n"; 79 foreach ( $elements as $element ) { 80 if ( !empty( $element['elements'] ) ) { 81 $contentElementor .= $this->extract_elementor_content( $element['elements'] ); 82 } 83 if ( !isset( $element['widgetType'] ) ) { 84 if ( $element['widgetType'] === 'heading' ) { 85 $contentElementor .= $element['settings']['title'] . "\n\n"; 86 } 87 if ( $element['widgetType'] === 'text-editor' ) { 88 $contentElementor .= wp_strip_all_tags( $element['settings']['editor'] ) . "\n\n"; 89 } 90 } 99 91 } 100 101 if ($element['widgetType'] === 'text-editor') { 102 $contentElementor .= wp_strip_all_tags($element['settings']['editor']) . "\n\n"; 92 if ( $contentElementor != '' ) { 93 $content = $contentElementor; 103 94 } 104 95 } 105 }106 if($contentElementor != ''){107 $content = $contentElementor;108 }109 110 }111 112 113 114 115 if ( oneoneclickseo_fs()->is__premium_only() ) {116 117 96 $prompt = sprintf( 118 "Analyze this page and provide detailed SEO recommendations. Here is the information:\n\n" . 119 "URL: %s\n" . 120 "Title: %s\n" . 121 "Content: %s\n\n" . 122 "Site Context:\n" . 123 "Description: %s\n" . 124 "Objective: %s\n" . 125 "Audience: %s\n" . 126 "Theme: %s\n" . 127 "Page Objective: %s\n" . 128 "Target Audience: %s\n" . 129 "Main Site Pages:\n%s\n\n" . 130 "Provide a JSON object with the following fields:\n" . 131 "- meta_title: Optimized SEO title\n" . 132 "- meta_description: Optimized SEO description\n" . 133 "- h1: Recommended H1 title\n" . 134 "- keywords: List of relevant keywords\n" . 135 "- page_objective: Specific page objective\n" . 136 "- target_audience: Specific target audience\n" . 137 "- content_suggestions: Content improvement suggestions (as string array)\n" . 138 "- internal_linking: Internal linking suggestions (as string array of urls)\n" . 139 "- schema_type: Recommended Schema.org type\n" . 140 "- schema_data: Recommended structured data\n" . 141 "- readability_score: Readability score (0-100)\n" . 142 "- content_score: Content quality score (0-100)\n" . 143 "- technical_score: Technical SEO score (0-100)", 144 get_permalink($post), 97 "Analyze this page and provide detailed SEO recommendations. Here is the information:\n\n" . "URL: %s\n" . "Title: %s\n" . "Content: %s\n\n" . "Site Context:\n" . "Description: %s\n" . "Objective: %s\n" . "Audience: %s\n" . "Theme: %s\n" . "Page Objective: %s\n" . "Target Audience: %s\n" . "Main Site Pages:\n%s\n\n" . "Provide a JSON object with the following fields:\n" . "- meta_title: Optimized SEO title\n" . "- meta_description: Optimized SEO description\n" . "- h1: Recommended H1 title\n" . "- keywords: List of relevant keywords\n" . "- page_objective: Specific page objective\n" . "- target_audience: Specific target audience", 98 get_permalink( $post ), 145 99 $post->post_title, 146 wp_strip_all_tags( $post->post_content),100 wp_strip_all_tags( $content ), 147 101 $site_analysis['description_site'] ?? '', 148 102 $site_analysis['objectif'] ?? '', … … 151 105 $page_objective ?? '', 152 106 $target_audience ?? '', 153 json_encode( $site_pages, JSON_PRETTY_PRINT)107 json_encode( $site_pages, JSON_PRETTY_PRINT ) 154 108 ); 155 } else { 156 $prompt = sprintf( 157 "Analyze this page and provide detailed SEO recommendations. Here is the information:\n\n" . 158 "URL: %s\n" . 159 "Title: %s\n" . 160 "Content: %s\n\n" . 161 "Site Context:\n" . 162 "Description: %s\n" . 163 "Objective: %s\n" . 164 "Audience: %s\n" . 165 "Theme: %s\n" . 166 "Page Objective: %s\n" . 167 "Target Audience: %s\n" . 168 "Main Site Pages:\n%s\n\n" . 169 "Provide a JSON object with the following fields:\n" . 170 "- meta_title: Optimized SEO title\n" . 171 "- meta_description: Optimized SEO description\n" . 172 "- h1: Recommended H1 title\n" . 173 "- keywords: List of relevant keywords\n" . 174 "- page_objective: Specific page objective\n" . 175 "- target_audience: Specific target audience", 176 get_permalink($post), 177 $post->post_title, 178 wp_strip_all_tags($content), 179 $site_analysis['description_site'] ?? '', 180 $site_analysis['objectif'] ?? '', 181 $site_analysis['audience_cible'] ?? '', 182 $site_analysis['thematique'] ?? '', 183 $page_objective ?? '', 184 $target_audience ?? '', 185 json_encode($site_pages, JSON_PRETTY_PRINT) 186 ); 187 188 } 189 190 $language = get_bloginfo('language'); 191 192 if ($language) { 193 $prompt .= "\n\nLangue à utiliser : " . $language; 194 } 195 196 $response = $this->call_openai_api('chat/completions', [ 197 'model' => $this->model, 198 'messages' => [ 199 [ 200 'role' => 'system', 201 'content' => 'You are an SEO expert analyzing website content. Respond only with a valid JSON object.' 202 ], 203 [ 204 'role' => 'user', 205 'content' => $prompt 206 ] 207 ], 208 'temperature' => 0.7 209 ]); 210 211 if (empty($this->api_key)) { 212 throw new Exception(esc_html__('OpenAI API key not configured', 'one-click-seo-optimizer')); 213 } 214 215 $contentRep = $response['choices'][0]['message']['content']; 216 217 218 $json_str = $this->extract_json($contentRep); 219 $metas = json_decode($json_str, true); 220 $analysis = json_decode($json_str, true); 221 222 223 if(!isset($options['optimize_metas']) || $options['optimize_metas'] == true){ 224 update_post_meta($post_id, '_oneclickseo_meta_title', $analysis['meta_title']); 225 update_post_meta($post_id, '_oneclickseo_meta_description', $analysis['meta_description']); 226 update_post_meta($post_id, '_oneclickseo_h1', $analysis['h1']); 227 update_post_meta($post_id, '_oneclickseo_keywords', $analysis['keywords']); 228 } 229 230 if($options['optimize_page_details'] == true){ 231 update_post_meta($post_id, '_oneclickseo_page_objective', $analysis['page_objective']); 232 update_post_meta($post_id, '_oneclickseo_target_audience', $analysis['target_audience']); 233 } 234 if ( oneoneclickseo_fs()->is__premium_only() ) { 235 236 if($options['content_suggestions'] == true){ 237 update_post_meta($post_id, '_oneclickseo_content_suggestions', $analysis['content_suggestions']); 238 } 239 if($options['internal_link_suggestions'] == true){ 240 update_post_meta($post_id, '_oneclickseo_internal_linking', $analysis['internal_linking']); 241 } 242 243 244 if($options['optimize_scores'] == true){ 245 $readability_score = $this->calculate_readability_score($content); 246 247 update_post_meta($post_id, '_oneclickseo_readability_score', $readability_score); 248 $content_score = $this->calculate_content_score($content); 249 update_post_meta($post_id, '_oneclickseo_content_score', $content_score); 250 update_post_meta($post_id, '_oneclickseo_last_analysis', current_time('mysql')); 251 } 252 253 if(!isset($options['generate_structured_data']) || $options['generate_structured_data'] == true){ 254 update_post_meta($post_id, '_oneclickseo_schema_type', $analysis['schema_type']); 255 update_post_meta($post_id, '_oneclickseo_schema_data', $analysis['schema_data']); 256 } 257 } 258 259 260 261 } 109 $language = get_bloginfo( 'language' ); 110 if ( $language ) { 111 $prompt .= "\n\nLangue à utiliser : " . $language; 112 } 113 $response = $this->call_openai_api( 'chat/completions', [ 114 'model' => $this->model, 115 'messages' => [[ 116 'role' => 'system', 117 'content' => 'You are an SEO expert analyzing website content. Respond only with a valid JSON object.', 118 ], [ 119 'role' => 'user', 120 'content' => $prompt, 121 ]], 122 'temperature' => 0.7, 123 ] ); 124 if ( empty( $this->api_key ) ) { 125 throw new Exception(esc_html__( 'OpenAI API key not configured', 'one-click-seo-optimizer' )); 126 } 127 $contentRep = $response['choices'][0]['message']['content']; 128 $json_str = $this->extract_json( $contentRep ); 129 $metas = json_decode( $json_str, true ); 130 $analysis = json_decode( $json_str, true ); 131 if ( !isset( $options['optimize_metas'] ) || $options['optimize_metas'] == true ) { 132 update_post_meta( $post_id, '_oneclickseo_meta_title', $analysis['meta_title'] ); 133 update_post_meta( $post_id, '_oneclickseo_meta_description', $analysis['meta_description'] ); 134 update_post_meta( $post_id, '_oneclickseo_h1', $analysis['h1'] ); 135 update_post_meta( $post_id, '_oneclickseo_keywords', $analysis['keywords'] ); 136 } 137 if ( $options['optimize_page_details'] == true ) { 138 update_post_meta( $post_id, '_oneclickseo_page_objective', $analysis['page_objective'] ); 139 update_post_meta( $post_id, '_oneclickseo_target_audience', $analysis['target_audience'] ); 140 } 141 } 262 142 $optimized_images = []; 263 143 $optimized_headings = []; 264 if ( oneoneclickseo_fs()->is__premium_only() ) { 265 if(isset($options['optimize_headings']) && $options['optimize_headings'] == true){ 266 $optimized_headings = $this->optimize_headings($post_id, $post->post_content); 267 } 268 if(isset($options['optimize_images']) && $options['optimize_images'] == true){ 269 $optimized_images = $this->optimize_images($post_id); 270 } 271 } 272 273 if(isset($options['generate_sitemap']) && $options['generate_sitemap'] == true){ 274 $this->generate_sitemap(); 275 } 276 277 /* translators: %1$s: page title */ 278 $msg = sprintf(__('Page "%1$s" optimized successfully.', 'one-click-seo-optimizer'), 279 $post->post_title); 280 281 282 144 if ( isset( $options['generate_sitemap'] ) && $options['generate_sitemap'] == true ) { 145 $this->generate_sitemap(); 146 } 147 /* translators: %1$s: page title */ 148 $msg = sprintf( __( 'Page "%1$s" optimized successfully.', 'one-click-seo-optimizer' ), $post->post_title ); 283 149 $rep = [ 284 'success' => true, 285 'data' => $metas, 286 /* translators: %s: page title */ 287 'message' => $msg, 288 'optimized_images' => $optimized_images, 289 'optimized_headings' => $optimized_headings 150 'success' => true, 151 'data' => $metas, 152 'message' => $msg, 153 'optimized_images' => $optimized_images, 154 'optimized_headings' => $optimized_headings, 290 155 ]; 291 if(isset($options['optimize_headings']) && $options['optimize_headings'] === true){ 292 $rep['heading_updates'] = get_post_meta($post_id, '_oneclickseo_heading_updates', true); 293 } 294 156 if ( isset( $options['optimize_headings'] ) && $options['optimize_headings'] === true ) { 157 $rep['heading_updates'] = get_post_meta( $post_id, '_oneclickseo_heading_updates', true ); 158 } 295 159 return $rep; 296 160 } finally { … … 299 163 } 300 164 301 public function calculate_content_score($text) { 302 $plain_text = wp_strip_all_tags($text); 303 304 $words = str_word_count($plain_text, 1); 305 $word_count = count($words); 306 307 if ($word_count < 300) { 308 $length_score = (70 * $word_count) / 300; 165 public function calculate_content_score( $text ) { 166 $plain_text = wp_strip_all_tags( $text ); 167 $words = str_word_count( $plain_text, 1 ); 168 $word_count = count( $words ); 169 if ( $word_count < 300 ) { 170 $length_score = 70 * $word_count / 300; 309 171 } else { 310 172 $length_score = 70; 311 173 } 312 313 $sentences = preg_split('/[.!?]+/', $plain_text, -1, PREG_SPLIT_NO_EMPTY); 314 $sentence_count = count($sentences); 315 $avg_sentence_length = ($sentence_count > 0) ? ($word_count / $sentence_count) : 0; 316 317 if ($avg_sentence_length >= 15 && $avg_sentence_length <= 25) { 174 $sentences = preg_split( 175 '/[.!?]+/', 176 $plain_text, 177 -1, 178 PREG_SPLIT_NO_EMPTY 179 ); 180 $sentence_count = count( $sentences ); 181 $avg_sentence_length = ( $sentence_count > 0 ? $word_count / $sentence_count : 0 ); 182 if ( $avg_sentence_length >= 15 && $avg_sentence_length <= 25 ) { 318 183 $sentence_bonus = 20; 319 } elseif ( $avg_sentence_length < 15) {184 } elseif ( $avg_sentence_length < 15 ) { 320 185 $sentence_bonus = 20 * ($avg_sentence_length / 15); 321 186 } else { 322 $sentence_bonus = 20 * (1 - min(($avg_sentence_length - 25) / 25, 1)); 323 } 324 325 $lowercase_words = array_map('strtolower', $words); 326 $unique_words = array_unique($lowercase_words); 327 $diversity = ($word_count > 0) ? count($unique_words) / $word_count : 0; 328 329 if ($diversity >= 0.5) { 330 $diversity_bonus = min((($diversity - 0.5) / 0.3) * 10, 10); 187 $sentence_bonus = 20 * (1 - min( ($avg_sentence_length - 25) / 25, 1 )); 188 } 189 $lowercase_words = array_map( 'strtolower', $words ); 190 $unique_words = array_unique( $lowercase_words ); 191 $diversity = ( $word_count > 0 ? count( $unique_words ) / $word_count : 0 ); 192 if ( $diversity >= 0.5 ) { 193 $diversity_bonus = min( ($diversity - 0.5) / 0.3 * 10, 10 ); 331 194 } else { 332 195 $diversity_bonus = 0; 333 196 } 334 335 197 $total_score = $length_score + $sentence_bonus + $diversity_bonus; 336 $total_score = min(100, round($total_score)); 337 198 $total_score = min( 100, round( $total_score ) ); 338 199 return (int) $total_score; 339 200 } 340 201 341 function calculate_readability_score($text) { 342 $word_count = str_word_count($text); 343 344 $sentences = preg_split('/[.!?]+/', $text, -1, PREG_SPLIT_NO_EMPTY); 345 $sentence_count = count($sentences); 346 347 $syllable_count = $this->count_syllables($text); 348 349 if ($word_count == 0 || $sentence_count == 0) { 202 function calculate_readability_score( $text ) { 203 $word_count = str_word_count( $text ); 204 $sentences = preg_split( 205 '/[.!?]+/', 206 $text, 207 -1, 208 PREG_SPLIT_NO_EMPTY 209 ); 210 $sentence_count = count( $sentences ); 211 $syllable_count = $this->count_syllables( $text ); 212 if ( $word_count == 0 || $sentence_count == 0 ) { 350 213 return 0; 351 214 } 352 353 $reading_ease = 206.835 - 1.015 * ($word_count / $sentence_count) - 84.6 * ($syllable_count / $word_count); 354 355 return max(0, min(100, round($reading_ease))); 356 } 357 358 function count_syllables($text) { 359 $text = strtolower($text); 360 $text = preg_replace('/[^a-z]/', ' ', $text); 361 $words = explode(' ', $text); 215 $reading_ease = 206.835 - 1.015 * ($word_count / $sentence_count) - 84.59999999999999 * ($syllable_count / $word_count); 216 return max( 0, min( 100, round( $reading_ease ) ) ); 217 } 218 219 function count_syllables( $text ) { 220 $text = strtolower( $text ); 221 $text = preg_replace( '/[^a-z]/', ' ', $text ); 222 $words = explode( ' ', $text ); 362 223 $totalSyllables = 0; 363 foreach ( $words as $word) {364 if ( empty($word)) {224 foreach ( $words as $word ) { 225 if ( empty( $word ) ) { 365 226 continue; 366 227 } 367 preg_match_all( '/[aeiouy]+/', $word, $matches);368 $syllableCount = count( $matches[0]);369 $totalSyllables += ( $syllableCount > 0 ? $syllableCount : 1);228 preg_match_all( '/[aeiouy]+/', $word, $matches ); 229 $syllableCount = count( $matches[0] ); 230 $totalSyllables += ( $syllableCount > 0 ? $syllableCount : 1 ); 370 231 } 371 232 return $totalSyllables; … … 376 237 $upload_dir = wp_upload_dir(); 377 238 $sitemap_dir = $upload_dir['basedir'] . '/sitemaps'; 378 379 if (!file_exists($sitemap_dir)) { 380 wp_mkdir_p($sitemap_dir); 381 } 382 239 if ( !file_exists( $sitemap_dir ) ) { 240 wp_mkdir_p( $sitemap_dir ); 241 } 383 242 $home_content = $this->generate_home_sitemap(); 384 file_put_contents( $sitemap_dir . '/home.xml', $home_content);385 386 $post_types = get_post_types(['public' => true]);387 foreach ($post_types as $post_type) {388 243 file_put_contents( $sitemap_dir . '/home.xml', $home_content ); 244 $post_types = get_post_types( [ 245 'public' => true, 246 ] ); 247 foreach ( $post_types as $post_type ) { 389 248 $query = new WP_Query([ 390 'post_type' => $post_type,391 'post_status' => 'publish',392 'posts_per_page' => -1,393 'fields' => 'ids',394 'orderby' => 'ID',395 'order' => 'ASC',396 'cache_results' => false,249 'post_type' => $post_type, 250 'post_status' => 'publish', 251 'posts_per_page' => -1, 252 'fields' => 'ids', 253 'orderby' => 'ID', 254 'order' => 'ASC', 255 'cache_results' => false, 397 256 'update_post_meta_cache' => false, 398 257 'update_post_term_cache' => false, 399 'suppress_filters' => true,400 'nopaging' => true258 'suppress_filters' => true, 259 'nopaging' => true, 401 260 ]); 402 403 if ($query->have_posts()) { 261 if ( $query->have_posts() ) { 404 262 $total_posts = $query->found_posts; 405 406 263 $posts_per_file = 45000; 407 $total_files = ceil($total_posts / $posts_per_file); 408 264 $total_files = ceil( $total_posts / $posts_per_file ); 409 265 for ($i = 0; $i < $total_files; $i++) { 410 266 $offset = $i * $posts_per_file; 411 412 267 $posts_query = new WP_Query([ 413 'post_type' => $post_type,414 'post_status' => 'publish',415 'posts_per_page' => $posts_per_file,416 'offset' => $offset,417 'orderby' => 'ID',418 'order' => 'ASC',419 'cache_results' => false,268 'post_type' => $post_type, 269 'post_status' => 'publish', 270 'posts_per_page' => $posts_per_file, 271 'offset' => $offset, 272 'orderby' => 'ID', 273 'order' => 'ASC', 274 'cache_results' => false, 420 275 'update_post_meta_cache' => false, 421 276 'update_post_term_cache' => false, 422 'suppress_filters' => true277 'suppress_filters' => true, 423 278 ]); 424 425 if ($posts_query->have_posts()) { 426 $posts_count = count($posts_query->posts); 427 428 $sitemap_content = $this->generate_sitemap_content($posts_query->posts); 429 $filename = sprintf('%s-%d.xml', $post_type, $i + 1); 430 file_put_contents($sitemap_dir . '/' . $filename, $sitemap_content); 279 if ( $posts_query->have_posts() ) { 280 $posts_count = count( $posts_query->posts ); 281 $sitemap_content = $this->generate_sitemap_content( $posts_query->posts ); 282 $filename = sprintf( '%s-%d.xml', $post_type, $i + 1 ); 283 file_put_contents( $sitemap_dir . '/' . $filename, $sitemap_content ); 431 284 } 432 285 wp_reset_postdata(); … … 434 287 } 435 288 } 436 437 289 $sitemap_index = $this->generate_sitemap_index(); 438 file_put_contents($upload_dir['basedir'] . '/sitemap.xml', $sitemap_index); 439 290 file_put_contents( $upload_dir['basedir'] . '/sitemap.xml', $sitemap_index ); 440 291 return [ 441 'success' => true,442 'message' => __('Sitemap generated successfully', 'one-click-seo-optimizer'),443 'sitemap_url' => $upload_dir['baseurl'] . '/sitemap.xml' 292 'success' => true, 293 'message' => __( 'Sitemap generated successfully', 'one-click-seo-optimizer' ), 294 'sitemap_url' => $upload_dir['baseurl'] . '/sitemap.xml', 444 295 ]; 445 446 } catch (Exception $e) { 296 } catch ( Exception $e ) { 447 297 return [ 448 298 'success' => false, 449 'message' => $e->getMessage() 299 'message' => $e->getMessage(), 450 300 ]; 451 301 } … … 455 305 $content = '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; 456 306 $content .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n"; 457 458 307 $content .= "\t<url>\n"; 459 $content .= "\t\t<loc>" . esc_url( home_url('/')) . "</loc>\n";460 $content .= "\t\t<lastmod>" . gmdate( 'c') . "</lastmod>\n";308 $content .= "\t\t<loc>" . esc_url( home_url( '/' ) ) . "</loc>\n"; 309 $content .= "\t\t<lastmod>" . gmdate( 'c' ) . "</lastmod>\n"; 461 310 $content .= "\t\t<changefreq>daily</changefreq>\n"; 462 311 $content .= "\t\t<priority>1.0</priority>\n"; 463 312 $content .= "\t</url>\n"; 464 465 313 $content .= '</urlset>'; 466 314 return $content; … … 470 318 $upload_dir = wp_upload_dir(); 471 319 $base_url = home_url(); 472 473 320 $index = '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; 474 321 $index .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n"; 475 476 $index .= $this->generate_sitemap_index_entry( 477 $base_url . '/sitemaps/home.xml', 478 gmdate('c') 479 ); 480 481 $post_types = get_post_types(['public' => true]); 482 foreach ($post_types as $post_type) { 322 $index .= $this->generate_sitemap_index_entry( $base_url . '/sitemaps/home.xml', gmdate( 'c' ) ); 323 $post_types = get_post_types( [ 324 'public' => true, 325 ] ); 326 foreach ( $post_types as $post_type ) { 483 327 $query = new WP_Query([ 484 'post_type' => $post_type,485 'post_status' => 'publish',328 'post_type' => $post_type, 329 'post_status' => 'publish', 486 330 'posts_per_page' => -1, 487 'fields' => 'ids'331 'fields' => 'ids', 488 332 ]); 489 490 333 $total_posts = $query->found_posts; 491 $num_sitemaps = ceil($total_posts / 45000); 492 334 $num_sitemaps = ceil( $total_posts / 45000 ); 493 335 for ($i = 1; $i <= $num_sitemaps; $i++) { 494 $index .= $this->generate_sitemap_index_entry( 495 $base_url . '/sitemaps/' . $post_type . '-' . $i . '.xml', 496 gmdate('c') 497 ); 336 $index .= $this->generate_sitemap_index_entry( $base_url . '/sitemaps/' . $post_type . '-' . $i . '.xml', gmdate( 'c' ) ); 498 337 } 499 338 wp_reset_postdata(); 500 339 } 501 502 340 $index .= '</sitemapindex>'; 503 341 return $index; 504 342 } 505 343 506 private function generate_sitemap_index_entry($loc, $lastmod) { 507 return sprintf( 508 "\t<sitemap>\n\t\t<loc>%s</loc>\n\t\t<lastmod>%s</lastmod>\n\t</sitemap>\n", 509 esc_url($loc), 510 esc_html($lastmod) 511 ); 512 } 513 514 private function generate_sitemap_content($posts) { 344 private function generate_sitemap_index_entry( $loc, $lastmod ) { 345 return sprintf( "\t<sitemap>\n\t\t<loc>%s</loc>\n\t\t<lastmod>%s</lastmod>\n\t</sitemap>\n", esc_url( $loc ), esc_html( $lastmod ) ); 346 } 347 348 private function generate_sitemap_content( $posts ) { 515 349 $content = '<?xml version="1.0" encoding="UTF-8"?>' . "\n"; 516 350 $content .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n"; 517 518 foreach ($posts as $post) { 519 $last_modified = get_the_modified_date('Y-m-d\TH:i:s\Z', $post); 520 $priority = $this->calculate_page_priority($post); 521 $changefreq = $this->determine_change_frequency($post); 522 351 foreach ( $posts as $post ) { 352 $last_modified = get_the_modified_date( 'Y-m-d\\TH:i:s\\Z', $post ); 353 $priority = $this->calculate_page_priority( $post ); 354 $changefreq = $this->determine_change_frequency( $post ); 523 355 $content .= "\t<url>\n"; 524 $content .= "\t\t<loc>" . esc_url( get_permalink($post)) . "</loc>\n";525 $content .= "\t\t<lastmod>" . esc_html( $last_modified) . "</lastmod>\n";526 $content .= "\t\t<changefreq>" . esc_html( $changefreq) . "</changefreq>\n";527 $content .= "\t\t<priority>" . esc_html( number_format($priority, 1)) . "</priority>\n";356 $content .= "\t\t<loc>" . esc_url( get_permalink( $post ) ) . "</loc>\n"; 357 $content .= "\t\t<lastmod>" . esc_html( $last_modified ) . "</lastmod>\n"; 358 $content .= "\t\t<changefreq>" . esc_html( $changefreq ) . "</changefreq>\n"; 359 $content .= "\t\t<priority>" . esc_html( number_format( $priority, 1 ) ) . "</priority>\n"; 528 360 $content .= "\t</url>\n"; 529 361 } 530 531 362 $content .= '</urlset>'; 532 363 return $content; 533 364 } 534 365 535 private function calculate_page_priority( $post) {536 if ( is_front_page() || is_home()) {366 private function calculate_page_priority( $post ) { 367 if ( is_front_page() || is_home() ) { 537 368 return 1.0; 538 369 } 539 540 $comment_count = get_comment_count($post->ID)['approved']; 541 $days_old = (time() - strtotime($post->post_date)) / DAY_IN_SECONDS; 542 370 $comment_count = get_comment_count( $post->ID )['approved']; 371 $days_old = (time() - strtotime( $post->post_date )) / DAY_IN_SECONDS; 543 372 $priority = 0.5; 544 545 if ($days_old < 30) { 373 if ( $days_old < 30 ) { 546 374 $priority += 0.3; 547 } elseif ( $days_old < 90) {375 } elseif ( $days_old < 90 ) { 548 376 $priority += 0.2; 549 377 } 550 551 if ($comment_count > 10) { 378 if ( $comment_count > 10 ) { 552 379 $priority += 0.2; 553 } elseif ( $comment_count > 5) {380 } elseif ( $comment_count > 5 ) { 554 381 $priority += 0.1; 555 382 } 556 557 return max(0.1, min(1.0, $priority)); 558 } 559 560 private function determine_change_frequency($post) { 561 $post_age = time() - strtotime($post->post_date); 562 $last_modified = strtotime($post->post_modified); 563 564 if ($post_age < DAY_IN_SECONDS * 7) { 383 return max( 0.1, min( 1.0, $priority ) ); 384 } 385 386 private function determine_change_frequency( $post ) { 387 $post_age = time() - strtotime( $post->post_date ); 388 $last_modified = strtotime( $post->post_modified ); 389 if ( $post_age < DAY_IN_SECONDS * 7 ) { 565 390 return 'daily'; 566 391 } 567 568 if ((time() - $last_modified) < DAY_IN_SECONDS * 30) { 392 if ( time() - $last_modified < DAY_IN_SECONDS * 30 ) { 569 393 return 'weekly'; 570 394 } 571 572 if ($post_age < DAY_IN_SECONDS * 180) { 395 if ( $post_age < DAY_IN_SECONDS * 180 ) { 573 396 return 'monthly'; 574 397 } 575 576 398 return 'yearly'; 577 399 } 578 400 579 public function optimize_headings($post_id) { 580 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 581 return; 582 } 583 $post = get_post($post_id); 584 if (!$post) { 585 throw new Exception(esc_html__('Invalid post', 'one-click-seo-optimizer')); 586 } 587 $headings = $this->get_all_headings($post_id, $post->post_content); 588 $analysis = $this->analyze_headings_hierarchy($post, $headings); 589 /* $updated_content = $this->update_headings($post->post_content, $headings, $analysis, $post_id); 590 wp_update_post([ 591 'ID' => $post_id, 592 'post_content' => $updated_content 593 ]);*/ 594 $modifications = $this->get_headings_modifications($headings, $analysis); 401 public function optimize_headings( $post_id ) { 402 return; 403 $post = get_post( $post_id ); 404 if ( !$post ) { 405 throw new Exception(esc_html__( 'Invalid post', 'one-click-seo-optimizer' )); 406 } 407 $headings = $this->get_all_headings( $post_id, $post->post_content ); 408 $analysis = $this->analyze_headings_hierarchy( $post, $headings ); 409 /* $updated_content = $this->update_headings($post->post_content, $headings, $analysis, $post_id); 410 wp_update_post([ 411 'ID' => $post_id, 412 'post_content' => $updated_content 413 ]);*/ 414 $modifications = $this->get_headings_modifications( $headings, $analysis ); 595 415 return [ 596 'success' => true,597 'message' => __('Heading structure optimized', 'one-click-seo-optimizer'),598 'modifications' => $modifications 416 'success' => true, 417 'message' => __( 'Heading structure optimized', 'one-click-seo-optimizer' ), 418 'modifications' => $modifications, 599 419 ]; 600 420 } 601 421 602 private function get_all_headings($post_id, $content) { 603 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 604 return; 605 } 422 private function get_all_headings( $post_id, $content ) { 423 return; 606 424 $headings = []; 607 608 if (class_exists('\Elementor\Plugin')) { 609 $document = \Elementor\Plugin::$instance->documents->get($post_id); 610 if ($document) { 425 if ( class_exists( '\\Elementor\\Plugin' ) ) { 426 $document = \Elementor\Plugin::$instance->documents->get( $post_id ); 427 if ( $document ) { 611 428 $data = $document->get_elements_data(); 612 $headings = array_merge($headings, $this->extract_elementor_headings($data)); 613 } 614 } 615 616 $headings = array_merge($headings, $this->extract_gutenberg_headings($content)); 617 $headings = array_merge($headings, $this->extract_classic_headings($content)); 618 429 $headings = array_merge( $headings, $this->extract_elementor_headings( $data ) ); 430 } 431 } 432 $headings = array_merge( $headings, $this->extract_gutenberg_headings( $content ) ); 433 $headings = array_merge( $headings, $this->extract_classic_headings( $content ) ); 619 434 return $headings; 620 435 } 621 436 622 private function extract_elementor_headings(array $elements) { 623 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 624 return; 625 } 437 private function extract_elementor_headings( array $elements ) { 438 return; 626 439 $headings = []; 627 628 foreach ($elements as $element) { 629 if ($element['elType'] === 'widget' && $element['widgetType'] === 'heading') { 630 $settings = isset($element['settings']) ? $element['settings'] : []; 631 $header_size = isset($settings['header_size']) ? $settings['header_size'] : 'h2'; 632 633 $level = (int) filter_var($header_size, FILTER_SANITIZE_NUMBER_INT); 634 if ($level < 1 || $level > 6) { 440 foreach ( $elements as $element ) { 441 if ( $element['elType'] === 'widget' && $element['widgetType'] === 'heading' ) { 442 $settings = ( isset( $element['settings'] ) ? $element['settings'] : [] ); 443 $header_size = ( isset( $settings['header_size'] ) ? $settings['header_size'] : 'h2' ); 444 $level = (int) filter_var( $header_size, FILTER_SANITIZE_NUMBER_INT ); 445 if ( $level < 1 || $level > 6 ) { 635 446 $level = 2; 636 447 } 637 638 $content_heading = !empty($settings['title']) ? wp_strip_all_tags($settings['title']) : ''; 639 448 $content_heading = ( !empty( $settings['title'] ) ? wp_strip_all_tags( $settings['title'] ) : '' ); 640 449 $headings[] = [ 641 'type' => 'elementor_widget',642 'level' => $level,643 'content' => $content_heading,450 'type' => 'elementor_widget', 451 'level' => $level, 452 'content' => $content_heading, 644 453 'element_id' => $element['id'], 645 'original' => $element454 'original' => $element, 646 455 ]; 647 } elseif ($element['elType'] === 'widget' && $element['widgetType'] === 'text-editor') { 648 $settings = isset($element['settings']) ? $element['settings'] : []; 649 $editor_content = isset($settings['editor']) ? $settings['editor'] : ''; 650 651 preg_match_all('/<h([1-6])[^>]*>(.*?)<\/h\1>/is', $editor_content, $matches, PREG_SET_ORDER); 652 foreach ($matches as $m) { 456 } elseif ( $element['elType'] === 'widget' && $element['widgetType'] === 'text-editor' ) { 457 $settings = ( isset( $element['settings'] ) ? $element['settings'] : [] ); 458 $editor_content = ( isset( $settings['editor'] ) ? $settings['editor'] : '' ); 459 preg_match_all( 460 '/<h([1-6])[^>]*>(.*?)<\\/h\\1>/is', 461 $editor_content, 462 $matches, 463 PREG_SET_ORDER 464 ); 465 foreach ( $matches as $m ) { 653 466 $current_level = (int) $m[1]; 654 $heading_text = wp_strip_all_tags($m[2]); 655 467 $heading_text = wp_strip_all_tags( $m[2] ); 656 468 $headings[] = [ 657 'type' => 'elementor_texteditor',658 'level' => $current_level,659 'content' => $heading_text,660 'element_id' => $element['id'],469 'type' => 'elementor_texteditor', 470 'level' => $current_level, 471 'content' => $heading_text, 472 'element_id' => $element['id'], 661 473 'original_tag' => $m[0], 662 'full_content' => $editor_content 474 'full_content' => $editor_content, 663 475 ]; 664 476 } 665 477 } 666 667 if (!empty($element['elements'])) { 668 $headings = array_merge($headings, $this->extract_elementor_headings($element['elements'])); 669 } 670 } 671 478 if ( !empty( $element['elements'] ) ) { 479 $headings = array_merge( $headings, $this->extract_elementor_headings( $element['elements'] ) ); 480 } 481 } 672 482 return $headings; 673 483 } 674 484 675 private function extract_gutenberg_headings($content) { 676 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 677 return; 678 } 485 private function extract_gutenberg_headings( $content ) { 486 return; 679 487 $headings = []; 680 $pattern = '/(<!-- wp:heading\s*(\{.*?\})?\s*-->)(.*?)(<!-- \/wp:heading -->)/is'; 681 preg_match_all($pattern, $content, $matches, PREG_SET_ORDER); 682 683 foreach ($matches as $m) { 488 $pattern = '/(<!-- wp:heading\\s*(\\{.*?\\})?\\s*-->)(.*?)(<!-- \\/wp:heading -->)/is'; 489 preg_match_all( 490 $pattern, 491 $content, 492 $matches, 493 PREG_SET_ORDER 494 ); 495 foreach ( $matches as $m ) { 684 496 $whole_block = $m[0]; 685 $attributes_json = !empty($m[2]) ? $m[2] : '{}';686 $attributes = json_decode( $attributes_json, true);687 if ( !is_array($attributes)) {497 $attributes_json = ( !empty( $m[2] ) ? $m[2] : '{}' ); 498 $attributes = json_decode( $attributes_json, true ); 499 if ( !is_array( $attributes ) ) { 688 500 $attributes = []; 689 501 } 690 691 502 $inner_html = $m[3]; 692 if ( preg_match('/<h([1-6])[^>]*>(.*?)<\/h\1>/is', $inner_html, $hm)) {503 if ( preg_match( '/<h([1-6])[^>]*>(.*?)<\\/h\\1>/is', $inner_html, $hm ) ) { 693 504 $level_in_tag = (int) $hm[1]; 694 $heading_content = wp_strip_all_tags( $hm[2]);505 $heading_content = wp_strip_all_tags( $hm[2] ); 695 506 } else { 696 507 $level_in_tag = 2; 697 $heading_content = trim(wp_strip_all_tags($inner_html)); 698 } 699 700 $level_attr = isset($attributes['level']) ? (int) $attributes['level'] : $level_in_tag; 701 508 $heading_content = trim( wp_strip_all_tags( $inner_html ) ); 509 } 510 $level_attr = ( isset( $attributes['level'] ) ? (int) $attributes['level'] : $level_in_tag ); 702 511 $headings[] = [ 703 'type' => 'gutenberg',704 'level' => $level_attr,705 'content' => $heading_content,706 'original' => $whole_block,707 'attributes' => $attributes 512 'type' => 'gutenberg', 513 'level' => $level_attr, 514 'content' => $heading_content, 515 'original' => $whole_block, 516 'attributes' => $attributes, 708 517 ]; 709 518 } 710 711 519 return $headings; 712 520 } 713 521 714 private function extract_classic_headings($content) { 715 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 716 return; 717 } 522 private function extract_classic_headings( $content ) { 523 return; 718 524 $headings = []; 719 preg_match_all('/<h([1-6])[^>]*>(.*?)<\/h\1>/i', $content, $matches, PREG_SET_ORDER); 720 721 foreach ($matches as $m) { 525 preg_match_all( 526 '/<h([1-6])[^>]*>(.*?)<\\/h\\1>/i', 527 $content, 528 $matches, 529 PREG_SET_ORDER 530 ); 531 foreach ( $matches as $m ) { 722 532 $headings[] = [ 723 'type' => 'classic',724 'level' => (int) $m[1],725 'content' => esc_html(wp_strip_all_tags($m[2])),726 'original' => $m[0] 533 'type' => 'classic', 534 'level' => (int) $m[1], 535 'content' => esc_html( wp_strip_all_tags( $m[2] ) ), 536 'original' => $m[0], 727 537 ]; 728 538 } 729 730 539 return $headings; 731 540 } 732 541 733 private function analyze_headings_hierarchy($post, $headings) { 734 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 735 return; 736 } 737 $headings_data = array_map(function($h, $i) { 542 private function analyze_headings_hierarchy( $post, $headings ) { 543 return; 544 $headings_data = array_map( function ( $h, $i ) { 738 545 return [ 739 'index' => $i,740 'content' => $h['content'],741 'current_level' => $h['level'] 546 'index' => $i, 547 'content' => $h['content'], 548 'current_level' => $h['level'], 742 549 ]; 743 }, $headings, array_keys($headings)); 744 550 }, $headings, array_keys( $headings ) ); 745 551 $prompt = sprintf( 746 "Analyze and optimize the heading hierarchy for this page. Rules:\n" . 747 "- Exactly one H1\n" . 748 "- Logical nesting\n" . 749 "- Semantic meaning\n\n" . 750 "Page title: %s\n" . 751 "URL: %s\n" . 752 "Headings:\n%s\n\n" . 753 "Return JSON with 'headings' array containing index, recommended_level and reasoning", 552 "Analyze and optimize the heading hierarchy for this page. Rules:\n" . "- Exactly one H1\n" . "- Logical nesting\n" . "- Semantic meaning\n\n" . "Page title: %s\n" . "URL: %s\n" . "Headings:\n%s\n\n" . "Return JSON with 'headings' array containing index, recommended_level and reasoning", 754 553 $post->post_title, 755 get_permalink( $post->ID),756 json_encode( $headings_data, JSON_PRETTY_PRINT)554 get_permalink( $post->ID ), 555 json_encode( $headings_data, JSON_PRETTY_PRINT ) 757 556 ); 758 759 $language = get_bloginfo('language'); 760 761 if ($language) { 557 $language = get_bloginfo( 'language' ); 558 if ( $language ) { 762 559 $prompt .= "\n\nLangue à utiliser : " . $language; 763 560 } 764 765 $response = $this->call_openai_api('chat/completions', [ 766 'model' => $this->model, 767 'messages' => [ 768 [ 769 'role' => 'system', 770 'content' => 'You are an SEO expert specialized in heading hierarchy optimization' 771 ], 772 [ 773 'role' => 'user', 774 'content' => $prompt 775 ] 776 ], 777 'temperature' => 0.3 778 ]); 779 780 if (!isset($response['choices'][0]['message']['content'])) { 781 throw new Exception(esc_html__('Invalid OpenAI response', 'one-click-seo-optimizer')); 782 } 783 784 return json_decode($this->extract_json($response['choices'][0]['message']['content']), true); 785 } 786 787 private function update_headings($content, $headings, $analysis, $post_id = null) { 788 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 789 return; 790 } 561 $response = $this->call_openai_api( 'chat/completions', [ 562 'model' => $this->model, 563 'messages' => [[ 564 'role' => 'system', 565 'content' => 'You are an SEO expert specialized in heading hierarchy optimization', 566 ], [ 567 'role' => 'user', 568 'content' => $prompt, 569 ]], 570 'temperature' => 0.3, 571 ] ); 572 if ( !isset( $response['choices'][0]['message']['content'] ) ) { 573 throw new Exception(esc_html__( 'Invalid OpenAI response', 'one-click-seo-optimizer' )); 574 } 575 return json_decode( $this->extract_json( $response['choices'][0]['message']['content'] ), true ); 576 } 577 578 private function update_headings( 579 $content, 580 $headings, 581 $analysis, 582 $post_id = null 583 ) { 584 return; 791 585 $elementor_updates = []; 792 586 $chat_messages = []; 793 794 foreach ($analysis['headings'] as $recommendation) { 587 foreach ( $analysis['headings'] as $recommendation ) { 795 588 $i = $recommendation['index']; 796 589 $new_level = $recommendation['recommended_level']; 797 if ( !isset($headings[$i])) {590 if ( !isset( $headings[$i] ) ) { 798 591 continue; 799 592 } 800 593 $heading = $headings[$i]; 801 if ( $new_level == $heading['level']) {594 if ( $new_level == $heading['level'] ) { 802 595 continue; 803 596 } 804 $new_block = $this->generate_new_heading($heading, $new_level); 805 597 $new_block = $this->generate_new_heading( $heading, $new_level ); 806 598 $chat_messages[] = sprintf( 807 599 /* translators: %s: heading content */ 808 __( ' heading "%1$s" from H%2$d to H%3$d', 'one-click-seo-optimizer'),600 __( ' heading "%1$s" from H%2$d to H%3$d', 'one-click-seo-optimizer' ), 809 601 $heading['content'], 810 602 $heading['level'], 811 603 $new_level 812 604 ); 813 814 if ($heading['type'] === 'gutenberg' || $heading['type'] === 'classic') { 815 $content = str_replace($heading['original'], $new_block, $content); 816 } elseif ($heading['type'] === 'elementor_widget' || $heading['type'] === 'elementor_texteditor') { 605 if ( $heading['type'] === 'gutenberg' || $heading['type'] === 'classic' ) { 606 $content = str_replace( $heading['original'], $new_block, $content ); 607 } elseif ( $heading['type'] === 'elementor_widget' || $heading['type'] === 'elementor_texteditor' ) { 817 608 $elementor_updates[] = [ 818 'heading' => $heading,609 'heading' => $heading, 819 610 'new_block' => $new_block, 820 611 'new_level' => $new_level, 821 'message' => end($chat_messages)612 'message' => end( $chat_messages ), 822 613 ]; 823 614 } 824 615 } 825 826 if (!empty($elementor_updates) && $post_id) { 827 $this->update_elementor_headings($post_id, $elementor_updates); 828 } 829 830 if (!empty($chat_messages)) { 831 update_post_meta($post_id, '_oneclickseo_heading_updates', $chat_messages); 832 } 833 616 if ( !empty( $elementor_updates ) && $post_id ) { 617 $this->update_elementor_headings( $post_id, $elementor_updates ); 618 } 619 if ( !empty( $chat_messages ) ) { 620 update_post_meta( $post_id, '_oneclickseo_heading_updates', $chat_messages ); 621 } 834 622 return $content; 835 623 } 836 624 837 private function update_elementor_headings($post_id, $updates) { 838 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 625 private function update_elementor_headings( $post_id, $updates ) { 626 return; 627 if ( !class_exists( '\\Elementor\\Plugin' ) ) { 839 628 return; 840 629 } 841 if (!class_exists('\Elementor\Plugin')) { 842 return; 843 } 844 $document = \Elementor\Plugin::$instance->documents->get($post_id); 845 if (!$document) { 630 $document = \Elementor\Plugin::$instance->documents->get( $post_id ); 631 if ( !$document ) { 846 632 return; 847 633 } 848 634 $elements_data = $document->get_elements_data(); 849 635 $modified = false; 850 $this->update_elements_recursive($elements_data, $updates, $modified); 851 if ($modified) { 852 remove_all_actions('elementor/editor/after_save'); 853 $document->save(['elements' => $elements_data]); 854 update_post_meta($post_id, '_elementor_data', $elements_data); 636 $this->update_elements_recursive( $elements_data, $updates, $modified ); 637 if ( $modified ) { 638 remove_all_actions( 'elementor/editor/after_save' ); 639 $document->save( [ 640 'elements' => $elements_data, 641 ] ); 642 update_post_meta( $post_id, '_elementor_data', $elements_data ); 855 643 \Elementor\Plugin::$instance->files_manager->clear_cache(); 856 644 } 857 645 } 858 646 859 private function update_elements_recursive(&$elements, $updates, &$modified) { 860 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 647 private function update_elements_recursive( &$elements, $updates, &$modified ) { 648 return; 649 if ( !is_array( $elements ) ) { 861 650 return; 862 651 } 863 if (!is_array($elements)) { 864 return; 865 } 866 867 foreach ($elements as &$element) { 868 if (!isset($element['id'])) { 652 foreach ( $elements as &$element ) { 653 if ( !isset( $element['id'] ) ) { 869 654 continue; 870 655 } 871 872 foreach ($updates as $update) { 873 if ($element['id'] === $update['heading']['element_id']) { 874 if ($update['heading']['type'] === 'elementor_widget') { 656 foreach ( $updates as $update ) { 657 if ( $element['id'] === $update['heading']['element_id'] ) { 658 if ( $update['heading']['type'] === 'elementor_widget' ) { 875 659 $element['settings']['header_size'] = 'h' . $update['new_level']; 876 660 $modified = true; 877 } elseif ( $update['heading']['type'] === 'elementor_texteditor') {661 } elseif ( $update['heading']['type'] === 'elementor_texteditor' ) { 878 662 $old_tag = $update['heading']['original_tag']; 879 663 $old_level = $update['heading']['level']; 880 664 $new_level = $update['new_level']; 881 882 $new_tag = str_replace('<h' . $old_level, '<h' . $new_level, $old_tag); 883 $new_tag = str_replace('</h' . $old_level . '>', '</h' . $new_level . '>', $new_tag); 884 665 $new_tag = str_replace( '<h' . $old_level, '<h' . $new_level, $old_tag ); 666 $new_tag = str_replace( '</h' . $old_level . '>', '</h' . $new_level . '>', $new_tag ); 885 667 $content = $element['settings']['editor']; 886 $content = str_replace($old_tag, $new_tag, $content); 887 668 $content = str_replace( $old_tag, $new_tag, $content ); 888 669 $element['settings']['editor'] = $content; 889 670 $modified = true; … … 891 672 } 892 673 } 893 894 if (!empty($element['elements'])) { 895 $this->update_elements_recursive($element['elements'], $updates, $modified); 896 } 897 } 898 } 899 900 901 902 private function generate_new_heading($heading, $new_level) { 903 904 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 905 return; 906 } 907 switch ($heading['type']) { 674 if ( !empty( $element['elements'] ) ) { 675 $this->update_elements_recursive( $element['elements'], $updates, $modified ); 676 } 677 } 678 } 679 680 private function generate_new_heading( $heading, $new_level ) { 681 return; 682 switch ( $heading['type'] ) { 908 683 case 'gutenberg': 909 $attributes = isset($heading['attributes']) ? $heading['attributes'] : [];684 $attributes = ( isset( $heading['attributes'] ) ? $heading['attributes'] : [] ); 910 685 $attributes['level'] = $new_level; 911 $attributes_json = json_encode($attributes, JSON_UNESCAPED_SLASHES); 912 686 $attributes_json = json_encode( $attributes, JSON_UNESCAPED_SLASHES ); 913 687 return sprintf( 914 688 '<!-- wp:heading %s --><h%d>%s</h%d><!-- /wp:heading -->', … … 918 692 $new_level 919 693 ); 920 921 694 case 'classic': 922 return sprintf('<h%d>%s</h%d>', $new_level, $heading['content'], $new_level); 923 695 return sprintf( 696 '<h%d>%s</h%d>', 697 $new_level, 698 $heading['content'], 699 $new_level 700 ); 924 701 case 'elementor_widget': 925 702 case 'elementor_texteditor': 926 703 return $heading['original']; 927 928 704 default: 929 return sprintf('<h%d>%s</h%d>', $new_level, $heading['content'], $new_level); 930 } 931 } 932 933 private function get_headings_modifications($headings, $analysis) { 934 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 935 return; 936 } 705 return sprintf( 706 '<h%d>%s</h%d>', 707 $new_level, 708 $heading['content'], 709 $new_level 710 ); 711 } 712 } 713 714 private function get_headings_modifications( $headings, $analysis ) { 715 return; 937 716 $modifications = []; 938 939 foreach ($analysis['headings'] as $recommendation) { 717 foreach ( $analysis['headings'] as $recommendation ) { 940 718 $i = $recommendation['index']; 941 942 if (!isset($headings[$i])) { 719 if ( !isset( $headings[$i] ) ) { 943 720 continue; 944 721 } 945 946 722 $heading = $headings[$i]; 947 723 $old_level = $heading['level']; 948 724 $new_level = $recommendation['recommended_level']; 949 725 $title_text = $heading['content']; 950 951 if($old_level != $new_level){ 726 if ( $old_level != $new_level ) { 952 727 $modifications[] = sprintf( 953 728 /* translators: %s: heading type */ 954 __( 'Title suggested to be changed from H%1$d to H%2$d: "%3$s"', 'one-click-seo-optimizer'),729 __( 'Title suggested to be changed from H%1$d to H%2$d: "%3$s"', 'one-click-seo-optimizer' ), 955 730 $old_level, 956 731 $new_level, … … 959 734 } 960 735 } 961 962 736 return $modifications; 963 737 } 964 738 965 public function optimize_images($post_id) { 966 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 967 return; 968 } 969 970 if (!isset($this->current_options['optimize_images']) || !$this->current_options['optimize_images']) { 739 public function optimize_images( $post_id ) { 740 return; 741 if ( !isset( $this->current_options['optimize_images'] ) || !$this->current_options['optimize_images'] ) { 971 742 return []; 972 743 } 973 974 $post = get_post($post_id); 975 if (!$post) { 744 $post = get_post( $post_id ); 745 if ( !$post ) { 976 746 throw new Exception('Post invalide'); 977 747 } 978 979 748 $optimized_images = []; 980 749 $optimized_images_count = 0; 981 982 750 $content = $post->post_content; 983 $optimized_images = array_merge( 984 $optimized_images, 985 $this->optimize_content_images($content) 986 ); 987 988 if (class_exists('\Elementor\Plugin')) { 989 $document = \Elementor\Plugin::$instance->documents->get($post_id); 990 if ($document) { 751 $optimized_images = array_merge( $optimized_images, $this->optimize_content_images( $content ) ); 752 if ( class_exists( '\\Elementor\\Plugin' ) ) { 753 $document = \Elementor\Plugin::$instance->documents->get( $post_id ); 754 if ( $document ) { 991 755 $data = $document->get_elements_data(); 992 $elementor_images = $this->extract_elementor_images( $data);993 foreach ( $elementor_images as $image_data) {756 $elementor_images = $this->extract_elementor_images( $data ); 757 foreach ( $elementor_images as $image_data ) { 994 758 try { 995 $analysis = $this->analyze_image( $image_data['url']);996 if ( $analysis['success']) {997 if ( $image_data['attachment_id']) {759 $analysis = $this->analyze_image( $image_data['url'] ); 760 if ( $analysis['success'] ) { 761 if ( $image_data['attachment_id'] ) { 998 762 $attachment_data = array( 999 'ID' => $image_data['attachment_id'],1000 'post_title' => $analysis['data']['metas']['title'],763 'ID' => $image_data['attachment_id'], 764 'post_title' => $analysis['data']['metas']['title'], 1001 765 'post_excerpt' => $analysis['data']['metas']['alt_text'], 1002 'post_content' => $analysis['data']['metas']['description'] 766 'post_content' => $analysis['data']['metas']['description'], 1003 767 ); 1004 wp_update_post($attachment_data); 1005 1006 update_post_meta($image_data['attachment_id'], '_wp_attachment_image_alt', $analysis['data']['metas']['alt_text']); 768 wp_update_post( $attachment_data ); 769 update_post_meta( $image_data['attachment_id'], '_wp_attachment_image_alt', $analysis['data']['metas']['alt_text'] ); 1007 770 } 1008 1009 771 $this->update_elementor_image_settings( 1010 772 $post_id, … … 1013 775 $analysis['data']['metas'] 1014 776 ); 1015 1016 777 $optimized_images[] = [ 1017 778 'image_url' => $image_data['url'], 1018 'alt' => $analysis['data']['metas']['alt_text'],1019 'title' => $analysis['data']['metas']['title'],1020 'type' => 'elementor_' . $image_data['widget_type']779 'alt' => $analysis['data']['metas']['alt_text'], 780 'title' => $analysis['data']['metas']['title'], 781 'type' => 'elementor_' . $image_data['widget_type'], 1021 782 ]; 1022 783 $optimized_images_count++; 1023 784 } 1024 } catch (Exception $e) { 1025 785 } catch ( Exception $e ) { 1026 786 } 1027 787 } 1028 788 } 1029 789 } 1030 1031 790 return $optimized_images; 1032 791 } 1033 792 1034 private function extract_elementor_images($elements) { 1035 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 1036 return; 1037 } 793 private function extract_elementor_images( $elements ) { 794 return; 1038 795 $images = []; 1039 1040 foreach ($elements as $element) { 1041 if (!empty($element['elements'])) { 1042 $images = array_merge($images, $this->extract_elementor_images($element['elements'])); 1043 } 1044 1045 if (!isset($element['settings'])) { 796 foreach ( $elements as $element ) { 797 if ( !empty( $element['elements'] ) ) { 798 $images = array_merge( $images, $this->extract_elementor_images( $element['elements'] ) ); 799 } 800 if ( !isset( $element['settings'] ) ) { 1046 801 continue; 1047 802 } 1048 1049 foreach ($element['settings'] as $key => $value) { 1050 if ($this->is_image_setting($key, $value)) { 1051 $image_url = $this->get_image_url($value); 1052 if ($image_url) { 803 foreach ( $element['settings'] as $key => $value ) { 804 if ( $this->is_image_setting( $key, $value ) ) { 805 $image_url = $this->get_image_url( $value ); 806 if ( $image_url ) { 1053 807 $images[] = [ 1054 'url' => $image_url,1055 'element_id' => $element['id'],1056 'widget_type' => $element['widgetType'],1057 'setting_key' => $key,1058 'attachment_id' => $this->get_attachment_id( $image_url)808 'url' => $image_url, 809 'element_id' => $element['id'], 810 'widget_type' => $element['widgetType'], 811 'setting_key' => $key, 812 'attachment_id' => $this->get_attachment_id( $image_url ), 1059 813 ]; 1060 814 } … … 1062 816 } 1063 817 } 1064 1065 818 return $images; 1066 819 } 1067 820 1068 private function is_image_setting($key, $value) { 1069 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 821 private function is_image_setting( $key, $value ) { 822 return; 823 $image_keys = [ 824 'image', 825 'photo', 826 'picture', 827 'thumbnail', 828 'background_image' 829 ]; 830 foreach ( $image_keys as $image_key ) { 831 if ( strpos( $key, $image_key ) !== false ) { 832 return true; 833 } 834 } 835 if ( is_string( $value ) && preg_match( '/\\.(jpg|jpeg|png|gif)$/i', $value ) ) { 836 return true; 837 } 838 return false; 839 } 840 841 private function get_image_url( $value ) { 842 if ( is_array( $value ) && isset( $value['url'] ) ) { 843 return $value['url']; 844 } 845 if ( is_string( $value ) && filter_var( $value, FILTER_VALIDATE_URL ) ) { 846 return $value; 847 } 848 return null; 849 } 850 851 private function update_elementor_image_settings( 852 $post_id, 853 $element_id, 854 $setting_key, 855 $metas 856 ) { 857 return; 858 $document = \Elementor\Plugin::$instance->documents->get( $post_id ); 859 if ( !$document ) { 1070 860 return; 1071 861 } 1072 $image_keys = ['image', 'photo', 'picture', 'thumbnail', 'background_image'];1073 1074 foreach ($image_keys as $image_key) {1075 if (strpos($key, $image_key) !== false) {1076 return true;1077 }1078 }1079 1080 if (is_string($value) && preg_match('/\.(jpg|jpeg|png|gif)$/i', $value)) {1081 return true;1082 }1083 1084 return false;1085 }1086 1087 private function get_image_url($value) {1088 if (is_array($value) && isset($value['url'])) {1089 return $value['url'];1090 }1091 if (is_string($value) && filter_var($value, FILTER_VALIDATE_URL)) {1092 return $value;1093 }1094 return null;1095 }1096 1097 private function update_elementor_image_settings($post_id, $element_id, $setting_key, $metas) {1098 if ( ! oneoneclickseo_fs()->is__premium_only() ) {1099 return;1100 }1101 $document = \Elementor\Plugin::$instance->documents->get($post_id);1102 if (!$document) {1103 return;1104 }1105 1106 862 $elements_data = $document->get_elements_data(); 1107 863 $modified = false; 1108 1109 $this->update_element_image_settings($elements_data, $element_id, $setting_key, $metas, $modified); 1110 1111 if ($modified) { 1112 $document->save(['elements' => $elements_data]); 1113 } 1114 } 1115 1116 private function update_element_image_settings(&$elements, $element_id, $setting_key, $metas, &$modified) { 1117 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 1118 return; 1119 } 1120 foreach ($elements as &$element) { 1121 if ($element['id'] === $element_id) { 1122 if (isset($element['settings'][$setting_key])) { 1123 if (is_array($element['settings'][$setting_key])) { 864 $this->update_element_image_settings( 865 $elements_data, 866 $element_id, 867 $setting_key, 868 $metas, 869 $modified 870 ); 871 if ( $modified ) { 872 $document->save( [ 873 'elements' => $elements_data, 874 ] ); 875 } 876 } 877 878 private function update_element_image_settings( 879 &$elements, 880 $element_id, 881 $setting_key, 882 $metas, 883 &$modified 884 ) { 885 return; 886 foreach ( $elements as &$element ) { 887 if ( $element['id'] === $element_id ) { 888 if ( isset( $element['settings'][$setting_key] ) ) { 889 if ( is_array( $element['settings'][$setting_key] ) ) { 1124 890 $element['settings'][$setting_key]['alt'] = $metas['alt_text']; 1125 891 $element['settings'][$setting_key]['title'] = $metas['title']; … … 1128 894 } 1129 895 } 1130 1131 if (!empty($element['elements'])) { 1132 $this->update_element_image_settings($element['elements'], $element_id, $setting_key, $metas, $modified); 896 if ( !empty( $element['elements'] ) ) { 897 $this->update_element_image_settings( 898 $element['elements'], 899 $element_id, 900 $setting_key, 901 $metas, 902 $modified 903 ); 1133 904 } 1134 905 } … … 1136 907 1137 908 public function analyze_site() { 1138 $home_id = get_option( 'page_on_front');909 $home_id = get_option( 'page_on_front' ); 1139 910 $content = ''; 1140 911 $analysis = []; 1141 1142 1143 if (!$home_id) { 1144 $recent_pages = get_posts([ 1145 'post_type' => 'page', 912 if ( !$home_id ) { 913 $recent_pages = get_posts( [ 914 'post_type' => 'page', 1146 915 'posts_per_page' => 1, 1147 'orderby' => 'date',1148 'order' => 'DESC',1149 'post_status' => 'publish'1150 ] );1151 if ( !empty($recent_pages)) {916 'orderby' => 'date', 917 'order' => 'DESC', 918 'post_status' => 'publish', 919 ] ); 920 if ( !empty( $recent_pages ) ) { 1152 921 $home_id = $recent_pages[0]->ID; 1153 922 } 1154 923 } 1155 1156 if (!$home_id) { 1157 throw new Exception(esc_html__('Home page not found', 'one-click-seo-optimizer')); 1158 } 1159 924 if ( !$home_id ) { 925 throw new Exception(esc_html__( 'Home page not found', 'one-click-seo-optimizer' )); 926 } 1160 927 $content = ''; 1161 1162 if (class_exists('\Elementor\Plugin')) { 1163 $document = \Elementor\Plugin::$instance->documents->get($home_id); 1164 if ($document) { 928 if ( class_exists( '\\Elementor\\Plugin' ) ) { 929 $document = \Elementor\Plugin::$instance->documents->get( $home_id ); 930 if ( $document ) { 1165 931 $data = $document->get_elements_data(); 1166 $content = $this->extract_elementor_content($data); 1167 } 1168 } 1169 1170 if (empty($content)) { 1171 $post = get_post($home_id); 932 $content = $this->extract_elementor_content( $data ); 933 } 934 } 935 if ( empty( $content ) ) { 936 $post = get_post( $home_id ); 1172 937 $content = $post->post_content; 1173 938 } 1174 1175 $prompt = sprintf( 1176 "Analyse le contenu suivant et fournis une analyse SEO structurée au format JSON avec les champs suivants : description_site, objectif, audience_cible, mots_clefs (array), thematique. Contenu à analyser :\n\n%s", 1177 $content 1178 ); 1179 1180 $language = get_bloginfo('language'); 1181 1182 if ($language) { 939 $prompt = sprintf( "Analyse le contenu suivant et fournis une analyse SEO structurée au format JSON avec les champs suivants : description_site, objectif, audience_cible, mots_clefs (array), thematique. Contenu à analyser :\n\n%s", $content ); 940 $language = get_bloginfo( 'language' ); 941 if ( $language ) { 1183 942 $prompt .= "\n\nLangue à utiliser : " . $language; 1184 943 } 1185 1186 $response = $this->call_openai_api('chat/completions', [ 1187 'model' => $this->model, 1188 'messages' => [ 1189 [ 1190 'role' => 'system', 1191 'content' => 'Tu es un expert SEO chargé d\'analyser le contenu d\'un site web. Réponds uniquement avec un objet JSON valide.' 1192 ], 1193 [ 1194 'role' => 'user', 1195 'content' => $prompt 1196 ] 1197 ], 1198 'temperature' => 0.7 1199 ]); 1200 944 $response = $this->call_openai_api( 'chat/completions', [ 945 'model' => $this->model, 946 'messages' => [[ 947 'role' => 'system', 948 'content' => 'Tu es un expert SEO chargé d\'analyser le contenu d\'un site web. Réponds uniquement avec un objet JSON valide.', 949 ], [ 950 'role' => 'user', 951 'content' => $prompt, 952 ]], 953 'temperature' => 0.7, 954 ] ); 1201 955 $content = $response['choices'][0]['message']['content']; 1202 $json_str = $this->extract_json($content); 1203 $analysis = json_decode($json_str, true); 1204 1205 update_option('oneclickseo_site_analysis', $analysis); 1206 update_option('oneclickseo_last_analysis', current_time('timestamp')); 1207 956 $json_str = $this->extract_json( $content ); 957 $analysis = json_decode( $json_str, true ); 958 update_option( 'oneclickseo_site_analysis', $analysis ); 959 update_option( 'oneclickseo_last_analysis', current_time( 'timestamp' ) ); 1208 960 return [ 1209 961 'success' => true, 1210 'data' => $analysis962 'data' => $analysis, 1211 963 ]; 1212 964 } 1213 965 1214 public function analyze_image($image_url) { 1215 if ( ! oneoneclickseo_fs()->is__premium_only() ) { 1216 return; 1217 } 1218 $analysis = get_option('oneclickseo_site_analysis'); 966 public function analyze_image( $image_url ) { 967 return; 968 $analysis = get_option( 'oneclickseo_site_analysis' ); 1219 969 $site_infos = array( 1220 970 'description_site' => $analysis['description_site'], 1221 'objectif' => $analysis['objectif'],1222 'audience_cible' => $analysis['audience_cible'],1223 'mots_clefs' => $analysis['mots_clefs'],1224 'thematique' => $analysis['thematique']971 'objectif' => $analysis['objectif'], 972 'audience_cible' => $analysis['audience_cible'], 973 'mots_clefs' => $analysis['mots_clefs'], 974 'thematique' => $analysis['thematique'], 1225 975 ); 1226 $prompt = sprintf( 1227 "Analyse cette image : %s et génère un objet JSON avec la structure exacte suivante : 1228 { 1229 \"metas\": { 1230 \"description\": \"Description détaillée de l'image en 150-160 caractères\", 1231 \"alt_text\": \"Texte alternatif court et descriptif\", 1232 \"title\": \"Titre optimisé pour le SEO\" 1233 } 1234 } 1235 1236 Contexte du site : 1237 %s 1238 1239 Instructions spécifiques : 1240 - La description doit être détaillée et optimisée pour le SEO (150-160 caractères) 1241 - L'alt_text doit être court et descriptif 1242 - Le title doit inclure si possible le nom du site ou la thématique principale 1243 1244 Réponds uniquement avec l'objet JSON demandé, sans texte additionnel.", 1245 $image_url, 1246 json_encode($site_infos, JSON_PRETTY_PRINT) 1247 ); 1248 $language = get_bloginfo('language'); 1249 1250 if ($language) { 976 $prompt = sprintf( "Analyse cette image : %s et génère un objet JSON avec la structure exacte suivante :\n {\n \"metas\": {\n \"description\": \"Description détaillée de l'image en 150-160 caractères\",\n \"alt_text\": \"Texte alternatif court et descriptif\",\n \"title\": \"Titre optimisé pour le SEO\"\n }\n }\n\n Contexte du site :\n %s\n\n Instructions spécifiques :\n - La description doit être détaillée et optimisée pour le SEO (150-160 caractères)\n - L'alt_text doit être court et descriptif\n - Le title doit inclure si possible le nom du site ou la thématique principale\n \n Réponds uniquement avec l'objet JSON demandé, sans texte additionnel.", $image_url, json_encode( $site_infos, JSON_PRETTY_PRINT ) ); 977 $language = get_bloginfo( 'language' ); 978 if ( $language ) { 1251 979 $prompt .= "\n\nLangue à utiliser : " . $language; 1252 980 } 1253 1254 1255 $response = $this->call_openai_api('chat/completions', [ 1256 'model' => $this->model, 1257 'messages' => [ 1258 [ 1259 'role' => 'system', 1260 'content' => 'Tu es un expert SEO chargé d\'analyser le contenu d\'un site web. Réponds uniquement avec un objet JSON valide.' 1261 ], 1262 [ 1263 'role' => 'user', 1264 'content' => $prompt 1265 ] 1266 ], 1267 'temperature' => 0.7 1268 ]); 1269 981 $response = $this->call_openai_api( 'chat/completions', [ 982 'model' => $this->model, 983 'messages' => [[ 984 'role' => 'system', 985 'content' => 'Tu es un expert SEO chargé d\'analyser le contenu d\'un site web. Réponds uniquement avec un objet JSON valide.', 986 ], [ 987 'role' => 'user', 988 'content' => $prompt, 989 ]], 990 'temperature' => 0.7, 991 ] ); 1270 992 $content = $response['choices'][0]['message']['content']; 1271 $json_str = $this->extract_json($content); 1272 $metas = json_decode($json_str, true); 1273 993 $json_str = $this->extract_json( $content ); 994 $metas = json_decode( $json_str, true ); 1274 995 return [ 1275 996 'success' => true, 1276 'data' => $metas997 'data' => $metas, 1277 998 ]; 1278 999 } 1279 1000 1280 private function call_openai_api($endpoint, $data) { 1281 if (empty($this->api_key)) { 1282 throw new Exception(esc_html__('OpenAI API key not configured', 'one-click-seo-optimizer')); 1283 } 1284 1285 $response = wp_remote_post($this->api_base_url . '/' . $endpoint, [ 1001 private function call_openai_api( $endpoint, $data ) { 1002 if ( empty( $this->api_key ) ) { 1003 throw new Exception(esc_html__( 'OpenAI API key not configured', 'one-click-seo-optimizer' )); 1004 } 1005 $response = wp_remote_post( $this->api_base_url . '/' . $endpoint, [ 1286 1006 'headers' => [ 1287 1007 'Authorization' => 'Bearer ' . $this->api_key, 1288 'Content-Type' => 'application/json'1008 'Content-Type' => 'application/json', 1289 1009 ], 1290 'body' => json_encode($data), 1291 'timeout' => 30 1292 ]); 1293 1294 if (is_wp_error($response)) { 1295 throw new Exception(esc_html($response->get_error_message())); 1296 } 1297 1298 $body = json_decode(wp_remote_retrieve_body($response), true); 1299 1300 if (isset($body['error'])) { 1301 throw new Exception(esc_html($body['error']['message'])); 1302 } 1303 1010 'body' => json_encode( $data ), 1011 'timeout' => 30, 1012 ] ); 1013 if ( is_wp_error( $response ) ) { 1014 throw new Exception(esc_html( $response->get_error_message() )); 1015 } 1016 $body = json_decode( wp_remote_retrieve_body( $response ), true ); 1017 if ( isset( $body['error'] ) ) { 1018 throw new Exception(esc_html( $body['error']['message'] )); 1019 } 1304 1020 return $body; 1305 1021 } 1306 1022 1307 private function extract_elementor_content($elements) { 1308 1023 private function extract_elementor_content( $elements ) { 1309 1024 $content = ''; 1310 1311 foreach ($elements as $element) { 1312 if (!empty($element['elements'])) { 1313 $content .= $this->extract_elementor_content($element['elements']); 1314 } 1315 1316 if (isset($element['widgetType']) && $element['widgetType'] === 'heading') { 1025 foreach ( $elements as $element ) { 1026 if ( !empty( $element['elements'] ) ) { 1027 $content .= $this->extract_elementor_content( $element['elements'] ); 1028 } 1029 if ( isset( $element['widgetType'] ) && $element['widgetType'] === 'heading' ) { 1317 1030 $content .= $element['settings']['title'] . "\n\n"; 1318 1031 } 1319 1320 if (isset($element['widgetType']) && $element['widgetType'] === 'text-editor') { 1321 $content .= wp_strip_all_tags($element['settings']['editor']) . "\n\n"; 1322 } 1323 } 1324 1032 if ( isset( $element['widgetType'] ) && $element['widgetType'] === 'text-editor' ) { 1033 $content .= wp_strip_all_tags( $element['settings']['editor'] ) . "\n\n"; 1034 } 1035 } 1325 1036 return $content; 1326 1037 } 1327 1038 1328 private function extract_json($string) { 1329 $start = strpos($string, '{'); 1330 $end = strrpos($string, '}'); 1331 1332 if ($start === false || $end === false) { 1333 throw new Exception(esc_html__('Invalid response format', 'one-click-seo-optimizer')); 1334 } 1335 1336 return substr($string, $start, $end - $start + 1); 1337 } 1338 1339 private function add_chat_message($message) { 1039 private function extract_json( $string ) { 1040 $start = strpos( $string, '{' ); 1041 $end = strrpos( $string, '}' ); 1042 if ( $start === false || $end === false ) { 1043 throw new Exception(esc_html__( 'Invalid response format', 'one-click-seo-optimizer' )); 1044 } 1045 return substr( $string, $start, $end - $start + 1 ); 1046 } 1047 1048 private function add_chat_message( $message ) { 1340 1049 return [ 1341 'type' => 'chat',1342 'message' => $message 1050 'type' => 'chat', 1051 'message' => $message, 1343 1052 ]; 1344 1053 } 1345 1054 1346 public function analyze_internal_linking($post_id) { 1347 $post = get_post($post_id); 1348 if (!$post) { 1349 throw new Exception(esc_html__('Invalid post', 'one-click-seo-optimizer')); 1350 } 1351 1352 $all_pages = get_posts([ 1353 'post_type' => ['post', 'page'], 1055 public function analyze_internal_linking( $post_id ) { 1056 $post = get_post( $post_id ); 1057 if ( !$post ) { 1058 throw new Exception(esc_html__( 'Invalid post', 'one-click-seo-optimizer' )); 1059 } 1060 $all_pages = get_posts( [ 1061 'post_type' => ['post', 'page'], 1354 1062 'posts_per_page' => -1, 1355 'post__not_in' => [$post_id] 1356 ]); 1357 1358 $pages_data = array_map(function($page) { 1063 'post__not_in' => [$post_id], 1064 ] ); 1065 $pages_data = array_map( function ( $page ) { 1359 1066 return [ 1360 'id' => $page->ID,1361 'title' => $page->post_title,1362 'content' => wp_strip_all_tags($page->post_content),1363 'url' => get_permalink($page->ID),1364 'keywords' => get_post_meta( $page->ID, '_oneclickseo_keywords', true),1067 'id' => $page->ID, 1068 'title' => $page->post_title, 1069 'content' => wp_strip_all_tags( $page->post_content ), 1070 'url' => get_permalink( $page->ID ), 1071 'keywords' => get_post_meta( $page->ID, '_oneclickseo_keywords', true ), 1365 1072 ]; 1366 }, $all_pages); 1367 1073 }, $all_pages ); 1368 1074 $prompt = sprintf( 1369 "Analysez cette page et suggérez des liens internes pertinents. Voici les informations :\n\n" . 1370 "Page à analyser :\n" . 1371 "Titre : %s\n" . 1372 "Contenu : %s\n" . 1373 "Mots-clés : %s\n\n" . 1374 "Pages disponibles pour le maillage :\n%s\n\n" . 1375 "Fournissez un objet JSON avec :\n" . 1376 "- suggested_links: tableau d'objets avec url,target_id, anchor_text, context, relevance_score (0-100)\n" . 1377 "- content_placement: suggestions d'emplacements dans le contenu\n" . 1378 "- semantic_clusters: groupes thématiques de pages liées", 1075 "Analysez cette page et suggérez des liens internes pertinents. Voici les informations :\n\n" . "Page à analyser :\n" . "Titre : %s\n" . "Contenu : %s\n" . "Mots-clés : %s\n\n" . "Pages disponibles pour le maillage :\n%s\n\n" . "Fournissez un objet JSON avec :\n" . "- suggested_links: tableau d'objets avec url,target_id, anchor_text, context, relevance_score (0-100)\n" . "- content_placement: suggestions d'emplacements dans le contenu\n" . "- semantic_clusters: groupes thématiques de pages liées", 1379 1076 $post->post_title, 1380 wp_strip_all_tags( $post->post_content),1381 get_post_meta( $post_id, '_oneclickseo_keywords', true),1382 json_encode( $pages_data)1077 wp_strip_all_tags( $post->post_content ), 1078 get_post_meta( $post_id, '_oneclickseo_keywords', true ), 1079 json_encode( $pages_data ) 1383 1080 ); 1384 1385 $language = get_bloginfo('language'); 1386 1387 if ($language) { 1081 $language = get_bloginfo( 'language' ); 1082 if ( $language ) { 1388 1083 $prompt .= "\n\nLangue à utiliser : " . $language; 1389 1084 } 1390 1391 $response = $this->call_openai_api('chat/completions', [ 1392 'model' => $this->model, 1393 'messages' => [ 1394 [ 1395 'role' => 'system', 1396 'content' => 'Vous êtes un expert en SEO spécialisé dans l\'analyse du maillage interne.' 1397 ], 1398 [ 1399 'role' => 'user', 1400 'content' => $prompt 1401 ] 1402 ], 1403 'temperature' => 0.7 1404 ]); 1405 1085 $response = $this->call_openai_api( 'chat/completions', [ 1086 'model' => $this->model, 1087 'messages' => [[ 1088 'role' => 'system', 1089 'content' => 'Vous êtes un expert en SEO spécialisé dans l\'analyse du maillage interne.', 1090 ], [ 1091 'role' => 'user', 1092 'content' => $prompt, 1093 ]], 1094 'temperature' => 0.7, 1095 ] ); 1406 1096 $content = $response['choices'][0]['message']['content']; 1407 $analysis = json_decode($this->extract_json($content), true); 1408 1409 update_post_meta($post_id, '_oneclickseo_internal_linking_analysis', $analysis); 1410 1097 $analysis = json_decode( $this->extract_json( $content ), true ); 1098 update_post_meta( $post_id, '_oneclickseo_internal_linking_analysis', $analysis ); 1411 1099 return $analysis; 1412 1100 } 1413 1101 1414 public function generate_meta_title( $data) {1102 public function generate_meta_title( $data ) { 1415 1103 try { 1416 $response = $this->make_api_request( '/generate/meta-title', $data);1104 $response = $this->make_api_request( '/generate/meta-title', $data ); 1417 1105 return $response['title']; 1418 } catch ( Exception $e) {1419 throw new Exception(esc_html__( 'Error generating the meta title', 'one-click-seo-optimizer'));1420 } 1421 } 1422 1423 public function generate_meta_description( $data) {1106 } catch ( Exception $e ) { 1107 throw new Exception(esc_html__( 'Error generating the meta title', 'one-click-seo-optimizer' )); 1108 } 1109 } 1110 1111 public function generate_meta_description( $data ) { 1424 1112 try { 1425 $response = $this->make_api_request( '/generate/meta-description', $data);1113 $response = $this->make_api_request( '/generate/meta-description', $data ); 1426 1114 return $response['description']; 1427 } catch ( Exception $e) {1428 throw new Exception(esc_html__( 'Error generating the meta description', 'one-click-seo-optimizer'));1429 } 1430 } 1431 1432 public function generate_h1( $data) {1115 } catch ( Exception $e ) { 1116 throw new Exception(esc_html__( 'Error generating the meta description', 'one-click-seo-optimizer' )); 1117 } 1118 } 1119 1120 public function generate_h1( $data ) { 1433 1121 try { 1434 $response = $this->make_api_request( '/generate/h1', $data);1122 $response = $this->make_api_request( '/generate/h1', $data ); 1435 1123 return $response['h1']; 1436 } catch ( Exception $e) {1437 throw new Exception(esc_html__( 'Error generating the H1', 'one-click-seo-optimizer'));1438 } 1439 } 1440 1441 public function generate_content_suggestions( $data) {1124 } catch ( Exception $e ) { 1125 throw new Exception(esc_html__( 'Error generating the H1', 'one-click-seo-optimizer' )); 1126 } 1127 } 1128 1129 public function generate_content_suggestions( $data ) { 1442 1130 try { 1443 $response = $this->make_api_request( '/generate/content-suggestions', $data);1131 $response = $this->make_api_request( '/generate/content-suggestions', $data ); 1444 1132 return $response['suggestions']; 1445 } catch ( Exception $e) {1446 throw new Exception(esc_html__( 'Error generating content suggestions', 'one-click-seo-optimizer'));1447 } 1448 } 1449 1450 public function generate_internal_linking( $data) {1133 } catch ( Exception $e ) { 1134 throw new Exception(esc_html__( 'Error generating content suggestions', 'one-click-seo-optimizer' )); 1135 } 1136 } 1137 1138 public function generate_internal_linking( $data ) { 1451 1139 try { 1452 $response = $this->make_api_request( '/generate/internal-linking', $data);1140 $response = $this->make_api_request( '/generate/internal-linking', $data ); 1453 1141 return $response['links']; 1454 } catch ( Exception $e) {1455 throw new Exception(esc_html__( 'Error generating internal linking suggestions', 'one-click-seo-optimizer'));1456 } 1457 } 1458 1459 private function make_api_request( $endpoint, $data) {1460 $response = wp_remote_post( $this->api_base_url . $endpoint, [1142 } catch ( Exception $e ) { 1143 throw new Exception(esc_html__( 'Error generating internal linking suggestions', 'one-click-seo-optimizer' )); 1144 } 1145 } 1146 1147 private function make_api_request( $endpoint, $data ) { 1148 $response = wp_remote_post( $this->api_base_url . $endpoint, [ 1461 1149 'headers' => [ 1462 1150 'Authorization' => 'Bearer ' . $this->api_key, 1463 'Content-Type' => 'application/json'1151 'Content-Type' => 'application/json', 1464 1152 ], 1465 'body' => json_encode($data), 1466 'timeout' => 30 1467 ]); 1468 1469 if (is_wp_error($response)) { 1470 throw new Exception(esc_html($response->get_error_message())); 1471 } 1472 1473 $body = json_decode(wp_remote_retrieve_body($response), true); 1474 1475 if (isset($body['error'])) { 1476 throw new Exception(esc_html($body['error'])); 1477 } 1478 1153 'body' => json_encode( $data ), 1154 'timeout' => 30, 1155 ] ); 1156 if ( is_wp_error( $response ) ) { 1157 throw new Exception(esc_html( $response->get_error_message() )); 1158 } 1159 $body = json_decode( wp_remote_retrieve_body( $response ), true ); 1160 if ( isset( $body['error'] ) ) { 1161 throw new Exception(esc_html( $body['error'] )); 1162 } 1479 1163 return $body; 1480 1164 } 1481 1165 1482 public function validate_api_key( $api_key) {1166 public function validate_api_key( $api_key ) { 1483 1167 try { 1484 $response = wp_remote_post( $this->api_base_url . '/chat/completions', [1168 $response = wp_remote_post( $this->api_base_url . '/chat/completions', [ 1485 1169 'headers' => [ 1486 1170 'Authorization' => 'Bearer ' . $api_key, 1487 'Content-Type' => 'application/json'1171 'Content-Type' => 'application/json', 1488 1172 ], 1489 'body' => json_encode([ 1490 'model' => 'gpt-3.5-turbo', 1491 'messages' => [ 1492 [ 1493 'role' => 'user', 1494 'content' => 'Test API key' 1495 ] 1496 ], 1497 'max_tokens' => 5 1498 ]), 1499 'timeout' => 15 1500 ]); 1501 1502 if (is_wp_error($response)) { 1173 'body' => json_encode( [ 1174 'model' => 'gpt-3.5-turbo', 1175 'messages' => [[ 1176 'role' => 'user', 1177 'content' => 'Test API key', 1178 ]], 1179 'max_tokens' => 5, 1180 ] ), 1181 'timeout' => 15, 1182 ] ); 1183 if ( is_wp_error( $response ) ) { 1503 1184 return false; 1504 1185 } 1505 1506 $body = json_decode(wp_remote_retrieve_body($response), true); 1507 $status_code = wp_remote_retrieve_response_code($response); 1508 1509 if ($status_code === 200 && !isset($body['error'])) { 1186 $body = json_decode( wp_remote_retrieve_body( $response ), true ); 1187 $status_code = wp_remote_retrieve_response_code( $response ); 1188 if ( $status_code === 200 && !isset( $body['error'] ) ) { 1510 1189 return true; 1511 1190 } 1512 1513 1514 1191 return false; 1515 } catch ( Exception $e) {1192 } catch ( Exception $e ) { 1516 1193 return false; 1517 1194 } 1518 1195 } 1519 1196 1520 private function optimize_content_images( $content) {1197 private function optimize_content_images( $content ) { 1521 1198 $optimized_images = []; 1522 1523 preg_match_all('/<img[^>]+>/i', $content, $matches); 1524 1525 foreach ($matches[0] as $img_tag) { 1526 if (preg_match('/src=["\']([^"\']+)["\']/i', $img_tag, $src_match)) { 1199 preg_match_all( '/<img[^>]+>/i', $content, $matches ); 1200 foreach ( $matches[0] as $img_tag ) { 1201 if ( preg_match( '/src=["\']([^"\']+)["\']/i', $img_tag, $src_match ) ) { 1527 1202 $image_url = $src_match[1]; 1528 1529 1203 try { 1530 $analysis = $this->analyze_image($image_url); 1531 1532 if ($analysis['success']) { 1533 $attachment_id = attachment_url_to_postid($image_url); 1534 1535 if ($attachment_id) { 1204 $analysis = $this->analyze_image( $image_url ); 1205 if ( $analysis['success'] ) { 1206 $attachment_id = attachment_url_to_postid( $image_url ); 1207 if ( $attachment_id ) { 1536 1208 $attachment_data = array( 1537 'ID' => $attachment_id,1538 'post_title' => $analysis['data']['metas']['title'],1209 'ID' => $attachment_id, 1210 'post_title' => $analysis['data']['metas']['title'], 1539 1211 'post_excerpt' => $analysis['data']['metas']['alt_text'], 1540 'post_content' => $analysis['data']['metas']['description'] 1212 'post_content' => $analysis['data']['metas']['description'], 1541 1213 ); 1542 wp_update_post($attachment_data); 1543 1544 update_post_meta($attachment_id, '_wp_attachment_image_alt', $analysis['data']['metas']['alt_text']); 1545 1214 wp_update_post( $attachment_data ); 1215 update_post_meta( $attachment_id, '_wp_attachment_image_alt', $analysis['data']['metas']['alt_text'] ); 1546 1216 $optimized_images[] = [ 1547 1217 'image_url' => $image_url, 1548 'alt' => $analysis['data']['metas']['alt_text'],1549 'title' => $analysis['data']['metas']['title'],1550 'type' => 'content_image'1218 'alt' => $analysis['data']['metas']['alt_text'], 1219 'title' => $analysis['data']['metas']['title'], 1220 'type' => 'content_image', 1551 1221 ]; 1552 1222 } 1553 1223 } 1554 } catch (Exception $e) { 1555 1556 } 1557 } 1558 } 1559 1224 } catch ( Exception $e ) { 1225 } 1226 } 1227 } 1560 1228 return $optimized_images; 1561 1229 } 1562 1230 1563 private function get_attachment_id( $image_url) {1231 private function get_attachment_id( $image_url ) { 1564 1232 global $wpdb; 1565 1566 $image_url = preg_replace('/^https?:\/\//', '', $image_url); 1567 $image_url = preg_replace('/[?#].*$/', '', $image_url); 1568 1569 1570 1571 $attachment_id = attachment_url_to_postid('https://' . $image_url); 1572 if (!$attachment_id) { 1573 $attachment_id = attachment_url_to_postid('http://' . $image_url); 1574 } 1575 1576 if (!$attachment_id) { 1577 $attachment_id = attachment_url_to_postid('http://' . $image_url); 1578 if (!$attachment_id) { 1579 $attachment_id = attachment_url_to_postid('https://' . $image_url); 1580 } 1581 } 1582 1233 $image_url = preg_replace( '/^https?:\\/\\//', '', $image_url ); 1234 $image_url = preg_replace( '/[?#].*$/', '', $image_url ); 1235 $attachment_id = attachment_url_to_postid( 'https://' . $image_url ); 1236 if ( !$attachment_id ) { 1237 $attachment_id = attachment_url_to_postid( 'http://' . $image_url ); 1238 } 1239 if ( !$attachment_id ) { 1240 $attachment_id = attachment_url_to_postid( 'http://' . $image_url ); 1241 if ( !$attachment_id ) { 1242 $attachment_id = attachment_url_to_postid( 'https://' . $image_url ); 1243 } 1244 } 1583 1245 return $attachment_id; 1584 1246 } 1585 } 1247 1248 } -
one-click-seo-optimizer/trunk/oneclickseo.php
r3249837 r3249839 1 1 <?php 2 2 3 /** 3 4 * Plugin Name: One Click SEO Optimizer … … 13 14 * Requires PHP: 7.4 14 15 */ 15 if ( !defined('ABSPATH')) {16 if ( !defined( 'ABSPATH' ) ) { 16 17 exit; 17 18 } 18 19 require_once __DIR__ . '/vendor/autoload.php'; 19 20 define('ONECLICKSEO_VERSION', '1.0.1'); 21 define('ONECLICKSEO_PLUGIN_DIR', plugin_dir_path(__FILE__)); 22 define('ONECLICKSEO_PLUGIN_URL', plugin_dir_url(__FILE__)); 23 define('ONECLICKSEO_PLUGIN_FILE', __FILE__); 24 25 if ( ! function_exists( 'oneoneclickseo_fs' ) ) { 20 define( 'ONECLICKSEO_VERSION', '1.0.1' ); 21 define( 'ONECLICKSEO_PLUGIN_DIR', plugin_dir_path( __FILE__ ) ); 22 define( 'ONECLICKSEO_PLUGIN_URL', plugin_dir_url( __FILE__ ) ); 23 define( 'ONECLICKSEO_PLUGIN_FILE', __FILE__ ); 24 if ( !function_exists( 'oneoneclickseo_fs' ) ) { 26 25 function oneoneclickseo_fs() { 27 26 global $oneoneclickseo_fs; 28 29 if ( ! isset( $oneoneclickseo_fs ) ) { 30 require_once dirname(__FILE__) . '/vendor/freemius/wordpress-sdk/start.php'; 31 27 if ( !isset( $oneoneclickseo_fs ) ) { 28 require_once dirname( __FILE__ ) . '/vendor/freemius/wordpress-sdk/start.php'; 32 29 $oneoneclickseo_fs = fs_dynamic_init( array( 33 'id' => '17825', 34 'slug' => 'oneclickseo', 35 'type' => 'plugin', 36 'public_key' => 'pk_69cf6dd9b1c66d2065a88e93ee678', 37 'is_premium' => true, 38 'premium_suffix' => 'Pro', 39 'has_premium_version' => true, 40 'has_addons' => false, 41 'has_paid_plans' => true, 42 'menu' => array( 43 'slug' => 'oneclickseo', 44 'support' => false, 30 'id' => '17825', 31 'slug' => 'oneclickseo', 32 'type' => 'plugin', 33 'public_key' => 'pk_69cf6dd9b1c66d2065a88e93ee678', 34 'is_premium' => false, 35 'premium_suffix' => 'Pro', 36 'has_addons' => false, 37 'has_paid_plans' => true, 38 'menu' => array( 39 'slug' => 'oneclickseo', 40 'support' => false, 45 41 ), 42 'is_live' => true, 46 43 ) ); 47 44 } 48 49 45 return $oneoneclickseo_fs; 50 46 } … … 53 49 do_action( 'oneoneclickseo_fs_loaded' ); 54 50 } 55 56 51 require_once ONECLICKSEO_PLUGIN_DIR . 'includes/class-oneclickseo.php'; 57 52 require_once ONECLICKSEO_PLUGIN_DIR . 'includes/class-oneclickseo-admin.php'; … … 62 57 require_once ONECLICKSEO_PLUGIN_DIR . 'includes/class-oneclickseo-updater.php'; 63 58 require_once ONECLICKSEO_PLUGIN_DIR . 'includes/class-oneclickseo-sitemap.php'; 64 65 59 function oneclickseo_init() { 66 load_plugin_textdomain('one-click-seo-optimizer', false, dirname(plugin_basename(__FILE__)) . '/languages'); 67 60 load_plugin_textdomain( 'one-click-seo-optimizer', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' ); 68 61 $api = new OneClickSEO_API(); 69 62 $settings = new OneClickSEO_Settings(); … … 71 64 $elementor = new OneClickSEO_Elementor(); 72 65 $updater = new OneClickSEO_Updater(); 73 74 66 $oneclickseo = new OneClickSEO(); 75 67 $oneclickseo->init(); 76 68 } 77 add_action('plugins_loaded', 'oneclickseo_init');78 69 79 register_activation_hook(__FILE__, array('OneClickSEO_Updater', 'activate'));80 81 register_deactivation_hook( __FILE__, array('OneClickSEO_Updater', 'deactivate'));70 add_action( 'plugins_loaded', 'oneclickseo_init' ); 71 register_activation_hook( __FILE__, array('OneClickSEO_Updater', 'activate') ); 72 register_deactivation_hook( __FILE__, array('OneClickSEO_Updater', 'deactivate') ); -
one-click-seo-optimizer/trunk/readme.txt
r3249837 r3249839 1 1 === One Click SEO Optimizer === 2 Contributors: loopus 2 Contributors: loopus, freemius 3 3 Tags: seo, artificial intelligence, gpt-4, optimization, search engine 4 4 Requires at least: 5.0
Note: See TracChangeset
for help on using the changeset viewer.