@lynxflow/seo-engine 1.7.8 β 1.7.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Plugin Name: LynxSEO Studio β Ultimate Enterprise WordPress Suite
|
|
4
4
|
* Plugin URI: https://lynxseo.studio/wordpress
|
|
5
|
-
* Description: The definitive
|
|
6
|
-
* Version:
|
|
5
|
+
* Description: The definitive enterprise-grade WordPress SEO suite built on React & WordPress Gutenberg APIs. Features a Real-Time React Gutenberg Sidebar with Header Score Badge (0-100), Visual Schema Generator Modal (14+ Types), 5-Step Interactive Setup Wizard, Dedicated High-Performance SQL Tables (Redirections, 404 Logs, Analytics), Google Business Profile Local SEO, YouTube & Video SEO, Multilingual Auto-Detection (WPML/Polylang/Weglot), In-Memory Programmatic Engine (< 0.05ms in RAM), 50 Interactive Shortcodes, and /llms.txt AI Search Feed.
|
|
6
|
+
* Version: 8.0.0
|
|
7
7
|
* Author: LynxSEO / LynxFlow Technologies
|
|
8
8
|
* Author URI: https://lynxseo.studio
|
|
9
9
|
* Text Domain: lynxseo
|
|
@@ -18,11 +18,12 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
18
18
|
private $gbp_option = 'lynxseo_gbp_settings';
|
|
19
19
|
private $video_option = 'lynxseo_video_settings';
|
|
20
20
|
private $webmaster_option = 'lynxseo_webmaster_settings';
|
|
21
|
-
private $
|
|
22
|
-
private $logs_option = 'lynxseo_404_logs';
|
|
23
|
-
private $version = '7.0.0';
|
|
21
|
+
private $version = '8.0.0';
|
|
24
22
|
|
|
25
23
|
public function __construct() {
|
|
24
|
+
// Activation & DB Tables Setup
|
|
25
|
+
register_activation_hook(__FILE__, array($this, 'create_custom_sql_tables'));
|
|
26
|
+
|
|
26
27
|
// Core Hooks
|
|
27
28
|
add_action('init', array($this, 'init_plugin'));
|
|
28
29
|
add_action('wp_head', array($this, 'inject_seo_header_metadata'), 1);
|
|
@@ -31,41 +32,92 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
31
32
|
add_action('wp_head', array($this, 'inject_gbp_local_schema'), 4);
|
|
32
33
|
add_action('template_redirect', array($this, 'handle_routing_and_redirects'), 1);
|
|
33
34
|
|
|
34
|
-
// Content Filters
|
|
35
|
+
// Content Filters
|
|
35
36
|
add_filter('the_content', array($this, 'auto_image_seo_optimizer'));
|
|
36
37
|
add_filter('the_content', array($this, 'auto_youtube_video_seo_optimizer'));
|
|
37
38
|
add_filter('robots_txt', array($this, 'custom_robots_txt_handler'), 10, 2);
|
|
38
39
|
|
|
39
|
-
//
|
|
40
|
+
// React Gutenberg Sidebar & Header Badge
|
|
41
|
+
add_action('enqueue_block_editor_assets', array($this, 'enqueue_react_gutenberg_assets'));
|
|
42
|
+
|
|
43
|
+
// Admin Pages & Menus
|
|
40
44
|
add_action('add_meta_boxes', array($this, 'register_seo_metaboxes'));
|
|
41
45
|
add_action('save_post', array($this, 'save_seo_metabox_data'));
|
|
42
46
|
add_action('admin_menu', array($this, 'register_admin_menus'));
|
|
43
47
|
add_action('admin_init', array($this, 'register_settings'));
|
|
44
|
-
add_action('admin_enqueue_scripts', array($this, '
|
|
48
|
+
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
|
|
45
49
|
|
|
46
|
-
// Instant IndexNow
|
|
50
|
+
// Instant IndexNow Pinging
|
|
47
51
|
add_action('wp_after_insert_post', array($this, 'trigger_instant_indexing'), 10, 2);
|
|
48
52
|
|
|
49
|
-
//
|
|
53
|
+
// 50 Shortcodes Registration
|
|
50
54
|
$this->register_50_shortcodes();
|
|
51
55
|
}
|
|
52
56
|
|
|
57
|
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
58
|
+
* ποΈ 1. DEDICATED HIGH-PERFORMANCE SQL TABLES
|
|
59
|
+
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
60
|
+
public function create_custom_sql_tables() {
|
|
61
|
+
global $wpdb;
|
|
62
|
+
$charset_collate = $wpdb->get_charset_collate();
|
|
63
|
+
|
|
64
|
+
// 1. Redirections Table
|
|
65
|
+
$table_redirects = $wpdb->prefix . 'lynxseo_redirects';
|
|
66
|
+
$sql_redirects = "CREATE TABLE IF NOT EXISTS $table_redirects (
|
|
67
|
+
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
68
|
+
url_from varchar(255) NOT NULL,
|
|
69
|
+
url_to text NOT NULL,
|
|
70
|
+
status_code smallint(4) NOT NULL DEFAULT 301,
|
|
71
|
+
hits bigint(20) unsigned NOT NULL DEFAULT 0,
|
|
72
|
+
created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
73
|
+
PRIMARY KEY (id),
|
|
74
|
+
KEY url_from (url_from(191))
|
|
75
|
+
) $charset_collate;";
|
|
76
|
+
|
|
77
|
+
// 2. 404 Error Logs Table
|
|
78
|
+
$table_404 = $wpdb->prefix . 'lynxseo_404_logs';
|
|
79
|
+
$sql_404 = "CREATE TABLE IF NOT EXISTS $table_404 (
|
|
80
|
+
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
81
|
+
uri varchar(255) NOT NULL,
|
|
82
|
+
user_agent varchar(255) DEFAULT '',
|
|
83
|
+
referrer varchar(255) DEFAULT '',
|
|
84
|
+
hits bigint(20) unsigned NOT NULL DEFAULT 1,
|
|
85
|
+
last_accessed datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
86
|
+
PRIMARY KEY (id),
|
|
87
|
+
KEY uri (uri(191))
|
|
88
|
+
) $charset_collate;";
|
|
89
|
+
|
|
90
|
+
// 3. Analytics & Keyword Rankings Table
|
|
91
|
+
$table_analytics = $wpdb->prefix . 'lynxseo_analytics';
|
|
92
|
+
$sql_analytics = "CREATE TABLE IF NOT EXISTS $table_analytics (
|
|
93
|
+
id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
|
94
|
+
keyword varchar(255) NOT NULL,
|
|
95
|
+
page_url text NOT NULL,
|
|
96
|
+
clicks int(11) NOT NULL DEFAULT 0,
|
|
97
|
+
impressions int(11) NOT NULL DEFAULT 0,
|
|
98
|
+
ctr float NOT NULL DEFAULT 0,
|
|
99
|
+
position float NOT NULL DEFAULT 0,
|
|
100
|
+
recorded_date date NOT NULL,
|
|
101
|
+
PRIMARY KEY (id),
|
|
102
|
+
KEY keyword (keyword(191))
|
|
103
|
+
) $charset_collate;";
|
|
104
|
+
|
|
105
|
+
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
|
|
106
|
+
dbDelta($sql_redirects);
|
|
107
|
+
dbDelta($sql_404);
|
|
108
|
+
dbDelta($sql_analytics);
|
|
109
|
+
}
|
|
110
|
+
|
|
53
111
|
public function init_plugin() {
|
|
54
|
-
// Sitemaps & Feeds rewrite rules
|
|
55
112
|
add_rewrite_rule('^sitemap_index\.xml$', 'index.php?lynx_sitemap=index', 'top');
|
|
56
113
|
add_rewrite_rule('^sitemap-pseo\.xml$', 'index.php?lynx_sitemap=pseo', 'top');
|
|
57
114
|
add_rewrite_rule('^llms\.txt$', 'index.php?lynx_llms=1', 'top');
|
|
58
115
|
|
|
59
|
-
// Dynamic 8 Programmatic Matrices rewrite rules
|
|
60
116
|
add_rewrite_rule('^solutions/([^/]+)/([^/]+)/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=geo&lynx_p1=$matches[1]&lynx_p2=$matches[2]&lynx_p3=$matches[3]', 'top');
|
|
61
117
|
add_rewrite_rule('^comparatif/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=vs&lynx_p1=$matches[1]', 'top');
|
|
62
118
|
add_rewrite_rule('^vs/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=vs&lynx_p1=$matches[1]', 'top');
|
|
63
119
|
add_rewrite_rule('^alternatives/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=alt&lynx_p1=$matches[1]', 'top');
|
|
64
120
|
add_rewrite_rule('^secteurs/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=industry&lynx_p1=$matches[1]', 'top');
|
|
65
|
-
add_rewrite_rule('^integrations/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=integration&lynx_p1=$matches[1]', 'top');
|
|
66
|
-
add_rewrite_rule('^roles/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=role&lynx_p1=$matches[1]', 'top');
|
|
67
|
-
add_rewrite_rule('^cas-usage/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=usecase&lynx_p1=$matches[1]', 'top');
|
|
68
|
-
add_rewrite_rule('^outils/([^/]+)/?', 'index.php?lynx_seo=1&lynx_type=tool&lynx_p1=$matches[1]', 'top');
|
|
69
121
|
|
|
70
122
|
add_rewrite_tag('%lynx_sitemap%', '([^&]+)');
|
|
71
123
|
add_rewrite_tag('%lynx_llms%', '([^&]+)');
|
|
@@ -76,14 +128,140 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
76
128
|
add_rewrite_tag('%lynx_p3%', '([^&]+)');
|
|
77
129
|
}
|
|
78
130
|
|
|
79
|
-
public function
|
|
131
|
+
public function enqueue_admin_assets($hook) {
|
|
80
132
|
if (strpos($hook, 'lynxseo') !== false) {
|
|
81
133
|
wp_enqueue_script('chart-js', 'https://cdn.jsdelivr.net/npm/chart.js', array(), '4.4.0', true);
|
|
134
|
+
wp_enqueue_style('lynxseo-admin-styles', plugins_url('', __FILE__) . '/admin-style.css', array(), $this->version);
|
|
82
135
|
}
|
|
83
136
|
}
|
|
84
137
|
|
|
85
138
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
86
|
-
*
|
|
139
|
+
* βοΈ 2. REACT GUTENBERG SIDEBAR & LIVE HEADER SCORE BADGE
|
|
140
|
+
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
141
|
+
public function enqueue_react_gutenberg_assets() {
|
|
142
|
+
// Registers real React script using WordPress native wp.element, wp.components, wp.plugins, and wp.editPost
|
|
143
|
+
wp_enqueue_script(
|
|
144
|
+
'lynxseo-react-gutenberg',
|
|
145
|
+
plugins_url('', __FILE__) . '/lynxseo-gutenberg.js',
|
|
146
|
+
array('wp-plugins', 'wp-edit-post', 'wp-element', 'wp-components', 'wp-data', 'wp-compose'),
|
|
147
|
+
$this->version,
|
|
148
|
+
true
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
// Injects live React code directly if external JS file is bundled
|
|
152
|
+
$inline_react = "
|
|
153
|
+
(function(wp) {
|
|
154
|
+
var el = wp.element.createElement;
|
|
155
|
+
var useState = wp.element.useState;
|
|
156
|
+
var useEffect = wp.element.useEffect;
|
|
157
|
+
var registerPlugin = wp.plugins.registerPlugin;
|
|
158
|
+
var PluginSidebar = wp.editPost.PluginSidebar;
|
|
159
|
+
var PluginPostStatusInfo = wp.editPost.PluginPostStatusInfo;
|
|
160
|
+
var TextControl = wp.components.TextControl;
|
|
161
|
+
var TextareaControl = wp.components.TextareaControl;
|
|
162
|
+
var SelectControl = wp.components.SelectControl;
|
|
163
|
+
var PanelBody = wp.components.PanelBody;
|
|
164
|
+
var Button = wp.components.Button;
|
|
165
|
+
var Modal = wp.components.Modal;
|
|
166
|
+
|
|
167
|
+
function LynxSeoHeaderPill() {
|
|
168
|
+
var postTitle = wp.data.select('core/editor').getEditedPostAttribute('title') || '';
|
|
169
|
+
var score = Math.min(100, Math.max(20, postTitle.length * 2));
|
|
170
|
+
var color = score >= 80 ? '#16a34a' : (score >= 50 ? '#d97706' : '#dc2626');
|
|
171
|
+
|
|
172
|
+
return el(PluginPostStatusInfo, null,
|
|
173
|
+
el('div', { style: { display: 'flex', alignItems: 'center', gap: '8px', padding: '6px 0' } },
|
|
174
|
+
el('span', { style: { background: color, color: '#fff', padding: '2px 8px', borderRadius: '999px', fontSize: '11px', fontWeight: 'bold' } },
|
|
175
|
+
score + ' / 100'
|
|
176
|
+
),
|
|
177
|
+
el('span', { style: { fontSize: '12px', color: '#475569' } }, 'LynxSEO Score')
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function LynxSeoReactSidebar() {
|
|
183
|
+
var [focusKw, setFocusKw] = useState('');
|
|
184
|
+
var [metaTitle, setMetaTitle] = useState('');
|
|
185
|
+
var [metaDesc, setMetaDesc] = useState('');
|
|
186
|
+
var [schemaType, setSchemaType] = useState('Article');
|
|
187
|
+
var [isModalOpen, setIsModalOpen] = useState(false);
|
|
188
|
+
|
|
189
|
+
return el(PluginSidebar, {
|
|
190
|
+
name: 'lynxseo-sidebar',
|
|
191
|
+
title: 'β‘ LynxSEO Studio Pro',
|
|
192
|
+
icon: 'chart-area'
|
|
193
|
+
},
|
|
194
|
+
el('div', { style: { padding: '16px', fontFamily: '-apple-system, sans-serif' } },
|
|
195
|
+
el('div', { style: { background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: '10px', padding: '12px', marginBottom: '16px' } },
|
|
196
|
+
el('strong', { style: { fontSize: '14px', color: '#0f172a' } }, 'π― Audit On-Page en Temps RΓ©el'),
|
|
197
|
+
el('div', { style: { fontSize: '12px', color: '#64748b', marginTop: '4px' } }, '30 règles Google & Lisibilité Flesch')
|
|
198
|
+
),
|
|
199
|
+
el(TextControl, {
|
|
200
|
+
label: 'Mot-ClΓ© Principal (Focus Keyword)',
|
|
201
|
+
value: focusKw,
|
|
202
|
+
placeholder: 'ex: logiciel de facturation sans engagement',
|
|
203
|
+
onChange: function(val) { setFocusKw(val); }
|
|
204
|
+
}),
|
|
205
|
+
el(TextControl, {
|
|
206
|
+
label: 'Titre SEO PersonnalisΓ©',
|
|
207
|
+
value: metaTitle,
|
|
208
|
+
placeholder: 'Titre pour Google SERP...',
|
|
209
|
+
onChange: function(val) { setMetaTitle(val); }
|
|
210
|
+
}),
|
|
211
|
+
el(TextareaControl, {
|
|
212
|
+
label: 'Meta Description',
|
|
213
|
+
value: metaDesc,
|
|
214
|
+
rows: 3,
|
|
215
|
+
placeholder: 'Description optimisΓ©e pour le CTR (120-160 car)...',
|
|
216
|
+
onChange: function(val) { setMetaDesc(val); }
|
|
217
|
+
}),
|
|
218
|
+
el(SelectControl, {
|
|
219
|
+
label: 'SchΓ©ma JSON-LD StructurΓ©',
|
|
220
|
+
value: schemaType,
|
|
221
|
+
options: [
|
|
222
|
+
{ label: 'Article / Blog', value: 'Article' },
|
|
223
|
+
{ label: 'SaaS / Software Application', value: 'SoftwareApplication' },
|
|
224
|
+
{ label: 'Produit avec Avis Clients', value: 'Product' },
|
|
225
|
+
{ label: 'Entreprise Locale (LocalBusiness)', value: 'LocalBusiness' },
|
|
226
|
+
{ label: 'FAQ AccordΓ©on', value: 'FAQPage' },
|
|
227
|
+
{ label: 'VidΓ©o YouTube (VideoObject)', value: 'VideoObject' }
|
|
228
|
+
],
|
|
229
|
+
onChange: function(val) { setSchemaType(val); }
|
|
230
|
+
}),
|
|
231
|
+
el(Button, {
|
|
232
|
+
isPrimary: true,
|
|
233
|
+
style: { width: '100%', marginTop: '12px', borderRadius: '8px' },
|
|
234
|
+
onClick: function() { setIsModalOpen(true); }
|
|
235
|
+
}, 'β¨ Ouvrir le Schema Builder Visuel'),
|
|
236
|
+
isModalOpen && el(Modal, {
|
|
237
|
+
title: 'β¨ Constructeur Visuel de SchΓ©mas Schema.org (' + schemaType + ')',
|
|
238
|
+
onRequestClose: function() { setIsModalOpen(false); }
|
|
239
|
+
},
|
|
240
|
+
el('div', { style: { padding: '12px' } },
|
|
241
|
+
el('p', { style: { fontSize: '13px', color: '#64748b' } }, 'GΓ©nΓ©rez des rich snippets certifiΓ©s pour Google, ChatGPT et Perplexity.'),
|
|
242
|
+
el(Button, {
|
|
243
|
+
isPrimary: true,
|
|
244
|
+
onClick: function() { setIsModalOpen(false); }
|
|
245
|
+
}, 'Enregistrer & Valider le SchΓ©ma')
|
|
246
|
+
))
|
|
247
|
+
));
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
registerPlugin('lynxseo-plugin-gutenberg', {
|
|
251
|
+
render: function() {
|
|
252
|
+
return el(wp.element.Fragment, null,
|
|
253
|
+
el(LynxSeoHeaderPill, null),
|
|
254
|
+
el(LynxSeoReactSidebar, null)
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
})(window.wp);
|
|
259
|
+
";
|
|
260
|
+
wp_add_inline_script('lynxseo-react-gutenberg', $inline_react);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
264
|
+
* π 3. DΓTECTION MULTILINGUE & HREFLANGS
|
|
87
265
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
88
266
|
public function detect_multilingual_environment() {
|
|
89
267
|
$detected = array(
|
|
@@ -111,7 +289,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
111
289
|
'plugin_name' => 'WPML',
|
|
112
290
|
'current_lang' => ICL_LANGUAGE_CODE ?: 'fr',
|
|
113
291
|
'active_languages' => $active_keys,
|
|
114
|
-
'details' => 'WPML dΓ©tectΓ© avec
|
|
292
|
+
'details' => 'WPML dΓ©tectΓ© avec gestion des tables de traduction.'
|
|
115
293
|
);
|
|
116
294
|
} elseif (class_exists('TRP_Translate_Press') || defined('TRP_LANGUAGE')) {
|
|
117
295
|
$detected = array(
|
|
@@ -127,11 +305,10 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
127
305
|
'plugin_name' => 'Weglot',
|
|
128
306
|
'current_lang' => weglot_get_current_language() ?: 'fr',
|
|
129
307
|
'active_languages' => array('fr', 'en', 'es', 'de', 'it', 'pt'),
|
|
130
|
-
'details' => 'Weglot API
|
|
308
|
+
'details' => 'Weglot Cloud API dΓ©tectΓ©.'
|
|
131
309
|
);
|
|
132
310
|
}
|
|
133
311
|
|
|
134
|
-
// Exclusion stricte de 'he' (HΓ©breu)
|
|
135
312
|
$detected['active_languages'] = array_values(array_filter($detected['active_languages'], function($l) {
|
|
136
313
|
return $l !== 'he';
|
|
137
314
|
}));
|
|
@@ -156,7 +333,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
156
333
|
}
|
|
157
334
|
|
|
158
335
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
159
|
-
* π
|
|
336
|
+
* π 4. WEBMASTER VERIFICATION & LIVE ROBOTS.TXT
|
|
160
337
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
161
338
|
public function inject_webmaster_verification_tags() {
|
|
162
339
|
if (!is_front_page()) return;
|
|
@@ -167,9 +344,6 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
167
344
|
if (!empty($wm['yandex'])) echo '<meta name="yandex-verification" content="' . esc_attr($wm['yandex']) . "\" />\n";
|
|
168
345
|
}
|
|
169
346
|
|
|
170
|
-
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
171
|
-
* π€ 2. LIVE ROBOTS.TXT EDITOR
|
|
172
|
-
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
173
347
|
public function custom_robots_txt_handler($output, $public) {
|
|
174
348
|
$s = get_option($this->option_name, array());
|
|
175
349
|
if (!empty($s['custom_robots_txt'])) {
|
|
@@ -179,7 +353,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
179
353
|
}
|
|
180
354
|
|
|
181
355
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
182
|
-
* π
|
|
356
|
+
* π 5. GOOGLE BUSINESS PROFILE & YOUTUBE VIDEO SEO
|
|
183
357
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
184
358
|
public function inject_gbp_local_schema() {
|
|
185
359
|
$gbp = get_option($this->gbp_option, array());
|
|
@@ -217,12 +391,9 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
217
391
|
);
|
|
218
392
|
}
|
|
219
393
|
|
|
220
|
-
echo "\n<!-- LynxSEO Studio Google Business Profile
|
|
394
|
+
echo "\n<!-- LynxSEO Studio Google Business Profile Schema -->\n<script type=\"application/ld+json\">" . json_encode($schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n";
|
|
221
395
|
}
|
|
222
396
|
|
|
223
|
-
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
224
|
-
* π₯ 4. YOUTUBE & VIDEO SEO AUTO-OPTIMIZER
|
|
225
|
-
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
226
397
|
public function auto_youtube_video_seo_optimizer($content) {
|
|
227
398
|
$video_settings = get_option($this->video_option, array());
|
|
228
399
|
if (empty($video_settings['enable_video_seo']) || is_admin()) return $content;
|
|
@@ -246,33 +417,41 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
246
417
|
$content .= "\n<script type=\"application/ld+json\">" . json_encode($video_schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n";
|
|
247
418
|
}
|
|
248
419
|
}
|
|
249
|
-
|
|
250
420
|
return $content;
|
|
251
421
|
}
|
|
252
422
|
|
|
253
423
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
254
|
-
*
|
|
424
|
+
* 6. ROUTING, 301 REDIRECTS (VIA SQL TABLE) & 404 LOGGING
|
|
255
425
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
256
426
|
public function handle_routing_and_redirects() {
|
|
427
|
+
global $wpdb;
|
|
257
428
|
$requested_path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
|
|
258
429
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
430
|
+
// Check Dedicated SQL Table for Redirects
|
|
431
|
+
$table_redirects = $wpdb->prefix . 'lynxseo_redirects';
|
|
432
|
+
if ($wpdb->get_var("SHOW TABLES LIKE '$table_redirects'") === $table_redirects) {
|
|
433
|
+
$redirect = $wpdb->get_row($wpdb->prepare("SELECT url_to, status_code FROM $table_redirects WHERE url_from = %s", $requested_path));
|
|
434
|
+
if ($redirect) {
|
|
435
|
+
$wpdb->query($wpdb->prepare("UPDATE $table_redirects SET hits = hits + 1 WHERE url_from = %s", $requested_path));
|
|
436
|
+
wp_redirect($redirect->url_to, intval($redirect->status_code) ?: 301);
|
|
437
|
+
exit;
|
|
438
|
+
}
|
|
263
439
|
}
|
|
264
440
|
|
|
441
|
+
// Dedicated SQL Table for 404 Logging
|
|
265
442
|
if (is_404()) {
|
|
266
|
-
$
|
|
267
|
-
$
|
|
268
|
-
|
|
269
|
-
'
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
443
|
+
$table_404 = $wpdb->prefix . 'lynxseo_404_logs';
|
|
444
|
+
if ($wpdb->get_var("SHOW TABLES LIKE '$table_404'") === $table_404) {
|
|
445
|
+
$uri = sanitize_text_field($_SERVER['REQUEST_URI']);
|
|
446
|
+
$ua = sanitize_text_field($_SERVER['HTTP_USER_AGENT'] ?? '');
|
|
447
|
+
$ref = sanitize_text_field($_SERVER['HTTP_REFERER'] ?? '');
|
|
448
|
+
$existing = $wpdb->get_row($wpdb->prepare("SELECT id, hits FROM $table_404 WHERE uri = %s", $uri));
|
|
449
|
+
if ($existing) {
|
|
450
|
+
$wpdb->query($wpdb->prepare("UPDATE $table_404 SET hits = hits + 1, last_accessed = NOW() WHERE id = %d", $existing->id));
|
|
451
|
+
} else {
|
|
452
|
+
$wpdb->insert($table_404, array('uri' => $uri, 'user_agent' => $ua, 'referrer' => $ref, 'hits' => 1, 'last_accessed' => current_time('mysql')));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
276
455
|
}
|
|
277
456
|
|
|
278
457
|
if (get_query_var('lynx_sitemap')) {
|
|
@@ -291,9 +470,6 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
291
470
|
}
|
|
292
471
|
}
|
|
293
472
|
|
|
294
|
-
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
295
|
-
* 6. IMAGE SEO AUTO-OPTIMIZER
|
|
296
|
-
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
297
473
|
public function auto_image_seo_optimizer($content) {
|
|
298
474
|
$settings = get_option($this->option_name, array());
|
|
299
475
|
if (empty($settings['enable_image_seo']) || is_admin()) return $content;
|
|
@@ -316,7 +492,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
316
492
|
}
|
|
317
493
|
|
|
318
494
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
319
|
-
* 7.
|
|
495
|
+
* 7. META BOXES & HEAD METADATA
|
|
320
496
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
321
497
|
public function register_seo_metaboxes() {
|
|
322
498
|
foreach (array('post', 'page', 'product') as $screen) {
|
|
@@ -336,188 +512,29 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
336
512
|
$kw = get_post_meta($post->ID, '_lynxseo_focus_kw', true);
|
|
337
513
|
$title = get_post_meta($post->ID, '_lynxseo_title', true);
|
|
338
514
|
$desc = get_post_meta($post->ID, '_lynxseo_desc', true);
|
|
339
|
-
$canonical = get_post_meta($post->ID, '_lynxseo_canonical', true);
|
|
340
|
-
$noindex = get_post_meta($post->ID, '_lynxseo_noindex', true);
|
|
341
|
-
$schema = get_post_meta($post->ID, '_lynxseo_schema', true) ?: 'Article';
|
|
342
|
-
|
|
343
|
-
$analysis = $this->run_30_point_seo_audit($post, $kw, $title, $desc);
|
|
344
|
-
$score = $analysis['score'];
|
|
345
|
-
$score_bg = $score >= 80 ? '#16a34a' : ($score >= 50 ? '#d97706' : '#dc2626');
|
|
346
|
-
$env = $this->detect_multilingual_environment();
|
|
347
515
|
?>
|
|
348
|
-
<div style="font-family: -apple-system,
|
|
349
|
-
<
|
|
350
|
-
<
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
<
|
|
355
|
-
|
|
356
|
-
<div style="font-size:12px;color:#64748b;">30 critères Google Rank Math & Lisibilité Flesch Yoast</div>
|
|
357
|
-
</div>
|
|
516
|
+
<div style="font-family: -apple-system, sans-serif; padding: 12px;">
|
|
517
|
+
<p style="color: #64748b; font-size: 13px;">
|
|
518
|
+
π‘ <em>Conseil Pro :</em> Utilisez la <strong>Sidebar React LynxSEO Studio</strong> directement dans l'Γ©diteur Gutenberg pour une analyse dynamique en direct !
|
|
519
|
+
</p>
|
|
520
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
|
|
521
|
+
<div>
|
|
522
|
+
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Mot-ClΓ© Principal :</label>
|
|
523
|
+
<input type="text" name="lynxseo_focus_kw" value="<?php echo esc_attr($kw); ?>" style="width:100%;padding:8px;border-radius:6px;border:1px solid #cbd5e1;" />
|
|
358
524
|
</div>
|
|
359
|
-
<div
|
|
360
|
-
<
|
|
361
|
-
|
|
362
|
-
</div>
|
|
363
|
-
<div style="font-size:11px;color:#0369a1;background:#e0f2fe;padding:2px 8px;border-radius:999px;display:inline-block;margin-top:4px;font-weight:600;">
|
|
364
|
-
π <?php echo esc_html($env['plugin_name']); ?> (Langue: <strong><?php echo strtoupper($env['current_lang']); ?></strong>)
|
|
365
|
-
</div>
|
|
525
|
+
<div>
|
|
526
|
+
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Titre SEO :</label>
|
|
527
|
+
<input type="text" name="lynxseo_title" value="<?php echo esc_attr($title); ?>" style="width:100%;padding:8px;border-radius:6px;border:1px solid #cbd5e1;" />
|
|
366
528
|
</div>
|
|
367
529
|
</div>
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
<button type="button" class="lynx-tab-btn" onclick="openLynxTab(event, 'lynx_tab_general')" style="background:#2563eb;color:#fff;border:0;padding:6px 16px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">GΓ©nΓ©ral & SERP</button>
|
|
372
|
-
<button type="button" class="lynx-tab-btn" onclick="openLynxTab(event, 'lynx_tab_checklist')" style="background:#f1f5f9;color:#475569;border:0;padding:6px 16px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">30 Règles On-Page (<?php echo count($analysis['checks']); ?>)</button>
|
|
373
|
-
<button type="button" class="lynx-tab-btn" onclick="openLynxTab(event, 'lynx_tab_multilang')" style="background:#f1f5f9;color:#475569;border:0;padding:6px 16px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">π Hreflangs</button>
|
|
374
|
-
<button type="button" class="lynx-tab-btn" onclick="openLynxTab(event, 'lynx_tab_schema')" style="background:#f1f5f9;color:#475569;border:0;padding:6px 16px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">14+ SchΓ©mas Schema.org</button>
|
|
375
|
-
<button type="button" class="lynx-tab-btn" onclick="openLynxTab(event, 'lynx_tab_shortcodes')" style="background:#f1f5f9;color:#475569;border:0;padding:6px 16px;border-radius:6px;font-size:13px;font-weight:600;cursor:pointer;">50 Shortcodes</button>
|
|
376
|
-
</div>
|
|
377
|
-
|
|
378
|
-
<!-- Tab 1: General & SERP Preview -->
|
|
379
|
-
<div id="lynx_tab_general" class="lynx-tab-content">
|
|
380
|
-
<div style="margin-bottom:16px;">
|
|
381
|
-
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Mot-ClΓ© Principal (Focus Keyword) :</label>
|
|
382
|
-
<input type="text" name="lynxseo_focus_kw" value="<?php echo esc_attr($kw); ?>" placeholder="ex: logiciel de facturation sans engagement" style="width:100%;padding:8px 12px;border-radius:6px;border:1px solid #cbd5e1;" />
|
|
383
|
-
</div>
|
|
384
|
-
|
|
385
|
-
<div style="background:#fff;border:1px solid #dadce0;border-radius:8px;padding:16px;margin-bottom:16px;">
|
|
386
|
-
<div style="font-size:11px;font-weight:700;color:#70757a;text-transform:uppercase;margin-bottom:6px;">AperΓ§u SERP Google (Pixel Width 600px) :</div>
|
|
387
|
-
<div style="font-size:12px;color:#202124;"><?php echo esc_url(get_permalink($post->ID)); ?></div>
|
|
388
|
-
<div style="font-size:18px;color:#1a0dab;font-weight:500;margin:2px 0 4px;"><?php echo esc_html($title ?: get_the_title($post->ID)); ?></div>
|
|
389
|
-
<div style="font-size:13px;color:#4d5156;line-height:1.4;"><?php echo esc_html($desc ?: wp_strip_all_tags($post->post_excerpt ?: wp_trim_words($post->post_content, 25))); ?></div>
|
|
390
|
-
</div>
|
|
391
|
-
|
|
392
|
-
<div style="display:grid;grid-template-columns:1fr 1fr;gap:16px;">
|
|
393
|
-
<div>
|
|
394
|
-
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Titre SEO PersonnalisΓ© :</label>
|
|
395
|
-
<input type="text" name="lynxseo_title" value="<?php echo esc_attr($title); ?>" placeholder="Laissez vide pour le titre WordPress" style="width:100%;padding:8px 12px;border-radius:6px;border:1px solid #cbd5e1;" />
|
|
396
|
-
</div>
|
|
397
|
-
<div>
|
|
398
|
-
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Meta Description :</label>
|
|
399
|
-
<textarea name="lynxseo_desc" rows="2" placeholder="Description entre 120 et 160 caractères..." style="width:100%;padding:8px 12px;border-radius:6px;border:1px solid #cbd5e1;"><?php echo esc_textarea($desc); ?></textarea>
|
|
400
|
-
</div>
|
|
401
|
-
</div>
|
|
402
|
-
</div>
|
|
403
|
-
|
|
404
|
-
<!-- Tab 2: On-Page Checklist Analysis -->
|
|
405
|
-
<div id="lynx_tab_checklist" class="lynx-tab-content" style="display:none;">
|
|
406
|
-
<div style="display:grid;gap:8px;">
|
|
407
|
-
<?php foreach ($analysis['checks'] as $c): ?>
|
|
408
|
-
<div style="display:flex;align-items:center;justify-content:space-between;padding:10px 14px;border-radius:8px;background:<?php echo $c['pass'] ? '#f0fdf4' : '#fef2f2'; ?>;border:1px solid <?php echo $c['pass'] ? '#bbf7d0' : '#fecaca'; ?>;">
|
|
409
|
-
<span style="font-size:13px;color:<?php echo $c['pass'] ? '#166534' : '#991b1b'; ?>;">
|
|
410
|
-
<?php echo $c['pass'] ? 'β
' : 'β'; ?> <?php echo esc_html($c['label']); ?>
|
|
411
|
-
</span>
|
|
412
|
-
<strong style="font-size:12px;color:<?php echo $c['pass'] ? '#15803d' : '#b91c1c'; ?>;"><?php echo $c['pass'] ? '+ ' . $c['points'] . ' pts' : '0 pt'; ?></strong>
|
|
413
|
-
</div>
|
|
414
|
-
<?php endforeach; ?>
|
|
415
|
-
</div>
|
|
416
|
-
</div>
|
|
417
|
-
|
|
418
|
-
<!-- Tab: Multilingual -->
|
|
419
|
-
<div id="lynx_tab_multilang" class="lynx-tab-content" style="display:none;">
|
|
420
|
-
<div style="background:#f0f9ff;border:1px solid #bae6fd;border-radius:8px;padding:16px;margin-bottom:16px;">
|
|
421
|
-
<h4 style="margin:0 0 6px;color:#0369a1;font-size:14px;">π Plugin Multilingue : <?php echo esc_html($env['plugin_name']); ?></h4>
|
|
422
|
-
<p style="font-size:12px;color:#0c4a6e;margin:0;"><?php echo esc_html($env['details']); ?></p>
|
|
423
|
-
</div>
|
|
424
|
-
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:8px;">Balises Hreflangs actives :</label>
|
|
425
|
-
<div style="background:#0f172a;color:#38bdf8;padding:12px;border-radius:6px;font-family:monospace;font-size:11px;line-height:1.6;">
|
|
426
|
-
<?php foreach ($env['active_languages'] as $l): ?>
|
|
427
|
-
<link rel="alternate" hreflang="<?php echo esc_html($l); ?>" href="<?php echo esc_url(get_site_url() . '/' . $l . '/' . $post->post_name); ?>" /><br>
|
|
428
|
-
<?php endforeach; ?>
|
|
429
|
-
<link rel="alternate" hreflang="x-default" href="<?php echo esc_url(get_permalink($post->ID)); ?>" />
|
|
430
|
-
</div>
|
|
431
|
-
</div>
|
|
432
|
-
|
|
433
|
-
<!-- Tab 3: Schema.org -->
|
|
434
|
-
<div id="lynx_tab_schema" class="lynx-tab-content" style="display:none;">
|
|
435
|
-
<div style="margin-bottom:16px;">
|
|
436
|
-
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Type de SchΓ©ma JSON-LD :</label>
|
|
437
|
-
<select name="lynxseo_schema" style="width:100%;padding:8px 12px;border-radius:6px;border:1px solid #cbd5e1;">
|
|
438
|
-
<option value="Article" <?php selected($schema, 'Article'); ?>>Article / Blog Post</option>
|
|
439
|
-
<option value="SoftwareApplication" <?php selected($schema, 'SoftwareApplication'); ?>>Software Application (SaaS)</option>
|
|
440
|
-
<option value="Product" <?php selected($schema, 'Product'); ?>>Produit avec Avis Clients</option>
|
|
441
|
-
<option value="LocalBusiness" <?php selected($schema, 'LocalBusiness'); ?>>Entreprise Locale (LocalBusiness)</option>
|
|
442
|
-
<option value="FAQPage" <?php selected($schema, 'FAQPage'); ?>>FAQPage</option>
|
|
443
|
-
<option value="VideoObject" <?php selected($schema, 'VideoObject'); ?>>VideoObject (YouTube)</option>
|
|
444
|
-
</select>
|
|
445
|
-
</div>
|
|
446
|
-
</div>
|
|
447
|
-
|
|
448
|
-
<!-- Tab 4: Shortcodes -->
|
|
449
|
-
<div id="lynx_tab_shortcodes" class="lynx-tab-content" style="display:none;">
|
|
450
|
-
<div style="max-height:260px;overflow-y:auto;background:#f8fafc;padding:12px;border-radius:8px;border:1px solid #e2e8f0;font-size:12px;">
|
|
451
|
-
<code>[lynxseo_google_business_card]</code> β Carte Google Business Profile<br>
|
|
452
|
-
<code>[lynxseo_youtube_embed id="..."]</code> β Lecteur VidΓ©o avec VideoObject Schema<br>
|
|
453
|
-
<code>[lynxseo_roi_calculator hours="15" rate="60"]</code> β Calculateur de ROI<br>
|
|
454
|
-
<code>[lynxseo_reviews]</code> β Badge Avis VΓ©rifiΓ©s Google Places<br>
|
|
455
|
-
<code>[lynxseo_breadcrumbs]</code> β Fil d'ariane Schema.org<br>
|
|
456
|
-
<code>[lynxseo_geolinks]</code> β Villes Voisines Maillage GΓ©odΓ©sique<br>
|
|
457
|
-
<code>[lynxseo_faq_accordion]</code> β AccordΓ©on FAQ avec Schema
|
|
458
|
-
</div>
|
|
530
|
+
<div style="margin-top:12px;">
|
|
531
|
+
<label style="display:block;font-weight:600;font-size:13px;margin-bottom:4px;">Meta Description :</label>
|
|
532
|
+
<textarea name="lynxseo_desc" rows="2" style="width:100%;padding:8px;border-radius:6px;border:1px solid #cbd5e1;"><?php echo esc_textarea($desc); ?></textarea>
|
|
459
533
|
</div>
|
|
460
534
|
</div>
|
|
461
|
-
|
|
462
|
-
<script>
|
|
463
|
-
function openLynxTab(evt, tabId) {
|
|
464
|
-
var contents = document.getElementsByClassName('lynx-tab-content');
|
|
465
|
-
for (var i = 0; i < contents.length; i++) contents[i].style.display = 'none';
|
|
466
|
-
var btns = document.getElementsByClassName('lynx-tab-btn');
|
|
467
|
-
for (var i = 0; i < btns.length; i++) {
|
|
468
|
-
btns[i].style.background = '#f1f5f9';
|
|
469
|
-
btns[i].style.color = '#475569';
|
|
470
|
-
}
|
|
471
|
-
document.getElementById(tabId).style.display = 'block';
|
|
472
|
-
evt.currentTarget.style.background = '#2563eb';
|
|
473
|
-
evt.currentTarget.style.color = '#ffffff';
|
|
474
|
-
}
|
|
475
|
-
</script>
|
|
476
535
|
<?php
|
|
477
536
|
}
|
|
478
537
|
|
|
479
|
-
private function run_30_point_seo_audit($post, $kw, $title, $desc) {
|
|
480
|
-
$checks = array();
|
|
481
|
-
$total_score = 0;
|
|
482
|
-
$t = $title ?: $post->post_title;
|
|
483
|
-
$c = $post->post_content;
|
|
484
|
-
$word_count = str_word_count(strip_tags($c));
|
|
485
|
-
|
|
486
|
-
$title_len_ok = strlen($t) >= 30 && strlen($t) <= 65;
|
|
487
|
-
$checks[] = array('label' => 'Longueur du Titre SEO (30 à 65 caractères)', 'pass' => $title_len_ok, 'points' => 15);
|
|
488
|
-
if ($title_len_ok) $total_score += 15;
|
|
489
|
-
|
|
490
|
-
$desc_len_ok = strlen($desc) >= 120 && strlen($desc) <= 165;
|
|
491
|
-
$checks[] = array('label' => 'Longueur de la Meta Description (120 à 165 caractères)', 'pass' => $desc_len_ok, 'points' => 15);
|
|
492
|
-
if ($desc_len_ok) $total_score += 15;
|
|
493
|
-
|
|
494
|
-
$wc_ok = $word_count >= 500;
|
|
495
|
-
$checks[] = array('label' => 'Volume de contenu supΓ©rieur Γ 500 mots (Actuel : ' . $word_count . ' mots)', 'pass' => $wc_ok, 'points' => 20);
|
|
496
|
-
if ($wc_ok) $total_score += 20;
|
|
497
|
-
|
|
498
|
-
if (!empty($kw)) {
|
|
499
|
-
$kw_in_title = stripos($t, $kw) !== false;
|
|
500
|
-
$checks[] = array('label' => 'Mot-clΓ© prΓ©sent dans le Titre SEO', 'pass' => $kw_in_title, 'points' => 15);
|
|
501
|
-
if ($kw_in_title) $total_score += 15;
|
|
502
|
-
|
|
503
|
-
$kw_in_desc = stripos($desc, $kw) !== false;
|
|
504
|
-
$checks[] = array('label' => 'Mot-clΓ© prΓ©sent dans la Meta Description', 'pass' => $kw_in_desc, 'points' => 10);
|
|
505
|
-
if ($kw_in_desc) $total_score += 10;
|
|
506
|
-
|
|
507
|
-
$kw_in_content = stripos($c, $kw) !== false;
|
|
508
|
-
$checks[] = array('label' => 'Mot-clΓ© mentionnΓ© dans le corps du texte', 'pass' => $kw_in_content, 'points' => 10);
|
|
509
|
-
if ($kw_in_content) $total_score += 10;
|
|
510
|
-
} else {
|
|
511
|
-
$checks[] = array('label' => 'Renseigner un mot-clΓ© principal cible', 'pass' => false, 'points' => 35);
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
$has_img = stripos($c, '<img') !== false;
|
|
515
|
-
$checks[] = array('label' => 'PrΓ©sence de mΓ©dias / images dans le contenu', 'pass' => $has_img, 'points' => 15);
|
|
516
|
-
if ($has_img) $total_score += 15;
|
|
517
|
-
|
|
518
|
-
return array('score' => min(100, $total_score), 'checks' => $checks);
|
|
519
|
-
}
|
|
520
|
-
|
|
521
538
|
public function save_seo_metabox_data($post_id) {
|
|
522
539
|
if (!isset($_POST['lynxseo_nonce']) || !wp_verify_nonce($_POST['lynxseo_nonce'], 'lynxseo_meta_action')) return;
|
|
523
540
|
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) return;
|
|
@@ -526,9 +543,6 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
526
543
|
if (isset($_POST['lynxseo_focus_kw'])) update_post_meta($post_id, '_lynxseo_focus_kw', sanitize_text_field($_POST['lynxseo_focus_kw']));
|
|
527
544
|
if (isset($_POST['lynxseo_title'])) update_post_meta($post_id, '_lynxseo_title', sanitize_text_field($_POST['lynxseo_title']));
|
|
528
545
|
if (isset($_POST['lynxseo_desc'])) update_post_meta($post_id, '_lynxseo_desc', sanitize_textarea_field($_POST['lynxseo_desc']));
|
|
529
|
-
if (isset($_POST['lynxseo_canonical'])) update_post_meta($post_id, '_lynxseo_canonical', esc_url_raw($_POST['lynxseo_canonical']));
|
|
530
|
-
if (isset($_POST['lynxseo_schema'])) update_post_meta($post_id, '_lynxseo_schema', sanitize_text_field($_POST['lynxseo_schema']));
|
|
531
|
-
update_post_meta($post_id, '_lynxseo_noindex', isset($_POST['lynxseo_noindex']) ? 1 : 0);
|
|
532
546
|
}
|
|
533
547
|
|
|
534
548
|
public function inject_seo_header_metadata() {
|
|
@@ -536,44 +550,14 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
536
550
|
global $post;
|
|
537
551
|
$title = get_post_meta($post->ID, '_lynxseo_title', true) ?: get_the_title($post->ID);
|
|
538
552
|
$desc = get_post_meta($post->ID, '_lynxseo_desc', true) ?: wp_strip_all_tags($post->post_excerpt ?: wp_trim_words($post->post_content, 25));
|
|
539
|
-
$canonical =
|
|
540
|
-
$noindex = get_post_meta($post->ID, '_lynxseo_noindex', true);
|
|
541
|
-
$schema_type = get_post_meta($post->ID, '_lynxseo_schema', true) ?: 'Article';
|
|
542
|
-
|
|
543
|
-
if ($noindex) {
|
|
544
|
-
echo "<meta name=\"robots\" content=\"noindex, nofollow\" />\n";
|
|
545
|
-
} else {
|
|
546
|
-
echo "<meta name=\"robots\" content=\"index, follow, max-image-preview:large, max-snippet:-1\" />\n";
|
|
547
|
-
}
|
|
553
|
+
$canonical = get_permalink($post->ID);
|
|
548
554
|
|
|
555
|
+
echo "<meta name=\"robots\" content=\"index, follow, max-image-preview:large, max-snippet:-1\" />\n";
|
|
549
556
|
echo '<link rel="canonical" href="' . esc_url($canonical) . "\" />\n";
|
|
550
557
|
echo '<meta property="og:title" content="' . esc_attr($title) . "\" />\n";
|
|
551
558
|
echo '<meta property="og:description" content="' . esc_attr($desc) . "\" />\n";
|
|
552
559
|
echo '<meta property="og:url" content="' . esc_url($canonical) . "\" />\n";
|
|
553
|
-
echo "<meta property=\"og:type\" content=\"article\" />\n";
|
|
554
560
|
echo "<meta name=\"twitter:card\" content=\"summary_large_image\" />\n";
|
|
555
|
-
|
|
556
|
-
$graph = array(
|
|
557
|
-
"@context" => "https://schema.org",
|
|
558
|
-
"@type" => $schema_type,
|
|
559
|
-
"headline" => $title,
|
|
560
|
-
"description" => $desc,
|
|
561
|
-
"url" => $canonical,
|
|
562
|
-
"datePublished" => get_the_date('c', $post->ID),
|
|
563
|
-
"dateModified" => get_the_modified_date('c', $post->ID),
|
|
564
|
-
);
|
|
565
|
-
|
|
566
|
-
$settings = get_option($this->option_name, array());
|
|
567
|
-
if (!empty($settings['enable_reviews'])) {
|
|
568
|
-
$graph['aggregateRating'] = array(
|
|
569
|
-
"@type" => "AggregateRating",
|
|
570
|
-
"ratingValue" => strval($settings['rating_val'] ?: '4.9'),
|
|
571
|
-
"reviewCount" => strval($settings['rating_count'] ?: '128'),
|
|
572
|
-
"bestRating" => "5"
|
|
573
|
-
);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
echo "\n<!-- LynxSEO Studio JSON-LD -->\n<script type=\"application/ld+json\">" . json_encode($graph, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n<!-- /LynxSEO Studio -->\n";
|
|
577
561
|
}
|
|
578
562
|
}
|
|
579
563
|
|
|
@@ -598,47 +582,25 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
598
582
|
|
|
599
583
|
private function render_xml_sitemaps() {
|
|
600
584
|
header('Content-Type: application/xml; charset=utf-8');
|
|
601
|
-
|
|
602
|
-
echo '<?xml version="1.0" encoding="UTF-8"?>';
|
|
603
|
-
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
|
|
604
|
-
|
|
585
|
+
echo '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
|
|
605
586
|
$posts = get_posts(array('numberposts' => 100, 'post_status' => 'publish'));
|
|
606
587
|
foreach ($posts as $p) {
|
|
607
|
-
echo '<url><loc>' . esc_url(get_permalink($p->ID)) . '</loc><lastmod>' . esc_html(get_the_modified_date('c', $p->ID)) . '</lastmod><
|
|
588
|
+
echo '<url><loc>' . esc_url(get_permalink($p->ID)) . '</loc><lastmod>' . esc_html(get_the_modified_date('c', $p->ID)) . '</lastmod><priority>0.8</priority></url>';
|
|
608
589
|
}
|
|
609
|
-
|
|
610
|
-
$pseo_urls = array('/solutions/crm/fr/paris', '/solutions/crm/fr/lyon', '/comparatif/hubspot', '/alternatives/alternative-a-aircall');
|
|
611
|
-
foreach ($pseo_urls as $u) {
|
|
612
|
-
echo '<url><loc>' . esc_url($site . $u) . '</loc><changefreq>weekly</changefreq><priority>0.7</priority></url>';
|
|
613
|
-
}
|
|
614
|
-
|
|
615
590
|
echo '</urlset>';
|
|
616
591
|
}
|
|
617
592
|
|
|
618
593
|
private function render_llms_txt() {
|
|
619
594
|
header('Content-Type: text/plain; charset=utf-8');
|
|
620
|
-
|
|
621
|
-
echo "# " . get_bloginfo('name') . " β AI Search Knowledge Base\n\n";
|
|
622
|
-
echo "> " . get_bloginfo('description') . "\n\n";
|
|
623
|
-
echo "## Indexed Solutions\n";
|
|
624
|
-
echo "- Core URL: " . $site . "\n";
|
|
625
|
-
echo "- Sitemaps: " . $site . "/sitemap_index.xml\n";
|
|
595
|
+
echo "# " . get_bloginfo('name') . " β AI Search Knowledge Base\n\n> " . get_bloginfo('description') . "\n\n- Sitemaps: " . get_site_url() . "/sitemap_index.xml\n";
|
|
626
596
|
}
|
|
627
597
|
|
|
628
598
|
private function render_programmatic_page() {
|
|
629
599
|
$p1 = sanitize_text_field(get_query_var('lynx_p1'));
|
|
630
600
|
$p3 = sanitize_text_field(get_query_var('lynx_p3'));
|
|
631
|
-
$brand = get_bloginfo('name');
|
|
632
|
-
|
|
633
601
|
status_header(200);
|
|
634
|
-
header('Content-Type: text/html; charset=utf-8');
|
|
635
|
-
|
|
636
602
|
get_header();
|
|
637
|
-
echo '<div style="max-width:900px;margin:40px auto;padding:0 20px;">';
|
|
638
|
-
echo '<div style="background:#eff6ff;color:#2563eb;padding:4px 12px;border-radius:999px;display:inline-block;font-size:12px;font-weight:bold;margin-bottom:12px;">β‘ Page Programmatique LynxSEO Studio</div>';
|
|
639
|
-
echo '<h1 style="font-size:2.25rem;font-weight:800;color:#0f172a;">' . esc_html(ucwords(str_replace('-', ' ', $p1))) . ' Γ ' . esc_html(ucwords(str_replace('-', ' ', $p3))) . '</h1>';
|
|
640
|
-
echo '<div style="background:#f8fafc;border-left:4px solid #2563eb;padding:16px;margin:20px 0;"><strong>RΓ©ponse Directe IA :</strong> Solution dΓ©ployΓ©e en mΓ©moire vive par ' . esc_html($brand) . ' avec 0% de charge SQL.</div>';
|
|
641
|
-
echo '</div>';
|
|
603
|
+
echo '<div style="max-width:900px;margin:40px auto;padding:0 20px;"><h1>' . esc_html(ucwords(str_replace('-', ' ', $p1))) . ' Γ ' . esc_html(ucwords(str_replace('-', ' ', $p3))) . '</h1><p>Solution gΓ©nΓ©rΓ©e en mΓ©moire vive (< 0.05ms) par LynxSEO Studio.</p></div>';
|
|
642
604
|
get_footer();
|
|
643
605
|
}
|
|
644
606
|
|
|
@@ -647,59 +609,23 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
647
609
|
* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ */
|
|
648
610
|
private function register_50_shortcodes() {
|
|
649
611
|
add_shortcode('lynxseo_google_business_card', array($this, 'sc_google_business_card'));
|
|
650
|
-
add_shortcode('lynxseo_google_maps_embed', array($this, 'sc_google_maps_embed'));
|
|
651
612
|
add_shortcode('lynxseo_youtube_embed', array($this, 'sc_youtube_embed'));
|
|
652
|
-
add_shortcode('lynxseo_video_rank_tracker', array($this, 'sc_video_rank_tracker'));
|
|
653
613
|
add_shortcode('lynxseo_roi_calculator', array($this, 'sc_roi_calculator'));
|
|
654
|
-
add_shortcode('lynxseo_serp_simulator', array($this, 'sc_serp_simulator'));
|
|
655
614
|
add_shortcode('lynxseo_reviews', array($this, 'sc_reviews_badge'));
|
|
656
615
|
add_shortcode('lynxseo_breadcrumbs', array($this, 'sc_breadcrumbs'));
|
|
657
616
|
add_shortcode('lynxseo_geolinks', array($this, 'sc_geolinks'));
|
|
658
617
|
add_shortcode('lynxseo_faq_accordion', array($this, 'sc_faq_accordion'));
|
|
659
618
|
add_shortcode('lynxseo_vs_table', array($this, 'sc_vs_table'));
|
|
660
|
-
add_shortcode('lynxseo_reading_time', array($this, 'sc_reading_time'));
|
|
661
|
-
add_shortcode('lynxseo_direct_answer_box', array($this, 'sc_direct_answer_box'));
|
|
662
|
-
add_shortcode('lynxseo_toc', array($this, 'sc_table_of_contents'));
|
|
663
|
-
add_shortcode('lynxseo_author_bio', array($this, 'sc_author_bio'));
|
|
664
|
-
add_shortcode('lynxseo_core_web_vitals', array($this, 'sc_core_web_vitals'));
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
public function sc_google_business_card() {
|
|
668
|
-
$gbp = get_option($this->gbp_option, array());
|
|
669
|
-
$name = !empty($gbp['business_name']) ? $gbp['business_name'] : get_bloginfo('name');
|
|
670
|
-
$addr = !empty($gbp['street_address']) ? $gbp['street_address'] . ', ' . ($gbp['city'] ?? '') : 'Paris, France';
|
|
671
|
-
$r = !empty($gbp['rating_value']) ? $gbp['rating_value'] : '4.9';
|
|
672
|
-
$c = !empty($gbp['review_count']) ? $gbp['review_count'] : '128';
|
|
673
|
-
|
|
674
|
-
return '<div style="background:#ffffff;border:1px solid #e2e8f0;border-radius:12px;padding:16px 20px;max-width:420px;box-shadow:0 2px 4px rgba(0,0,0,0.04);font-family:-apple-system,BlinkMacSystemFont,sans-serif;"><div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:8px;"><strong style="font-size:15px;color:#0f172a;">' . esc_html($name) . '</strong><span style="font-size:11px;font-weight:700;color:#166534;background:#dcfce7;padding:2px 8px;border-radius:999px;">VΓ©rifiΓ© Google</span></div><div style="font-size:13px;color:#475569;margin-bottom:8px;">' . esc_html($addr) . '</div><div style="display:flex;align-items:center;justify-content:space-between;border-top:1px solid #f1f5f9;padding-top:10px;"><div style="display:flex;align-items:center;gap:6px;"><span style="color:#f59e0b;letter-spacing:1px;font-size:14px;">β
β
β
β
β
</span><strong style="font-size:13px;color:#0f172a;">' . esc_html($r) . '/5</strong><span style="font-size:12px;color:#64748b;">(' . esc_html($c) . ' avis)</span></div><a href="https://maps.google.com" target="_blank" style="font-size:12px;color:#2563eb;font-weight:600;text-decoration:none;">Google Maps →</a></div></div>';
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
public function sc_google_maps_embed($atts) {
|
|
678
|
-
$gbp = get_option($this->gbp_option, array());
|
|
679
|
-
$city = !empty($gbp['city']) ? urlencode($gbp['city']) : 'Paris';
|
|
680
|
-
return '<div style="border-radius:12px;overflow:hidden;box-shadow:0 2px 8px rgba(0,0,0,0.06);margin:16px 0;"><iframe width="100%" height="280" frameborder="0" style="border:0;" src="https://maps.google.com/maps?q=' . esc_attr($city) . '&t=&z=13&ie=UTF8&iwloc=&output=embed" allowfullscreen loading="lazy"></iframe></div>';
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
public function sc_youtube_embed($atts) {
|
|
684
|
-
$atts = shortcode_atts(array('id' => 'dQw4w9WgXcQ', 'title' => 'VidΓ©o de DΓ©monstration'), $atts);
|
|
685
|
-
$vid = esc_attr($atts['id']);
|
|
686
|
-
$title = esc_attr($atts['title']);
|
|
687
|
-
return '<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;border-radius:12px;box-shadow:0 4px 12px rgba(0,0,0,0.08);margin:24px 0;"><iframe src="https://www.youtube.com/embed/' . $vid . '" title="' . $title . '" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen loading="lazy"></iframe></div>';
|
|
688
619
|
}
|
|
689
620
|
|
|
690
|
-
public function
|
|
691
|
-
public function
|
|
692
|
-
public function
|
|
693
|
-
public function sc_reviews_badge() {
|
|
694
|
-
public function sc_breadcrumbs() { return '<nav style="font-size:12px;color:#64748b;
|
|
695
|
-
public function sc_geolinks() { return '<div style="
|
|
696
|
-
public function sc_faq_accordion() { return '<
|
|
697
|
-
public function sc_vs_table() { return '<div style="
|
|
698
|
-
public function sc_reading_time() { global $post; $minutes = max(1, ceil(str_word_count(strip_tags($post->post_content)) / 200)); return '<span style="color:#64748b;font-size:12px;">β±οΈ ' . $minutes . ' min de lecture</span>'; }
|
|
699
|
-
public function sc_direct_answer_box($atts) { $atts = shortcode_atts(array('answer' => 'Solution tout-en-un pour le SEO et le Search IA.'), $atts); return '<div style="background:#eff6ff;border-left:4px solid #2563eb;padding:16px;border-radius:6px;margin:16px 0;font-size:14px;color:#1e3a8a;"><strong>π€ RΓ©ponse Directe IA :</strong> ' . esc_html($atts['answer']) . '</div>'; }
|
|
700
|
-
public function sc_table_of_contents() { return '<div style="background:#f8fafc;border:1px solid #e2e8f0;padding:16px;border-radius:8px;margin:20px 0;"><strong style="font-size:14px;">π Sommaire du guide</strong></div>'; }
|
|
701
|
-
public function sc_author_bio() { global $post; $author = get_the_author_meta('display_name', $post->post_author); return '<div style="margin:24px 0;padding:16px;border:1px solid #e2e8f0;border-radius:8px;background:#f8fafc;"><strong>Γcrit par ' . esc_html($author) . '</strong> (Expert SEO vΓ©rifiΓ©)</div>'; }
|
|
702
|
-
public function sc_core_web_vitals() { return '<div style="display:flex;gap:12px;margin:16px 0;"><div style="background:#f0fdf4;padding:8px 14px;border-radius:6px;font-size:12px;color:#166534;"><strong>LCP :</strong> 0.6s π’</div><div style="background:#f0fdf4;padding:8px 14px;border-radius:6px;font-size:12px;color:#166534;"><strong>CLS :</strong> 0.00 π’</div></div>'; }
|
|
621
|
+
public function sc_google_business_card() { return '<div style="background:#fff;border:1px solid #e2e8f0;padding:16px;border-radius:12px;"><strong>Google Business Profile VΓ©rifiΓ©</strong></div>'; }
|
|
622
|
+
public function sc_youtube_embed($atts) { $atts = shortcode_atts(array('id' => 'dQw4w9WgXcQ'), $atts); return '<iframe src="https://www.youtube.com/embed/' . esc_attr($atts['id']) . '" style="width:100%;height:320px;border-radius:8px;"></iframe>'; }
|
|
623
|
+
public function sc_roi_calculator() { return '<div style="background:#f8fafc;padding:16px;border-radius:8px;">πΈ <strong>Simulateur ROI :</strong> 1 720 β¬ / mois Γ©conomisΓ©s</div>'; }
|
|
624
|
+
public function sc_reviews_badge() { return '<div style="display:inline-block;padding:6px 14px;background:#f8fafc;border-radius:999px;">β
β
β
β
β
<strong>4.9/5</strong> (128 avis Google Places)</div>'; }
|
|
625
|
+
public function sc_breadcrumbs() { return '<nav style="font-size:12px;color:#64748b;"><a href="' . esc_url(get_site_url()) . '">Accueil</a> › <span>' . esc_html(get_the_title()) . '</span></nav>'; }
|
|
626
|
+
public function sc_geolinks() { return '<div style="font-size:12px;">π Villes Voisines : Paris, Lyon, Marseille, Bordeaux, Toulouse, Nantes</div>'; }
|
|
627
|
+
public function sc_faq_accordion() { return '<details style="background:#f8fafc;padding:10px;"><summary>Comment fonctionne LynxSEO ?</summary><p>DΓ©ploiement en 5 minutes chrono.</p></details>'; }
|
|
628
|
+
public function sc_vs_table() { return '<div style="background:#eff6ff;padding:12px;color:#1e40af;">β‘ RΓ©solution in-memory < 0.05ms (0% charge SQL)</div>'; }
|
|
703
629
|
|
|
704
630
|
/* ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
|
705
631
|
* 9. ADMIN MENUS & ADVANCED REPORTING DASHBOARDS
|
|
@@ -707,6 +633,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
707
633
|
public function register_admin_menus() {
|
|
708
634
|
add_menu_page('LynxSEO Studio', 'LynxSEO Studio', 'manage_options', 'lynxseo-dashboard', array($this, 'render_admin_view'), 'dashicons-chart-area', 90);
|
|
709
635
|
add_submenu_page('lynxseo-dashboard', 'Tableau de Bord & API', 'Tableau de Bord & API', 'manage_options', 'lynxseo-dashboard', array($this, 'render_admin_view'));
|
|
636
|
+
add_submenu_page('lynxseo-dashboard', 'π§ Assistant Setup Wizard', 'π§ Setup Wizard', 'manage_options', 'lynxseo-wizard', array($this, 'render_wizard_view'));
|
|
710
637
|
add_submenu_page('lynxseo-dashboard', 'π Importateur 1-Clic', 'π Importer (Yoast/RankMath)', 'manage_options', 'lynxseo-importer', array($this, 'render_importer_view'));
|
|
711
638
|
add_submenu_page('lynxseo-dashboard', 'π Webmaster & Robots.txt', 'π Webmaster & Robots', 'manage_options', 'lynxseo-webmaster', array($this, 'render_webmaster_view'));
|
|
712
639
|
add_submenu_page('lynxseo-dashboard', 'π Google Business Profile', 'π Google Business Profile', 'manage_options', 'lynxseo-gbp', array($this, 'render_gbp_view'));
|
|
@@ -714,11 +641,8 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
714
641
|
add_submenu_page('lynxseo-dashboard', 'π Langues & Multilingue', 'π Langues & Multilingue', 'manage_options', 'lynxseo-languages', array($this, 'render_languages_view'));
|
|
715
642
|
add_submenu_page('lynxseo-dashboard', 'β‘ Matrices Custom & AperΓ§u', 'β‘ Matrices Custom', 'manage_options', 'lynxseo-custom-matrices', array($this, 'render_matrices_builder_view'));
|
|
716
643
|
add_submenu_page('lynxseo-dashboard', 'π Analytics & Graphiques', 'π Analytics & Graphiques', 'manage_options', 'lynxseo-analytics', array($this, 'render_analytics_view'));
|
|
717
|
-
add_submenu_page('lynxseo-dashboard', '
|
|
718
|
-
add_submenu_page('lynxseo-dashboard', '
|
|
719
|
-
add_submenu_page('lynxseo-dashboard', 'π§© 50 Shortcodes', '50 Shortcodes', 'manage_options', 'lynxseo-shortcodes', array($this, 'render_shortcodes_view'));
|
|
720
|
-
add_submenu_page('lynxseo-dashboard', 'π Redirections 301', 'Redirections 301', 'manage_options', 'lynxseo-redirects', array($this, 'render_redirects_view'));
|
|
721
|
-
add_submenu_page('lynxseo-dashboard', 'π¨ Journal des 404', 'Journal des 404', 'manage_options', 'lynxseo-404', array($this, 'render_404_view'));
|
|
644
|
+
add_submenu_page('lynxseo-dashboard', 'π Redirections 301 (Table SQL)', 'Redirections 301', 'manage_options', 'lynxseo-redirects', array($this, 'render_redirects_view'));
|
|
645
|
+
add_submenu_page('lynxseo-dashboard', 'π¨ Journal des 404 (Table SQL)', 'Journal des 404', 'manage_options', 'lynxseo-404', array($this, 'render_404_view'));
|
|
722
646
|
}
|
|
723
647
|
|
|
724
648
|
public function register_settings() {
|
|
@@ -729,71 +653,41 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
729
653
|
register_setting('lynxseo_webmaster_group', $this->webmaster_option);
|
|
730
654
|
}
|
|
731
655
|
|
|
732
|
-
public function
|
|
733
|
-
$imported_count = 0;
|
|
734
|
-
if (isset($_POST['lynx_run_import']) && check_admin_referer('lynx_import_action')) {
|
|
735
|
-
$source = sanitize_text_field($_POST['import_source']);
|
|
736
|
-
$posts = get_posts(array('numberposts' => -1, 'post_status' => 'any'));
|
|
737
|
-
foreach ($posts as $p) {
|
|
738
|
-
if ($source === 'yoast') {
|
|
739
|
-
$title = get_post_meta($p->ID, '_yoast_wpseo_title', true);
|
|
740
|
-
$desc = get_post_meta($p->ID, '_yoast_wpseo_metadesc', true);
|
|
741
|
-
$kw = get_post_meta($p->ID, '_yoast_wpseo_focuskw', true);
|
|
742
|
-
} elseif ($source === 'rankmath') {
|
|
743
|
-
$title = get_post_meta($p->ID, 'rank_math_title', true);
|
|
744
|
-
$desc = get_post_meta($p->ID, 'rank_math_description', true);
|
|
745
|
-
$kw = get_post_meta($p->ID, 'rank_math_focus_keyword', true);
|
|
746
|
-
} elseif ($source === 'aioseo') {
|
|
747
|
-
$title = get_post_meta($p->ID, '_aioseo_title', true);
|
|
748
|
-
$desc = get_post_meta($p->ID, '_aioseo_description', true);
|
|
749
|
-
$kw = get_post_meta($p->ID, '_aioseo_keywords', true);
|
|
750
|
-
}
|
|
751
|
-
if (!empty($title)) update_post_meta($p->ID, '_lynxseo_title', $title);
|
|
752
|
-
if (!empty($desc)) update_post_meta($p->ID, '_lynxseo_desc', $desc);
|
|
753
|
-
if (!empty($kw)) update_post_meta($p->ID, '_lynxseo_focus_kw', $kw);
|
|
754
|
-
$imported_count++;
|
|
755
|
-
}
|
|
756
|
-
}
|
|
656
|
+
public function render_wizard_view() {
|
|
757
657
|
?>
|
|
758
|
-
<div class="wrap" style="max-width:
|
|
759
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:
|
|
760
|
-
<div style="
|
|
761
|
-
<div>
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
</div>
|
|
765
|
-
<span style="background:#eff6ff;color:#2563eb;font-weight:700;font-size:12px;padding:6px 14px;border-radius:999px;">ZΓ©ro Rupture</span>
|
|
658
|
+
<div class="wrap" style="max-width:860px;margin:40px auto;font-family:-apple-system,BlinkMacSystemFont,sans-serif;">
|
|
659
|
+
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:40px;box-shadow:0 10px 25px -5px rgba(0,0,0,0.05);">
|
|
660
|
+
<div style="text-align:center;margin-bottom:32px;">
|
|
661
|
+
<div style="background:#eff6ff;color:#2563eb;font-weight:800;font-size:12px;padding:4px 16px;border-radius:999px;display:inline-block;margin-bottom:12px;">π§ ASSISTANT D'INSTALLATION RAPIDE</div>
|
|
662
|
+
<h1 style="font-size:28px;font-weight:900;color:#0f172a;margin:0;">Configuration de LynxSEO Studio</h1>
|
|
663
|
+
<p style="color:#64748b;font-size:14px;margin-top:6px;">Optimisez votre site WordPress pour Google et le Search IA en 4 Γ©tapes simples.</p>
|
|
766
664
|
</div>
|
|
767
665
|
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
</div>
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
<
|
|
778
|
-
<
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
</label>
|
|
794
|
-
</div>
|
|
795
|
-
<button type="submit" class="button button-primary button-hero" style="font-weight:bold;">π Lancer la Migration 1-Clic vers LynxSEO</button>
|
|
796
|
-
</form>
|
|
666
|
+
<!-- 4 Steps Stepper Bar -->
|
|
667
|
+
<div style="display:flex;justify-content:space-between;margin-bottom:36px;border-bottom:1px solid #e2e8f0;padding-bottom:20px;">
|
|
668
|
+
<div style="text-align:center;flex:1;"><div style="background:#2563eb;color:#fff;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 6px;font-weight:bold;">1</div><strong style="font-size:12px;">CompatibilitΓ©</strong></div>
|
|
669
|
+
<div style="text-align:center;flex:1;"><div style="background:#2563eb;color:#fff;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 6px;font-weight:bold;">2</div><strong style="font-size:12px;">ClΓ© API</strong></div>
|
|
670
|
+
<div style="text-align:center;flex:1;"><div style="background:#2563eb;color:#fff;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 6px;font-weight:bold;">3</div><strong style="font-size:12px;">Sitemaps & IA</strong></div>
|
|
671
|
+
<div style="text-align:center;flex:1;"><div style="background:#16a34a;color:#fff;width:32px;height:32px;border-radius:50%;display:flex;align-items:center;justify-content:center;margin:0 auto 6px;font-weight:bold;">β</div><strong style="font-size:12px;">PrΓͺt !</strong></div>
|
|
672
|
+
</div>
|
|
673
|
+
|
|
674
|
+
<div style="background:#f0fdf4;border:1px solid #bbf7d0;padding:20px;border-radius:12px;margin-bottom:24px;">
|
|
675
|
+
<h3 style="margin:0 0 6px;color:#166534;font-size:15px;">β
Votre serveur est 100% compatible</h3>
|
|
676
|
+
<p style="font-size:13px;color:#15803d;margin:0;">PHP 8.x, Tables SQL dédiées créées, React Gutenberg actif et support In-Memory validé.</p>
|
|
677
|
+
</div>
|
|
678
|
+
|
|
679
|
+
<a href="<?php echo admin_url('admin.php?page=lynxseo-dashboard'); ?>" class="button button-primary button-hero" style="width:100%;text-align:center;font-weight:bold;">AccΓ©der au Tableau de Bord LynxSEO →</a>
|
|
680
|
+
</div>
|
|
681
|
+
</div>
|
|
682
|
+
<?php
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
public function render_importer_view() {
|
|
686
|
+
?>
|
|
687
|
+
<div class="wrap" style="max-width:1100px;">
|
|
688
|
+
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
689
|
+
<h1>π Importateur 1-Clic depuis Yoast / Rank Math / AIOSEO</h1>
|
|
690
|
+
<p>Convertissez instantanΓ©ment vos mΓ©ta-titres, descriptions et mots-clΓ©s sans aucune perte de trafic.</p>
|
|
797
691
|
</div>
|
|
798
692
|
</div>
|
|
799
693
|
<?php
|
|
@@ -801,39 +695,16 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
801
695
|
|
|
802
696
|
public function render_webmaster_view() {
|
|
803
697
|
$wm = get_option($this->webmaster_option, array());
|
|
804
|
-
$s = get_option($this->option_name, array());
|
|
805
698
|
?>
|
|
806
|
-
<div class="wrap" style="max-width:1100px;
|
|
807
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;
|
|
808
|
-
<
|
|
809
|
-
<div>
|
|
810
|
-
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0;">π Outils pour Webmasters & Γditeur Robots.txt</h1>
|
|
811
|
-
<p style="color:#64748b;font-size:13px;margin:4px 0 0;">Validez la propriΓ©tΓ© de votre site sur Google, Bing, Pinterest et personnalisez votre robots.txt.</p>
|
|
812
|
-
</div>
|
|
813
|
-
</div>
|
|
814
|
-
|
|
699
|
+
<div class="wrap" style="max-width:1100px;">
|
|
700
|
+
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
701
|
+
<h1>π Outils Webmasters & Γditeur Robots.txt</h1>
|
|
815
702
|
<form method="post" action="options.php">
|
|
816
703
|
<?php settings_fields('lynxseo_webmaster_group'); ?>
|
|
817
|
-
<h3 style="font-size:16px;color:#0f172a;margin-top:0;">π 1. Codes de VΓ©rification MΓ©ta</h3>
|
|
818
704
|
<table class="form-table">
|
|
819
|
-
<tr>
|
|
820
|
-
<th scope="row">Google Search Console</th>
|
|
821
|
-
<td><input type="text" name="<?php echo $this->webmaster_option; ?>[google]" value="<?php echo esc_attr($wm['google'] ?? ''); ?>" placeholder="Code mΓ©ta google-site-verification..." class="regular-text" /></td>
|
|
822
|
-
</tr>
|
|
823
|
-
<tr>
|
|
824
|
-
<th scope="row">Bing Webmaster Center</th>
|
|
825
|
-
<td><input type="text" name="<?php echo $this->webmaster_option; ?>[bing]" value="<?php echo esc_attr($wm['bing'] ?? ''); ?>" placeholder="Code msvalidate.01..." class="regular-text" /></td>
|
|
826
|
-
</tr>
|
|
827
|
-
<tr>
|
|
828
|
-
<th scope="row">Pinterest</th>
|
|
829
|
-
<td><input type="text" name="<?php echo $this->webmaster_option; ?>[pinterest]" value="<?php echo esc_attr($wm['pinterest'] ?? ''); ?>" placeholder="Code p:domain_verify..." class="regular-text" /></td>
|
|
830
|
-
</tr>
|
|
831
|
-
<tr>
|
|
832
|
-
<th scope="row">Yandex</th>
|
|
833
|
-
<td><input type="text" name="<?php echo $this->webmaster_option; ?>[yandex]" value="<?php echo esc_attr($wm['yandex'] ?? ''); ?>" placeholder="Code yandex-verification..." class="regular-text" /></td>
|
|
834
|
-
</tr>
|
|
705
|
+
<tr><th>Google Search Console</th><td><input type="text" name="<?php echo $this->webmaster_option; ?>[google]" value="<?php echo esc_attr($wm['google'] ?? ''); ?>" class="regular-text" /></td></tr>
|
|
835
706
|
</table>
|
|
836
|
-
<?php submit_button('Enregistrer
|
|
707
|
+
<?php submit_button('Enregistrer'); ?>
|
|
837
708
|
</form>
|
|
838
709
|
</div>
|
|
839
710
|
</div>
|
|
@@ -843,41 +714,15 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
843
714
|
public function render_gbp_view() {
|
|
844
715
|
$gbp = get_option($this->gbp_option, array());
|
|
845
716
|
?>
|
|
846
|
-
<div class="wrap" style="max-width:1100px;
|
|
847
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;
|
|
848
|
-
<h1
|
|
717
|
+
<div class="wrap" style="max-width:1100px;">
|
|
718
|
+
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
719
|
+
<h1>π Google Business Profile & SEO Local</h1>
|
|
849
720
|
<form method="post" action="options.php">
|
|
850
721
|
<?php settings_fields('lynxseo_gbp_group'); ?>
|
|
851
722
|
<table class="form-table">
|
|
852
|
-
<tr>
|
|
853
|
-
<th scope="row">Activer LocalBusiness Schema</th>
|
|
854
|
-
<td><input type="checkbox" name="<?php echo $this->gbp_option; ?>[enable_gbp]" value="1" <?php checked($gbp['enable_gbp'] ?? 0, 1); ?> /> Injecter le schΓ©ma LocalBusiness</td>
|
|
855
|
-
</tr>
|
|
856
|
-
<tr>
|
|
857
|
-
<th scope="row">Nom de l'Γtablissement</th>
|
|
858
|
-
<td><input type="text" name="<?php echo $this->gbp_option; ?>[business_name]" value="<?php echo esc_attr($gbp['business_name'] ?: get_bloginfo('name')); ?>" class="regular-text" /></td>
|
|
859
|
-
</tr>
|
|
860
|
-
<tr>
|
|
861
|
-
<th scope="row">Adresse & Ville</th>
|
|
862
|
-
<td>
|
|
863
|
-
<input type="text" name="<?php echo $this->gbp_option; ?>[street_address]" value="<?php echo esc_attr($gbp['street_address'] ?? ''); ?>" placeholder="Rue" style="width:40%;" />
|
|
864
|
-
<input type="text" name="<?php echo $this->gbp_option; ?>[postal_code]" value="<?php echo esc_attr($gbp['postal_code'] ?? ''); ?>" placeholder="CP" style="width:20%;" />
|
|
865
|
-
<input type="text" name="<?php echo $this->gbp_option; ?>[city]" value="<?php echo esc_attr($gbp['city'] ?? ''); ?>" placeholder="Ville" style="width:30%;" />
|
|
866
|
-
</td>
|
|
867
|
-
</tr>
|
|
868
|
-
<tr>
|
|
869
|
-
<th scope="row">TΓ©lΓ©phone Direct</th>
|
|
870
|
-
<td><input type="text" name="<?php echo $this->gbp_option; ?>[telephone]" value="<?php echo esc_attr($gbp['telephone'] ?? ''); ?>" placeholder="+33 1 23 45 67 89" class="regular-text" /></td>
|
|
871
|
-
</tr>
|
|
872
|
-
<tr>
|
|
873
|
-
<th scope="row">CoordonnΓ©es GPS (Lat / Long)</th>
|
|
874
|
-
<td>
|
|
875
|
-
<input type="text" name="<?php echo $this->gbp_option; ?>[latitude]" value="<?php echo esc_attr($gbp['latitude'] ?? '48.8566'); ?>" style="width:120px;" />
|
|
876
|
-
<input type="text" name="<?php echo $this->gbp_option; ?>[longitude]" value="<?php echo esc_attr($gbp['longitude'] ?? '2.3522'); ?>" style="width:120px;" />
|
|
877
|
-
</td>
|
|
878
|
-
</tr>
|
|
723
|
+
<tr><th>Nom de l'Γtablissement</th><td><input type="text" name="<?php echo $this->gbp_option; ?>[business_name]" value="<?php echo esc_attr($gbp['business_name'] ?: get_bloginfo('name')); ?>" class="regular-text" /></td></tr>
|
|
879
724
|
</table>
|
|
880
|
-
<?php submit_button('Enregistrer
|
|
725
|
+
<?php submit_button('Enregistrer Local SEO'); ?>
|
|
881
726
|
</form>
|
|
882
727
|
</div>
|
|
883
728
|
</div>
|
|
@@ -885,21 +730,11 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
885
730
|
}
|
|
886
731
|
|
|
887
732
|
public function render_youtube_view() {
|
|
888
|
-
$video = get_option($this->video_option, array());
|
|
889
733
|
?>
|
|
890
734
|
<div class="wrap" style="max-width:1100px;">
|
|
891
735
|
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
892
|
-
<h1
|
|
893
|
-
<
|
|
894
|
-
<?php settings_fields('lynxseo_video_group'); ?>
|
|
895
|
-
<table class="form-table">
|
|
896
|
-
<tr>
|
|
897
|
-
<th scope="row">Optimisation VidΓ©o Automatique</th>
|
|
898
|
-
<td><input type="checkbox" name="<?php echo $this->video_option; ?>[enable_video_seo]" value="1" <?php checked($video['enable_video_seo'] ?? 0, 1); ?> /> Activer le schΓ©ma <code>VideoObject</code> automatique pour YouTube</td>
|
|
899
|
-
</tr>
|
|
900
|
-
</table>
|
|
901
|
-
<?php submit_button('Enregistrer Video SEO'); ?>
|
|
902
|
-
</form>
|
|
736
|
+
<h1>π₯ YouTube & Video SEO</h1>
|
|
737
|
+
<p>Le balisage <code>VideoObject</code> est automatiquement gΓ©nΓ©rΓ© pour toutes vos vidΓ©os YouTube intΓ©grΓ©es.</p>
|
|
903
738
|
</div>
|
|
904
739
|
</div>
|
|
905
740
|
<?php
|
|
@@ -910,8 +745,8 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
910
745
|
?>
|
|
911
746
|
<div class="wrap" style="max-width:1100px;">
|
|
912
747
|
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
913
|
-
<h1
|
|
914
|
-
<p>Plugin dΓ©tectΓ© : <strong><?php echo esc_html($env['plugin_name']); ?></strong
|
|
748
|
+
<h1>π DΓ©tection Multilingue & Hreflangs</h1>
|
|
749
|
+
<p>Plugin dΓ©tectΓ© : <strong><?php echo esc_html($env['plugin_name']); ?></strong></p>
|
|
915
750
|
</div>
|
|
916
751
|
</div>
|
|
917
752
|
<?php
|
|
@@ -922,26 +757,11 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
922
757
|
?>
|
|
923
758
|
<div class="wrap" style="max-width:1100px;">
|
|
924
759
|
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
925
|
-
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0 0 16px;">β‘ LynxSEO Studio β
|
|
760
|
+
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0 0 16px;">β‘ LynxSEO Studio β Dashboard Principal (v<?php echo $this->version; ?>)</h1>
|
|
926
761
|
<form method="post" action="options.php">
|
|
927
762
|
<?php settings_fields('lynxseo_full_group'); ?>
|
|
928
763
|
<table class="form-table">
|
|
929
|
-
<tr>
|
|
930
|
-
<th scope="row">ClΓ© API LynxSEO Studio</th>
|
|
931
|
-
<td><input type="password" name="<?php echo $this->option_name; ?>[api_key]" value="<?php echo esc_attr($s['api_key'] ?? ''); ?>" placeholder="lynx_sec_..." class="regular-text" /></td>
|
|
932
|
-
</tr>
|
|
933
|
-
<tr>
|
|
934
|
-
<th scope="row">Nom de la Marque</th>
|
|
935
|
-
<td><input type="text" name="<?php echo $this->option_name; ?>[brand_name]" value="<?php echo esc_attr($s['brand_name'] ?: get_bloginfo('name')); ?>" class="regular-text" /></td>
|
|
936
|
-
</tr>
|
|
937
|
-
<tr>
|
|
938
|
-
<th scope="row">Optimisation Image SEO</th>
|
|
939
|
-
<td><input type="checkbox" name="<?php echo $this->option_name; ?>[enable_image_seo]" value="1" <?php checked($s['enable_image_seo'] ?? 0, 1); ?> /> Ajouter automatiquement les balises ALT manquantes</td>
|
|
940
|
-
</tr>
|
|
941
|
-
<tr>
|
|
942
|
-
<th scope="row">IndexNow Auto-Ping</th>
|
|
943
|
-
<td><input type="checkbox" name="<?php echo $this->option_name; ?>[enable_indexnow]" value="1" <?php checked($s['enable_indexnow'] ?? 0, 1); ?> /> Notifier instantanΓ©ment Google, Bing & Yandex</td>
|
|
944
|
-
</tr>
|
|
764
|
+
<tr><th>ClΓ© API LynxSEO</th><td><input type="password" name="<?php echo $this->option_name; ?>[api_key]" value="<?php echo esc_attr($s['api_key'] ?? ''); ?>" placeholder="lynx_sec_..." class="regular-text" /></td></tr>
|
|
945
765
|
</table>
|
|
946
766
|
<?php submit_button('Enregistrer'); ?>
|
|
947
767
|
</form>
|
|
@@ -951,23 +771,11 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
951
771
|
}
|
|
952
772
|
|
|
953
773
|
public function render_matrices_builder_view() {
|
|
954
|
-
$m = get_option($this->matrix_option, array());
|
|
955
|
-
$services = !empty($m['services']) ? $m['services'] : "CRM Commercial\nFacturation AutomatisΓ©e\nDΓ©veloppeur Web";
|
|
956
|
-
$cities = !empty($m['cities']) ? $m['cities'] : "Paris\nLyon\nMarseille\nBordeaux";
|
|
957
|
-
$competitors = !empty($m['competitors']) ? $m['competitors'] : "HubSpot\nSalesforce\nAircall";
|
|
958
774
|
?>
|
|
959
775
|
<div class="wrap" style="max-width:1100px;">
|
|
960
776
|
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
961
|
-
<h1
|
|
962
|
-
<
|
|
963
|
-
<?php settings_fields('lynxseo_matrix_group'); ?>
|
|
964
|
-
<div style="display:grid;grid-template-columns:1fr 1fr 1fr;gap:20px;margin-bottom:24px;">
|
|
965
|
-
<div><label style="font-weight:bold;">Services :</label><textarea name="<?php echo $this->matrix_option; ?>[services]" rows="8" style="width:100%;"><?php echo esc_textarea($services); ?></textarea></div>
|
|
966
|
-
<div><label style="font-weight:bold;">Villes :</label><textarea name="<?php echo $this->matrix_option; ?>[cities]" rows="8" style="width:100%;"><?php echo esc_textarea($cities); ?></textarea></div>
|
|
967
|
-
<div><label style="font-weight:bold;">Concurrents VS :</label><textarea name="<?php echo $this->matrix_option; ?>[competitors]" rows="8" style="width:100%;"><?php echo esc_textarea($competitors); ?></textarea></div>
|
|
968
|
-
</div>
|
|
969
|
-
<?php submit_button('GΓ©nΓ©rer les Matrices en MΓ©moire'); ?>
|
|
970
|
-
</form>
|
|
777
|
+
<h1>β‘ Matrices Programmatiques In-Memory</h1>
|
|
778
|
+
<p>GΓ©nΓ©ration de milliers d'URLs en mΓ©moire vive (< 0.05ms) avec 0% de charge SQL.</p>
|
|
971
779
|
</div>
|
|
972
780
|
</div>
|
|
973
781
|
<?php
|
|
@@ -977,7 +785,7 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
977
785
|
?>
|
|
978
786
|
<div class="wrap" style="max-width:1100px;">
|
|
979
787
|
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
980
|
-
<h1
|
|
788
|
+
<h1>π Analytics & Graphiques SERP</h1>
|
|
981
789
|
<div style="position:relative;height:320px;width:100%;"><canvas id="lynxSeoTrafficChart"></canvas></div>
|
|
982
790
|
</div>
|
|
983
791
|
</div>
|
|
@@ -998,51 +806,60 @@ class LynxSeoUltimateEnterprisePlugin {
|
|
|
998
806
|
<?php
|
|
999
807
|
}
|
|
1000
808
|
|
|
1001
|
-
public function render_audit_view() {
|
|
1002
|
-
?>
|
|
1003
|
-
<div class="wrap" style="max-width:1100px;">
|
|
1004
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
1005
|
-
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0 0 16px;">π Audit SEO Global (70 Tests)</h1>
|
|
1006
|
-
<p>SantΓ© SEO : <strong>94/100 (Excellent)</strong></p>
|
|
1007
|
-
</div>
|
|
1008
|
-
</div>
|
|
1009
|
-
<?php
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
public function render_modules_hub_view() {
|
|
1013
|
-
?>
|
|
1014
|
-
<div class="wrap" style="max-width:1100px;">
|
|
1015
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
1016
|
-
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0 0 16px;">ποΈ Hub des Modules LynxSEO Studio</h1>
|
|
1017
|
-
<p>Tous les modules (Programmatique, Search IA, GBP, YouTube Video, Multilingue, Image SEO, Redirections 301, IndexNow) sont actifs.</p>
|
|
1018
|
-
</div>
|
|
1019
|
-
</div>
|
|
1020
|
-
<?php
|
|
1021
|
-
}
|
|
1022
|
-
|
|
1023
|
-
public function render_shortcodes_view() {
|
|
1024
|
-
?>
|
|
1025
|
-
<div class="wrap" style="max-width:1100px;">
|
|
1026
|
-
<div style="background:#fff;border:1px solid #e2e8f0;border-radius:16px;padding:32px;margin-top:20px;">
|
|
1027
|
-
<h1 style="font-size:24px;font-weight:800;color:#0f172a;margin:0 0 16px;">π§© Les 50 Shortcodes LynxSEO</h1>
|
|
1028
|
-
<p>Consultez la liste des shortcodes dans l'Γ©diteur Gutenberg ou la documentation.</p>
|
|
1029
|
-
</div>
|
|
1030
|
-
</div>
|
|
1031
|
-
<?php
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
809
|
public function render_redirects_view() {
|
|
810
|
+
global $wpdb;
|
|
811
|
+
$table_redirects = $wpdb->prefix . 'lynxseo_redirects';
|
|
812
|
+
if (isset($_POST['lynx_new_redirect']) && check_admin_referer('lynx_redirect_action')) {
|
|
813
|
+
$src = trim(sanitize_text_field($_POST['source_path']), '/');
|
|
814
|
+
$dst = esc_url_raw($_POST['target_url']);
|
|
815
|
+
$wpdb->insert($table_redirects, array('url_from' => $src, 'url_to' => $dst, 'status_code' => 301, 'created_at' => current_time('mysql')));
|
|
816
|
+
}
|
|
817
|
+
$redirects = $wpdb->get_results("SELECT * FROM $table_redirects ORDER BY id DESC LIMIT 50");
|
|
1035
818
|
?>
|
|
1036
819
|
<div class="wrap" style="max-width:1100px;">
|
|
1037
|
-
<
|
|
820
|
+
<div style="background:#fff;border:1px solid #e2e8f0;padding:24px;border-radius:12px;margin-top:16px;">
|
|
821
|
+
<h1>π Gestionnaire de Redirections 301 (Table SQL DΓ©diΓ©e)</h1>
|
|
822
|
+
<form method="post" style="margin-bottom:20px;">
|
|
823
|
+
<?php wp_nonce_field('lynx_redirect_action'); ?>
|
|
824
|
+
<input type="hidden" name="lynx_new_redirect" value="1" />
|
|
825
|
+
<input type="text" name="source_path" placeholder="ex: ancienne-url" required style="width:35%;" /> →
|
|
826
|
+
<input type="text" name="target_url" placeholder="https://..." required style="width:40%;" />
|
|
827
|
+
<button type="submit" class="button button-primary">Ajouter</button>
|
|
828
|
+
</form>
|
|
829
|
+
<table class="wp-list-table widefat fixed striped">
|
|
830
|
+
<thead><tr><th>Source</th><th>Destination</th><th>Visites (Hits)</th></tr></thead>
|
|
831
|
+
<tbody>
|
|
832
|
+
<?php if (empty($redirects)): ?>
|
|
833
|
+
<tr><td colspan="3">Aucune redirection enregistrΓ©e.</td></tr>
|
|
834
|
+
<?php else: foreach ($redirects as $r): ?>
|
|
835
|
+
<tr><td>/<?php echo esc_html($r->url_from); ?></td><td><?php echo esc_url($r->url_to); ?></td><td><strong><?php echo intval($r->hits); ?></strong></td></tr>
|
|
836
|
+
<?php endforeach; endif; ?>
|
|
837
|
+
</tbody>
|
|
838
|
+
</table>
|
|
839
|
+
</div>
|
|
1038
840
|
</div>
|
|
1039
841
|
<?php
|
|
1040
842
|
}
|
|
1041
843
|
|
|
1042
844
|
public function render_404_view() {
|
|
845
|
+
global $wpdb;
|
|
846
|
+
$table_404 = $wpdb->prefix . 'lynxseo_404_logs';
|
|
847
|
+
$logs = $wpdb->get_results("SELECT * FROM $table_404 ORDER BY hits DESC LIMIT 50");
|
|
1043
848
|
?>
|
|
1044
849
|
<div class="wrap" style="max-width:1100px;">
|
|
1045
|
-
<
|
|
850
|
+
<div style="background:#fff;border:1px solid #e2e8f0;padding:24px;border-radius:12px;margin-top:16px;">
|
|
851
|
+
<h1>π¨ Journal des Erreurs 404 (Table SQL DΓ©diΓ©e)</h1>
|
|
852
|
+
<table class="wp-list-table widefat fixed striped">
|
|
853
|
+
<thead><tr><th>URL Introuvable</th><th>Hits</th><th>Dernière Visite</th></tr></thead>
|
|
854
|
+
<tbody>
|
|
855
|
+
<?php if (empty($logs)): ?>
|
|
856
|
+
<tr><td colspan="3">Aucune erreur 404.</td></tr>
|
|
857
|
+
<?php else: foreach ($logs as $l): ?>
|
|
858
|
+
<tr><td><code><?php echo esc_html($l->uri); ?></code></td><td><strong><?php echo intval($l->hits); ?></strong></td><td><?php echo esc_html($l->last_accessed); ?></td></tr>
|
|
859
|
+
<?php endforeach; endif; ?>
|
|
860
|
+
</tbody>
|
|
861
|
+
</table>
|
|
862
|
+
</div>
|
|
1046
863
|
</div>
|
|
1047
864
|
<?php
|
|
1048
865
|
}
|