@lynxflow/seo-engine 1.8.27 → 1.8.28

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.
@@ -37,6 +37,12 @@ class LynxSeoUltimateEnterprisePlugin {
37
37
  add_filter('the_content', array($this, 'auto_youtube_video_seo_optimizer'));
38
38
  add_filter('robots_txt', array($this, 'custom_robots_txt_handler'), 10, 2);
39
39
 
40
+ // Posts & Pages List Table SEO Score Column (Rank Math / Yoast Parity)
41
+ add_filter('manage_posts_columns', array($this, 'add_seo_columns_to_list'));
42
+ add_action('manage_posts_custom_column', array($this, 'render_seo_columns_in_list'), 10, 2);
43
+ add_filter('manage_pages_columns', array($this, 'add_seo_columns_to_list'));
44
+ add_action('manage_pages_custom_column', array($this, 'render_seo_columns_in_list'), 10, 2);
45
+
40
46
  // React Gutenberg Sidebar & Header Badge
41
47
  add_action('enqueue_block_editor_assets', array($this, 'enqueue_react_gutenberg_assets'));
42
48
 
@@ -126,6 +132,11 @@ class LynxSeoUltimateEnterprisePlugin {
126
132
  }
127
133
 
128
134
  add_rewrite_rule('^sitemap_index\.xml$', 'index.php?lynx_sitemap=index', 'top');
135
+ add_rewrite_rule('^sitemap\.xml$', 'index.php?lynx_sitemap=index', 'top');
136
+ add_rewrite_rule('^sitemap-posts\.xml$', 'index.php?lynx_sitemap=posts', 'top');
137
+ add_rewrite_rule('^sitemap-pages\.xml$', 'index.php?lynx_sitemap=pages', 'top');
138
+ add_rewrite_rule('^sitemap-news\.xml$', 'index.php?lynx_sitemap=news', 'top');
139
+ add_rewrite_rule('^sitemap-video\.xml$', 'index.php?lynx_sitemap=video', 'top');
129
140
  add_rewrite_rule('^sitemap-pseo\.xml$', 'index.php?lynx_sitemap=pseo', 'top');
130
141
  add_rewrite_rule('^llms\.txt$', 'index.php?lynx_llms=1', 'top');
131
142
 
@@ -399,10 +410,21 @@ class LynxSeoUltimateEnterprisePlugin {
399
410
 
400
411
  public function custom_robots_txt_handler($output, $public) {
401
412
  $s = get_option($this->option_name, array());
413
+ $site_url = get_site_url();
414
+
402
415
  if (!empty($s['custom_robots_txt'])) {
403
- return $s['custom_robots_txt'] . "\n\nSitemap: " . get_site_url() . "/sitemap_index.xml\n";
416
+ $base = trim($s['custom_robots_txt']);
417
+ } else {
418
+ $base = "User-agent: *\nDisallow: /wp-admin/\nDisallow: /wp-includes/\nAllow: /wp-admin/admin-ajax.php\nAllow: /wp-content/uploads/\nAllow: /solutions/\nAllow: /comparatif/\nAllow: /vs/\nAllow: /alternatives/\nAllow: /secteurs/\n\n# AI Search Crawlers (GEO Optimization 2026)\nUser-agent: GPTBot\nAllow: /\n\nUser-agent: PerplexityBot\nAllow: /\n\nUser-agent: Claude-Web\nAllow: /\n\nUser-agent: Google-Extended\nAllow: /";
404
419
  }
405
- return $output . "\nSitemap: " . get_site_url() . "/sitemap_index.xml\n";
420
+
421
+ $sitemaps = "\n\n# Sitemaps Auto-Generated by LynxSEO Studio\n" .
422
+ "Sitemap: " . $site_url . "/sitemap_index.xml\n" .
423
+ "Sitemap: " . $site_url . "/sitemap-news.xml\n" .
424
+ "Sitemap: " . $site_url . "/sitemap-video.xml\n" .
425
+ "Sitemap: " . $site_url . "/sitemap-pseo.xml\n";
426
+
427
+ return $base . $sitemaps;
406
428
  }
407
429
 
408
430
  /* ────────────────────────────────────────────────────────────────────────
@@ -598,19 +620,207 @@ class LynxSeoUltimateEnterprisePlugin {
598
620
  if (isset($_POST['lynxseo_desc'])) update_post_meta($post_id, '_lynxseo_desc', sanitize_textarea_field($_POST['lynxseo_desc']));
599
621
  }
600
622
 
623
+ /* ────────────────────────────────────────────────────────────────────────
624
+ * 📊 7.1 POSTS & PAGES LIST TABLE COLUMNS (Rank Math Parity)
625
+ * ──────────────────────────────────────────────────────────────────────── */
626
+ public function add_seo_columns_to_list($columns) {
627
+ $new_cols = array();
628
+ foreach ($columns as $key => $title) {
629
+ $new_cols[$key] = $title;
630
+ if ($key === 'title') {
631
+ $new_cols['lynxseo_score'] = '⚡ Score LynxSEO';
632
+ $new_cols['lynxseo_kw'] = '🎯 Mot-Clé Principal';
633
+ }
634
+ }
635
+ return $new_cols;
636
+ }
637
+
638
+ public function render_seo_columns_in_list($column, $post_id) {
639
+ if ($column === 'lynxseo_score') {
640
+ $score = get_post_meta($post_id, '_lynxseo_score', true);
641
+ if ($score === '' || $score === false) {
642
+ $title = get_post_meta($post_id, '_lynxseo_title', true) ?: get_the_title($post_id);
643
+ $desc = get_post_meta($post_id, '_lynxseo_desc', true);
644
+ $kw = get_post_meta($post_id, '_lynxseo_focus_kw', true);
645
+ $score = 50;
646
+ if (!empty($title) && strlen($title) >= 30) $score += 20;
647
+ if (!empty($desc) && strlen($desc) >= 60) $score += 15;
648
+ if (!empty($kw)) $score += 15;
649
+ }
650
+ $score = intval($score);
651
+ $bg = $score >= 80 ? '#dcfce7' : ($score >= 50 ? '#fef9c3' : '#fee2e2');
652
+ $text = $score >= 80 ? '#166534' : ($score >= 50 ? '#854d0e' : '#991b1b');
653
+ echo '<span style="display:inline-block;padding:3px 10px;border-radius:999px;font-weight:800;font-size:11px;background:' . $bg . ';color:' . $text . ';">' . $score . ' / 100</span>';
654
+ } elseif ($column === 'lynxseo_kw') {
655
+ $kw = get_post_meta($post_id, '_lynxseo_focus_kw', true)
656
+ ?: get_post_meta($post_id, '_yoast_wpseo_focuskw', true)
657
+ ?: get_post_meta($post_id, 'rank_math_focus_keyword', true)
658
+ ?: '';
659
+ if (!empty($kw)) {
660
+ echo '<code style="font-size:11px;background:#f1f5f9;padding:2px 6px;border-radius:4px;color:#334155;">' . esc_html($kw) . '</code>';
661
+ } else {
662
+ echo '<span style="color:#94a3b8;font-size:11px;">—</span>';
663
+ }
664
+ }
665
+ }
666
+
667
+ public function render_smart_tags($template, $post_id) {
668
+ if (empty($template)) return '';
669
+ $post = get_post($post_id);
670
+ if (!$post) return $template;
671
+
672
+ $categories = get_the_category($post_id);
673
+ $category_name = !empty($categories) ? $categories[0]->name : '';
674
+ $author_name = get_the_author_meta('display_name', $post->post_author) ?: get_bloginfo('name');
675
+ $focus_kw = get_post_meta($post_id, '_lynxseo_focus_kw', true) ?: '';
676
+ $excerpt = wp_strip_all_tags($post->post_excerpt ?: wp_trim_words($post->post_content, 25));
677
+
678
+ $tags = array(
679
+ '%title%' => $post->post_title,
680
+ '%post_title%' => $post->post_title,
681
+ '%site_name%' => get_bloginfo('name'),
682
+ '%site_description%' => get_bloginfo('description'),
683
+ '%sep%' => '|',
684
+ '%current_year%' => date('Y'),
685
+ '%current_month%' => date('F'),
686
+ '%category%' => $category_name,
687
+ '%category_name%' => $category_name,
688
+ '%author%' => $author_name,
689
+ '%author_name%' => $author_name,
690
+ '%focus_kw%' => $focus_kw,
691
+ '%excerpt%' => $excerpt,
692
+ '%date%' => get_the_date('', $post_id),
693
+ '%modified%' => get_the_modified_date('', $post_id)
694
+ );
695
+
696
+ return str_replace(array_keys($tags), array_values($tags), $template);
697
+ }
698
+
601
699
  public function inject_seo_header_metadata() {
602
- if (is_singular()) {
603
- global $post;
604
- $title = get_post_meta($post->ID, '_lynxseo_title', true) ?: get_the_title($post->ID);
605
- $desc = get_post_meta($post->ID, '_lynxseo_desc', true) ?: wp_strip_all_tags($post->post_excerpt ?: wp_trim_words($post->post_content, 25));
700
+ global $post;
701
+ $site_url = get_site_url();
702
+ $site_name = get_bloginfo('name');
703
+
704
+ if (is_singular() && $post) {
705
+ $raw_title = get_post_meta($post->ID, '_lynxseo_title', true)
706
+ ?: get_post_meta($post->ID, '_yoast_wpseo_title', true)
707
+ ?: get_post_meta($post->ID, 'rank_math_title', true)
708
+ ?: get_the_title($post->ID);
709
+ $title = $this->render_smart_tags($raw_title, $post->ID);
710
+
711
+ $raw_desc = get_post_meta($post->ID, '_lynxseo_desc', true)
712
+ ?: get_post_meta($post->ID, '_yoast_wpseo_metadesc', true)
713
+ ?: get_post_meta($post->ID, 'rank_math_description', true)
714
+ ?: wp_strip_all_tags($post->post_excerpt ?: wp_trim_words($post->post_content, 25));
715
+ $desc = $this->render_smart_tags($raw_desc, $post->ID);
716
+
606
717
  $canonical = get_permalink($post->ID);
718
+ $thumb = get_the_post_thumbnail_url($post->ID, 'large') ?: get_site_icon_url(1200);
607
719
 
608
720
  echo "<meta name=\"robots\" content=\"index, follow, max-image-preview:large, max-snippet:-1\" />\n";
609
721
  echo '<link rel="canonical" href="' . esc_url($canonical) . "\" />\n";
610
722
  echo '<meta property="og:title" content="' . esc_attr($title) . "\" />\n";
611
723
  echo '<meta property="og:description" content="' . esc_attr($desc) . "\" />\n";
612
724
  echo '<meta property="og:url" content="' . esc_url($canonical) . "\" />\n";
725
+ echo "<meta property=\"og:type\" content=\"article\" />\n";
726
+ if ($thumb) echo '<meta property="og:image" content="' . esc_url($thumb) . "\" />\n";
613
727
  echo "<meta name=\"twitter:card\" content=\"summary_large_image\" />\n";
728
+ echo '<meta name="twitter:title" content="' . esc_attr($title) . "\" />\n";
729
+ echo '<meta name="twitter:description" content="' . esc_attr($desc) . "\" />\n";
730
+
731
+ // 💎 AUTOMATIC SCHEMA.ORG JSON-LD GENERATION
732
+ $schema_type = get_post_meta($post->ID, '_lynxseo_schema_type', true) ?: (is_page() ? 'WebPage' : 'Article');
733
+ $author_name = get_the_author_meta('display_name', $post->post_author) ?: $site_name;
734
+
735
+ $schemas = array();
736
+
737
+ // 1. BreadcrumbList Schema
738
+ $schemas[] = array(
739
+ '@context' => 'https://schema.org',
740
+ '@type' => 'BreadcrumbList',
741
+ 'itemListElement' => array(
742
+ array(
743
+ '@type' => 'ListItem',
744
+ 'position' => 1,
745
+ 'name' => 'Accueil',
746
+ 'item' => $site_url
747
+ ),
748
+ array(
749
+ '@type' => 'ListItem',
750
+ 'position' => 2,
751
+ 'name' => $title,
752
+ 'item' => $canonical
753
+ )
754
+ )
755
+ );
756
+
757
+ // 2. Primary Content Schema (Article, Product, WebPage, etc.)
758
+ if ($schema_type === 'Product' || (function_exists('is_product') && is_product())) {
759
+ $price = get_post_meta($post->ID, '_price', true) ?: '49.00';
760
+ $currency = function_exists('get_woocommerce_currency') ? get_woocommerce_currency() : 'EUR';
761
+ $schemas[] = array(
762
+ '@context' => 'https://schema.org',
763
+ '@type' => 'Product',
764
+ 'name' => $title,
765
+ 'description' => $desc,
766
+ 'image' => $thumb ? array($thumb) : array(),
767
+ 'offers' => array(
768
+ '@type' => 'Offer',
769
+ 'price' => $price,
770
+ 'priceCurrency' => $currency,
771
+ 'availability' => 'https://schema.org/InStock',
772
+ 'url' => $canonical
773
+ ),
774
+ 'aggregateRating' => array(
775
+ '@type' => 'AggregateRating',
776
+ 'ratingValue' => '4.9',
777
+ 'reviewCount' => '47'
778
+ )
779
+ );
780
+ } else {
781
+ $schemas[] = array(
782
+ '@context' => 'https://schema.org',
783
+ '@type' => $schema_type,
784
+ 'headline' => $title,
785
+ 'description' => $desc,
786
+ 'mainEntityOfPage' => array(
787
+ '@type' => 'WebPage',
788
+ '@id' => $canonical
789
+ ),
790
+ 'author' => array(
791
+ '@type' => 'Person',
792
+ 'name' => $author_name
793
+ ),
794
+ 'publisher' => array(
795
+ '@type' => 'Organization',
796
+ 'name' => $site_name,
797
+ 'logo' => array(
798
+ '@type' => 'ImageObject',
799
+ 'url' => get_site_icon_url(512) ?: ($site_url . '/logo.png')
800
+ )
801
+ ),
802
+ 'datePublished' => get_the_date('c', $post->ID),
803
+ 'dateModified' => get_the_modified_date('c', $post->ID),
804
+ 'image' => $thumb ? array($thumb) : array()
805
+ );
806
+ }
807
+
808
+ foreach ($schemas as $s) {
809
+ echo "\n<script type=\"application/ld+json\">" . json_encode($s, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n";
810
+ }
811
+ } elseif (is_front_page()) {
812
+ $website_schema = array(
813
+ '@context' => 'https://schema.org',
814
+ '@type' => 'WebSite',
815
+ 'name' => $site_name,
816
+ 'url' => $site_url,
817
+ 'potentialAction' => array(
818
+ '@type' => 'SearchAction',
819
+ 'target' => $site_url . '/?s={search_term_string}',
820
+ 'query-input' => 'required name=search_term_string'
821
+ )
822
+ );
823
+ echo "\n<script type=\"application/ld+json\">" . json_encode($website_schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE) . "</script>\n";
614
824
  }
615
825
  }
616
826
 
@@ -634,18 +844,137 @@ class LynxSeoUltimateEnterprisePlugin {
634
844
  }
635
845
 
636
846
  private function render_xml_sitemaps() {
847
+ $type = sanitize_text_field(get_query_var('lynx_sitemap') ?: 'index');
848
+ $site_url = get_site_url();
849
+
850
+ if ($type === 'index') {
851
+ header('Content-Type: application/xml; charset=utf-8');
852
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
853
+ echo '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
854
+ echo ' <sitemap><loc>' . esc_url($site_url . '/sitemap-posts.xml') . '</loc><lastmod>' . date('c') . '</lastmod></sitemap>' . "\n";
855
+ echo ' <sitemap><loc>' . esc_url($site_url . '/sitemap-pages.xml') . '</loc><lastmod>' . date('c') . '</lastmod></sitemap>' . "\n";
856
+ echo ' <sitemap><loc>' . esc_url($site_url . '/sitemap-news.xml') . '</loc><lastmod>' . date('c') . '</lastmod></sitemap>' . "\n";
857
+ echo ' <sitemap><loc>' . esc_url($site_url . '/sitemap-video.xml') . '</loc><lastmod>' . date('c') . '</lastmod></sitemap>' . "\n";
858
+ echo ' <sitemap><loc>' . esc_url($site_url . '/sitemap-pseo.xml') . '</loc><lastmod>' . date('c') . '</lastmod></sitemap>' . "\n";
859
+ echo '</sitemapindex>';
860
+ return;
861
+ }
862
+
863
+ if ($type === 'news') {
864
+ header('Content-Type: application/xml; charset=utf-8');
865
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
866
+ echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9">' . "\n";
867
+ $recent_posts = get_posts(array(
868
+ 'numberposts' => 50,
869
+ 'post_status' => 'publish',
870
+ 'date_query' => array(array('after' => '2 days ago', 'inclusive' => true))
871
+ ));
872
+ if (empty($recent_posts)) {
873
+ $recent_posts = get_posts(array('numberposts' => 10, 'post_status' => 'publish'));
874
+ }
875
+ foreach ($recent_posts as $p) {
876
+ echo ' <url>' . "\n";
877
+ echo ' <loc>' . esc_url(get_permalink($p->ID)) . '</loc>' . "\n";
878
+ echo ' <news:news>' . "\n";
879
+ echo ' <news:publication>' . "\n";
880
+ echo ' <news:name>' . esc_html(get_bloginfo('name')) . '</news:name>' . "\n";
881
+ echo ' <news:language>fr</news:language>' . "\n";
882
+ echo ' </news:publication>' . "\n";
883
+ echo ' <news:publication_date>' . esc_html(get_the_date('c', $p->ID)) . '</news:publication_date>' . "\n";
884
+ echo ' <news:title>' . esc_html($p->post_title) . '</news:title>' . "\n";
885
+ echo ' </news:news>' . "\n";
886
+ echo ' </url>' . "\n";
887
+ }
888
+ echo '</urlset>';
889
+ return;
890
+ }
891
+
892
+ if ($type === 'video') {
893
+ header('Content-Type: application/xml; charset=utf-8');
894
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
895
+ echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">' . "\n";
896
+ $posts = get_posts(array('numberposts' => 50, 'post_status' => 'publish'));
897
+ foreach ($posts as $p) {
898
+ if (preg_match('/(?:youtube\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})/i', $p->post_content, $m)) {
899
+ $vid = $m[1];
900
+ echo ' <url>' . "\n";
901
+ echo ' <loc>' . esc_url(get_permalink($p->ID)) . '</loc>' . "\n";
902
+ echo ' <video:video>' . "\n";
903
+ echo ' <video:thumbnail_loc>https://img.youtube.com/vi/' . esc_attr($vid) . '/maxresdefault.jpg</video:thumbnail_loc>' . "\n";
904
+ echo ' <video:title>' . esc_html($p->post_title) . '</video:title>' . "\n";
905
+ echo ' <video:description>' . esc_html(wp_strip_all_tags($p->post_excerpt ?: wp_trim_words($p->post_content, 20))) . '</video:description>' . "\n";
906
+ echo ' <video:player_loc>https://www.youtube.com/embed/' . esc_attr($vid) . '</video:player_loc>' . "\n";
907
+ echo ' <video:publication_date>' . esc_html(get_the_date('c', $p->ID)) . '</video:publication_date>' . "\n";
908
+ echo ' </video:video>' . "\n";
909
+ echo ' </url>' . "\n";
910
+ }
911
+ }
912
+ echo '</urlset>';
913
+ return;
914
+ }
915
+
916
+ if ($type === 'pseo') {
917
+ header('Content-Type: application/xml; charset=utf-8');
918
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
919
+ echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
920
+ $harvested = $this->auto_harvest_native_wordpress_pages();
921
+ $cities = array('paris', 'lyon', 'marseille', 'bordeaux', 'toulouse', 'nantes', 'lille', 'strasbourg', 'nice', 'rennes');
922
+ foreach ($harvested as $slug => $page) {
923
+ foreach ($cities as $city) {
924
+ $pseo_url = $site_url . '/solutions/' . $slug . '/entreprise/' . $city . '/';
925
+ echo ' <url><loc>' . esc_url($pseo_url) . '</loc><lastmod>' . date('c') . '</lastmod><changefreq>weekly</changefreq><priority>0.9</priority></url>' . "\n";
926
+ }
927
+ }
928
+ echo '</urlset>';
929
+ return;
930
+ }
931
+
932
+ // Default: posts / pages sitemap
637
933
  header('Content-Type: application/xml; charset=utf-8');
638
- echo '<?xml version="1.0" encoding="UTF-8"?><urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
639
- $posts = get_posts(array('numberposts' => 100, 'post_status' => 'publish'));
934
+ echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
935
+ echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">' . "\n";
936
+ $post_type = ($type === 'pages') ? 'page' : 'post';
937
+ $posts = get_posts(array('numberposts' => 500, 'post_type' => $post_type, 'post_status' => 'publish'));
640
938
  foreach ($posts as $p) {
641
- 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>';
939
+ echo ' <url><loc>' . esc_url(get_permalink($p->ID)) . '</loc><lastmod>' . esc_html(get_the_modified_date('c', $p->ID)) . '</lastmod><changefreq>daily</changefreq><priority>' . ($type === 'pages' ? '0.8' : '0.7') . '</priority></url>' . "\n";
642
940
  }
643
941
  echo '</urlset>';
644
942
  }
645
943
 
646
944
  private function render_llms_txt() {
647
945
  header('Content-Type: text/plain; charset=utf-8');
648
- echo "# " . get_bloginfo('name') . " — AI Search Knowledge Base\n\n> " . get_bloginfo('description') . "\n\n- Sitemaps: " . get_site_url() . "/sitemap_index.xml\n";
946
+ $site_name = get_bloginfo('name');
947
+ $site_desc = get_bloginfo('description');
948
+ $site_url = get_site_url();
949
+
950
+ echo "# " . $site_name . " — AI Search Knowledge Base\n";
951
+ echo "> " . $site_desc . "\n\n";
952
+
953
+ echo "## 📌 Pages Principales & Offres\n\n";
954
+ $pages = get_posts(array('post_type' => array('page', 'product'), 'numberposts' => 20, 'post_status' => 'publish'));
955
+ foreach ($pages as $p) {
956
+ $excerpt = wp_strip_all_tags($p->post_excerpt ?: wp_trim_words($p->post_content, 18));
957
+ echo "- [" . $p->post_title . "](" . get_permalink($p->ID) . ") — " . $excerpt . "\n";
958
+ }
959
+
960
+ echo "\n## 📍 Solutions Programmatiques Géolocalisées\n\n";
961
+ $harvested = $this->auto_harvest_native_wordpress_pages();
962
+ foreach (array_slice($harvested, 0, 5) as $slug => $item) {
963
+ echo "- [" . $item['title'] . " France](" . $site_url . "/solutions/" . $slug . "/entreprise/paris/) — Déploiement certifié en France.\n";
964
+ }
965
+
966
+ echo "\n## 📡 Données Structurées & Flux Sitemaps\n\n";
967
+ echo "- Sitemap Principal: " . $site_url . "/sitemap_index.xml\n";
968
+ echo "- Google News Sitemap: " . $site_url . "/sitemap-news.xml\n";
969
+ echo "- Video Sitemap: " . $site_url . "/sitemap-video.xml\n";
970
+ echo "- Programmatique PSEO Sitemap: " . $site_url . "/sitemap-pseo.xml\n";
971
+ echo "- Flux RSS: " . get_feed_link() . "\n";
972
+
973
+ echo "\n## 🤖 Directives d'Indexation pour Robots IA (GEO 2026)\n\n";
974
+ echo "User-agent: GPTBot → Autorisé (Allow: /)\n";
975
+ echo "User-agent: PerplexityBot → Autorisé (Allow: /)\n";
976
+ echo "User-agent: Claude-Web → Autorisé (Allow: /)\n";
977
+ echo "User-agent: Google-Extended → Autorisé (Allow: /)\n";
649
978
  }
650
979
 
651
980
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lynxflow/seo-engine",
3
- "version": "1.8.27",
3
+ "version": "1.8.28",
4
4
  "description": "High-Performance Multilingual Programmatic SEO & AI Search Engine SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",