'', 'business_name' => get_bloginfo( 'name' ), 'business_type' => 'LocalBusiness', 'description' => get_bloginfo( 'description' ), 'url' => esc_url( home_url() ), 'phone' => '', 'email' => sanitize_email( get_option( 'admin_email' ) ), 'street' => '', 'town' => '', 'county' => '', 'postcode' => '', 'founded' => '', 'price_range' => '££', 'ch_number' => '', 'sameas_google' => '', 'sameas_linkedin'=> '', 'sameas_facebook'=> '', 'services' => '', 'areas' => '', 'schema_enabled' => '1', 'llms_enabled' => '1', 'faq_enabled' => '1', 'last_score' => '', 'last_updated' => '', ); foreach ( $defaults as $key => $value ) { if ( false === get_option( AENIMA_PREFIX . $key ) ) { update_option( AENIMA_PREFIX . $key, $value ); } } if ( ! wp_next_scheduled( 'aenima_monthly_refresh' ) ) { wp_schedule_event( time(), 'aenima_monthly', 'aenima_monthly_refresh' ); } flush_rewrite_rules(); } register_deactivation_hook( __FILE__, 'aenima_deactivate' ); function aenima_deactivate() { wp_clear_scheduled_hook( 'aenima_monthly_refresh' ); flush_rewrite_rules(); } // ── DEACTIVATION WARNING ─────────────────────────────────────────────────── add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'aenima_plugin_action_links' ); function aenima_plugin_action_links( $links ) { $settings_link = '' . esc_html__( 'Settings', 'aenima-ai-search-visibility') . ''; array_unshift( $links, $settings_link ); return $links; } add_action( 'admin_footer', 'aenima_deactivation_warning' ); function aenima_deactivation_warning() { $screen = get_current_screen(); if ( ! $screen || 'plugins' !== $screen->id ) { return; } $msg = implode( "\n", array( 'Deactivating Aenima - important:', '', 'Your Schema JSON-LD and llms.txt files will remain on your site.', 'They will no longer update automatically each month.', 'Your AI visibility will gradually become outdated.', '', 'Your Aenima subscription will continue to be billed unless you cancel at aenima.co.uk.', '', 'Are you sure you want to deactivate?', ) ); $js = 'jQuery(function($){' . 'var l = $("[data-plugin=\'aenima/aenima.php\'] .deactivate a");' . 'if(!l.length)return;' . 'l.on("click",function(e){if(!confirm(' . wp_json_encode( $msg ) . ')){e.preventDefault();}});' . '});'; wp_add_inline_script( 'jquery', $js ); } // ── CUSTOM CRON SCHEDULE — MONTHLY ──────────────────────────────────────── add_filter( 'cron_schedules', 'aenima_add_monthly_schedule' ); function aenima_add_monthly_schedule( $schedules ) { $schedules['aenima_monthly'] = array( 'interval' => 30 * DAY_IN_SECONDS, 'display' => esc_html__( 'Once a month', 'aenima-ai-search-visibility'), ); return $schedules; } // ── LICENCE VERIFICATION ─────────────────────────────────────────────────── /** * Check whether a token has been entered. * The API validates the token server-side on each call — no phone-home licence check. */ function aenima_has_token() { return ! empty( get_option( AENIMA_PREFIX . 'api_token', '' ) ); } // ── SCORE CHECK VIA AJAX ─────────────────────────────────────────────────── add_action( 'wp_ajax_aenima_run_score', 'aenima_ajax_run_score' ); function aenima_ajax_run_score() { check_ajax_referer( 'aenima_score_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( 'Unauthorised' ); } $domain = sanitize_text_field( get_option( AENIMA_PREFIX . 'url', home_url() ) ); $domain = preg_replace( '#^https?://#', '', $domain ); $domain = rtrim( $domain, '/' ); $response = wp_remote_post( AENIMA_API_BASE . '/check-domain', array( 'timeout' => 20, 'headers' => array( 'Content-Type' => 'application/json' ), 'body' => wp_json_encode( array( 'domain' => $domain ) ), ) ); if ( is_wp_error( $response ) ) { wp_send_json_error( 'Could not reach Aenima API. Please try again.' ); } $body = json_decode( wp_remote_retrieve_body( $response ), true ); if ( empty( $body['overall'] ) && $body['overall'] !== 0 ) { wp_send_json_error( 'Score check failed. Please try again.' ); } // Cache the score update_option( AENIMA_PREFIX . 'last_score', intval( $body['overall'] ) ); update_option( AENIMA_PREFIX . 'last_issues', wp_json_encode( $body['issues'] ?? array() ) ); update_option( AENIMA_PREFIX . 'last_updated', date_i18n( get_option( 'date_format' ) ) ); wp_send_json_success( $body ); } // ── ENQUEUE ADMIN SCRIPTS ────────────────────────────────────────────────── add_action( 'admin_enqueue_scripts', 'aenima_settings_styles' ); function aenima_settings_styles( $hook ) { if ( 'settings_page_aenima' !== $hook ) { return; } $css = '#aenima-wrap { font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif; } #aenima-wrap * { box-sizing:border-box; } .ae-row { display:grid; grid-template-columns:1fr 1fr 1fr; gap:16px; margin-bottom:16px; } .ae-row-2 { display:grid; grid-template-columns:1fr 1fr; gap:16px; margin-bottom:16px; } .ae-row-full { margin-bottom:16px; } .ae-card { background:#fff; border:1px solid #e0e0e0; border-radius:10px; padding:22px; } .ae-card h2 { font-size:16px; font-weight:700; color:#111; margin:0 0 4px; } .ae-card p.ae-sub { font-size:14px; color:#444; margin:0 0 16px; line-height:1.6; } .ae-label { display:block; font-size:13px; font-weight:600; color:#222; margin-bottom:5px; } .ae-input { width:100%; padding:9px 12px; border:1px solid #ccc; border-radius:6px; font-size:14px; font-family:inherit; color:#111; } .ae-input:focus { outline:none; border-color:#F05A22; box-shadow:0 0 0 2px rgba(221,88,39,0.15); } .ae-check-row { display:flex; align-items:flex-start; gap:10px; margin-bottom:12px; } .ae-check-row input[type=checkbox] { width:17px; height:17px; margin-top:2px; flex-shrink:0; accent-color:#F05A22; } .ae-check-row .ae-check-text strong { font-size:14px; color:#111; display:block; margin-bottom:2px; } .ae-check-row .ae-check-text span { font-size:13px; color:#444; line-height:1.5; } .ae-save-row { display:grid; grid-template-columns:1fr 1fr 1fr; gap:12px; margin-bottom:16px; } .ae-save-btn { display:flex; flex-direction:column; align-items:center; justify-content:center; text-align:center; padding:14px 16px; border-radius:8px; font-family:inherit; font-weight:700; cursor:pointer; text-decoration:none; border:none; min-height:64px; font-size:14px; line-height:1.3; } .ae-save-btn-primary { background:#F05A22; color:#fff; } .ae-save-btn-primary:hover { background:#C04820; color:#fff; } .ae-save-btn-secondary { background:#fff; color:#333; border:2px solid #ddd; } .ae-save-btn-secondary:hover { border-color:#F05A22; color:#F05A22; } .ae-save-btn small { font-size:11px; font-weight:400; opacity:0.75; display:block; margin-top:3px; } .ae-badge { font-size:12px; font-weight:700; padding:3px 10px; border-radius:20px; display:inline-block; } .ae-section-title { font-size:11px; font-weight:700; letter-spacing:2px; text-transform:uppercase; color:#777; margin:0 0 12px; }'; wp_add_inline_style( 'wp-admin', $css ); } add_action( 'admin_enqueue_scripts', 'aenima_admin_scripts' ); function aenima_admin_scripts( $hook ) { if ( 'settings_page_aenima' !== $hook ) { return; } wp_localize_script( 'jquery', 'aenima_ajax', array( 'ajax_url' => admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'aenima_score_nonce' ), 'init_score' => get_option( AENIMA_PREFIX . 'last_score', '' ), ) ); wp_add_inline_style( 'wp-admin', '.ae-faq details{border-bottom:1px solid #eee;padding:8px 0}.ae-faq details:last-child{border-bottom:none}.ae-faq summary{font-size:13px;font-weight:700;color:#333;cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center}.ae-faq summary::after{content:"+";color:#F05A22;font-size:16px;flex-shrink:0}.ae-faq details[open] summary::after{content:"-"}.ae-faq details p{font-size:13px;color:#666;line-height:1.6;margin:8px 0 0;padding-left:2px}' ); } // ── SUPPRESS THIRD-PARTY NOTICES ON OUR PAGE ────────────────────────────── add_action( 'admin_head', 'aenima_suppress_notices' ); function aenima_suppress_notices() { $screen = get_current_screen(); if ( ! $screen || 'settings_page_aenima' !== $screen->id ) { return; } // Remove all admin notices from other plugins/themes on our page remove_all_actions( 'admin_notices' ); remove_all_actions( 'all_admin_notices' ); // Re-add only ours add_action( 'admin_notices', 'aenima_admin_notices' ); } // ── HIGHLIGHT AENIMA IN SETTINGS MENU ───────────────────────────────────── add_action( 'admin_enqueue_scripts', 'aenima_menu_highlight_style' ); function aenima_menu_highlight_style() { $css = '#adminmenu a[href="options-general.php?page=aenima"]{background:#F05A22 !important;color:#FFFFFF !important;font-weight:700 !important;border-radius:4px !important}#adminmenu a[href="options-general.php?page=aenima"]:hover{background:#C04820 !important}'; wp_add_inline_style( 'wp-admin', $css ); } add_action( 'admin_init', 'aenima_register_settings' ); function aenima_register_settings() { $fields = array( 'api_token', 'business_name', 'business_type', 'description', 'url', 'phone', 'email', 'street', 'town', 'county', 'postcode', 'founded', 'price_range', 'services', 'areas', 'ch_number', 'sameas_google', 'sameas_linkedin', 'sameas_facebook', 'schema_enabled', 'llms_enabled', 'faq_enabled', ); foreach ( $fields as $field ) { register_setting( 'aenima_settings_group', AENIMA_PREFIX . $field, array( 'sanitize_callback' => 'sanitize_textarea_field' ) ); } } // ── ADMIN MENU ───────────────────────────────────────────────────────────── add_action( 'admin_menu', 'aenima_admin_menu' ); function aenima_admin_menu() { add_options_page( esc_html__( 'Aenima — AI Visibility', 'aenima-ai-search-visibility'), esc_html__( 'Aenima', 'aenima-ai-search-visibility'), 'manage_options', 'aenima', 'aenima_settings_page' ); } // ── DASHBOARD WIDGET ─────────────────────────────────────────────────────── add_action( 'wp_dashboard_setup', 'aenima_register_dashboard_widget' ); function aenima_register_dashboard_widget() { wp_add_dashboard_widget( 'aenima_score_widget', esc_html__( 'AI Visibility — Aenima', 'aenima-ai-search-visibility'), 'aenima_dashboard_widget_render' ); } function aenima_dashboard_widget_render() { $score = get_option( AENIMA_PREFIX . 'last_score', '' ); $updated = get_option( AENIMA_PREFIX . 'last_updated', '' ); $next_run = wp_next_scheduled( 'aenima_monthly_refresh' ); $settings = admin_url( 'options-general.php?page=aenima' ); if ( 'active' !== $status ) { echo '
'; echo '' . esc_html__( 'Aenima subscription required', 'aenima-ai-search-visibility') . '
'; echo '' . esc_html__( 'Enter your API token in settings to activate AI visibility.', 'aenima-ai-search-visibility') . '
'; echo '' . esc_html__( 'Go to settings →', 'aenima-ai-search-visibility') . ''; echo '
'; return; } $score_colour = ''; $score_label = ''; if ( '' !== $score ) { $s = intval( $score ); if ( $s < 30 ) { $score_colour = '#CC2200'; $score_label = __( 'Not visible to AI search', 'aenima-ai-search-visibility'); } elseif ( $s < 55 ) { $score_colour = '#CC6600'; $score_label = __( 'Limited AI visibility', 'aenima-ai-search-visibility'); } elseif ( $s < 80 ) { $score_colour = '#CC8800'; $score_label = __( 'Moderate visibility', 'aenima-ai-search-visibility'); } else { $score_colour = '#1A8A40'; $score_label = __( 'Good visibility', 'aenima-ai-search-visibility'); } } echo '
'; if ( '' !== $score ) { $s = intval( $score ); $offset = 239 - ( $s / 100 ) * 239; echo '
'; echo ''; echo ''; echo ''; echo ''; echo '
'; echo '
' . esc_html( $score ) . '
'; echo '
/100
'; echo '
'; echo '
'; echo '
'; echo '
' . esc_html( $score_label ) . '
'; if ( $updated ) { echo '
' . esc_html__( 'Last checked:', 'aenima-ai-search-visibility') . ' ' . esc_html( $updated ) . '
'; } if ( $next_run ) { echo '
' . esc_html__( 'Next update:', 'aenima-ai-search-visibility') . ' ' . esc_html( date_i18n( get_option( 'date_format' ), $next_run ) ) . '
'; } echo '
'; } else { echo '
' . esc_html__( 'No score yet. Go to Settings → Aenima to check your AI visibility score.', 'aenima-ai-search-visibility') . '
'; } echo '
'; echo '
'; echo '' . esc_html__( 'Open Aenima dashboard →', 'aenima-ai-search-visibility') . ''; echo '' . esc_html__( 'Settings', 'aenima-ai-search-visibility') . ''; echo '
'; } // ── SETTINGS PAGE ────────────────────────────────────────────────────────── function aenima_settings_page() { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'You do not have permission to access this page.', 'aenima-ai-search-visibility') ); } $notice = ''; $notice_type = 'updated'; // Handle form save. if ( isset( $_POST['aenima_save_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['aenima_save_nonce'] ) ), 'aenima_save_settings' ) ) { // API token — save first then verify. $new_token = isset( $_POST[ AENIMA_PREFIX . 'api_token' ] ) ? sanitize_text_field( wp_unslash( $_POST[ AENIMA_PREFIX . 'api_token' ] ) ) : ''; update_option( AENIMA_PREFIX . 'api_token', $new_token ); $fields = array( 'business_name', 'business_type', 'description', 'url', 'phone', 'email', 'street', 'town', 'county', 'postcode', 'founded', 'price_range', 'services', 'areas', 'ch_number', 'sameas_google', 'sameas_linkedin', 'sameas_facebook', ); // Data guard — require business name and town before saving. $guard_name = isset( $_POST[ AENIMA_PREFIX . 'business_name' ] ) ? trim( sanitize_text_field( wp_unslash( $_POST[ AENIMA_PREFIX . 'business_name' ] ) ) ) : ''; $guard_town = isset( $_POST[ AENIMA_PREFIX . 'town' ] ) ? trim( sanitize_text_field( wp_unslash( $_POST[ AENIMA_PREFIX . 'town' ] ) ) ) : ''; if ( empty( $guard_name ) || empty( $guard_town ) ) { $notice = __( 'Please fill in Business Name and Town before saving — AI search engines need these to identify your business.', 'aenima-ai-search-visibility'); $notice_type = 'error'; } else { foreach ( $fields as $field ) { $raw = isset( $_POST[ AENIMA_PREFIX . $field ] ) ? sanitize_textarea_field( wp_unslash( $_POST[ AENIMA_PREFIX . $field ] ) ) : ''; update_option( AENIMA_PREFIX . $field, $raw ); } update_option( AENIMA_PREFIX . 'schema_enabled', isset( $_POST[ AENIMA_PREFIX . 'schema_enabled' ] ) ? '1' : '' ); update_option( AENIMA_PREFIX . 'llms_enabled', isset( $_POST[ AENIMA_PREFIX . 'llms_enabled' ] ) ? '1' : '' ); update_option( AENIMA_PREFIX . 'faq_enabled', isset( $_POST[ AENIMA_PREFIX . 'faq_enabled' ] ) ? '1' : '' ); if ( aenima_has_token() ) { aenima_write_llms_txt(); update_option( AENIMA_PREFIX . 'last_updated', date_i18n( get_option( 'date_format' ) ) ); $notice = __( 'Settings saved. Schema and llms.txt updated. ✓', 'aenima-ai-search-visibility'); } else { $notice = __( 'Settings saved. Add your API token from aenima.co.uk to generate your files.', 'aenima-ai-search-visibility'); } } // end data guard else } $last_score = get_option( AENIMA_PREFIX . 'last_score', '' ); $last_updated = get_option( AENIMA_PREFIX . 'last_updated', '' ); $next_run = wp_next_scheduled( 'aenima_monthly_refresh' ); $g = function( $key ) { return esc_attr( get_option( AENIMA_PREFIX . $key, '' ) ); }; $business_types = array( 'LocalBusiness' => 'Local Business (generic)', 'Plumber' => 'Plumber', 'Electrician' => 'Electrician', 'GeneralContractor' => 'Builder / Contractor', 'RoofingContractor' => 'Roofer', 'Plasterer' => 'Plasterer', 'LegalService' => 'Solicitor / Legal Service', 'AccountingService' => 'Accountant', 'FinancialService' => 'Financial Adviser', 'Architect' => 'Architect', 'Dentist' => 'Dentist', 'Physician' => 'Doctor / GP', 'Optician' => 'Optician', 'Physiotherapist' => 'Physiotherapist', 'Osteopath' => 'Osteopath', 'VeterinaryCare' => 'Vet', 'Restaurant' => 'Restaurant / Café', 'Store' => 'Shop / Retail', 'AutoRepair' => 'Mechanic / Auto Repair', 'HVACBusiness' => 'Heating Engineer / HVAC', 'LandscapingBusiness' => 'Gardener / Landscaper', 'MovingCompany' => 'Removal Company', 'CleaningService' => 'Cleaning Service', 'Locksmith' => 'Locksmith', 'Painter' => 'Painter & Decorator', 'RealEstateAgent' => 'Estate Agent', 'InsuranceAgency' => 'Insurance Broker', 'TravelAgency' => 'Travel Agent', 'ChildCare' => 'Childcare / Nursery', 'BeautySalon' => 'Beauty / Hair Salon', 'GymOrHealthClub' => 'Gym / Fitness', 'SportsActivityLocation'=> 'Sports / Leisure', ); $stored_issues = get_option( AENIMA_PREFIX . 'last_issues', '' ); $issues_arr = $stored_issues ? json_decode( $stored_issues, true ) : array(); ?>
Aenima
· technicalgraffiti.co.uk

/100

✓

01
02
03
04
please wait...'; var xhr=new XMLHttpRequest(); xhr.open('POST',aenima_ajax.ajax_url,true); xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded'); xhr.onload=function(){ btn.disabled=false; btn.innerHTML='↻ RE-CHECK
YOUR SCORE'; try{ var r=JSON.parse(xhr.responseText); if(r.success&&r.data){ aenimaSetDisc(r.data.overall); var iss=r.data.issues||[]; if(!iss.length){list.innerHTML='

✓ No critical issues — your AI visibility is clean.

';} else{ var h=''; iss.slice(0,5).forEach(function(i){ var bg=i.p==='critical'?'rgba(204,34,0,0.2)':'rgba(204,102,0,0.2)',cl=i.p==='critical'?'#FF6B6B':'#FFB347'; h+='
'+i.p.toUpperCase()+''+i.t+'
'; }); list.innerHTML=h; } }else{list.innerHTML='

'+(r.data||'Check failed — please try again.')+'

';} }catch(e){list.innerHTML='

Unexpected error. Please try again.

';} }; xhr.onerror=function(){btn.disabled=false;btn.innerHTML='↻ RE-CHECK
YOUR SCORE';list.innerHTML='

Network error. Please try again.

';}; xhr.send('action=aenima_run_score&nonce='+aenima_ajax.nonce); } window.addEventListener('DOMContentLoaded',function(){if(aenimaInitScore!==null)setTimeout(function(){aenimaSetDisc(aenimaInitScore);},300);}); AENIMA_JS ); ?>

aenima.co.uk

✓

—

>
>
>



', 'aenima-ai-search-visibility'); ?> ', 'aenima-ai-search-visibility'); ?>
·
$type, '@id' => $biz_id, 'name' => $name, 'url' => $base_url, 'dateModified' => $today, // Gemini signal 3 ); if ( $desc ) $business['description'] = $desc; if ( $phone ) $business['telephone'] = $phone; if ( $email ) $business['email'] = $email; if ( $price ) $business['priceRange'] = $price; if ( $founded ) $business['foundingDate'] = $founded; $address = array( '@type' => 'PostalAddress', 'addressCountry' => 'GB' ); if ( $street ) $address['streetAddress'] = $street; if ( $town ) $address['addressLocality'] = $town; if ( $county ) $address['addressRegion'] = $county; if ( $postcode ) $address['postalCode'] = $postcode; $business['address'] = $address; if ( ! empty( $areas ) ) { $business['areaServed'] = array_values( array_map( function( $a ) { return array( '@type' => 'City', 'name' => $a ); }, $areas ) ); } // Gemini signal 1: knowsAbout with DefinedTerm $defined_terms = array( array( '@type' => 'DefinedTerm', 'name' => $type, 'description' => $desc ?: $name . ' providing services in ' . $town ), ); if ( ! empty( $services ) ) { foreach ( array_slice( array_values( $services ), 0, 5 ) as $svc ) { $defined_terms[] = array( '@type' => 'DefinedTerm', 'name' => $svc ); } } $business['knowsAbout'] = $defined_terms; // Gemini signal 4: sameAs with multiple sources + user-supplied links $same_as = array( $base_url ); if ( $town ) { $same_as[] = 'https://www.google.com/maps/search/' . rawurlencode( $name . ' ' . $town ); } $ch_number = sanitize_text_field( get_option( AENIMA_PREFIX . 'ch_number', '' ) ); $sameas_google = esc_url_raw( get_option( AENIMA_PREFIX . 'sameas_google', '' ) ); $sameas_linkedin = esc_url_raw( get_option( AENIMA_PREFIX . 'sameas_linkedin', '' ) ); $sameas_facebook = esc_url_raw( get_option( AENIMA_PREFIX . 'sameas_facebook', '' ) ); if ( $ch_number ) { $ch_url = 'https://find-and-update.company-information.service.gov.uk/company/' . strtoupper( preg_replace( '/\s+/', '', $ch_number ) ); $same_as[] = $ch_url; $business['legalName'] = $name; $business['identifier'] = array( '@type' => 'PropertyValue', 'name' => 'Companies House', 'value' => $ch_number ); } if ( $sameas_google ) $same_as[] = $sameas_google; if ( $sameas_linkedin ) $same_as[] = $sameas_linkedin; if ( $sameas_facebook ) $same_as[] = $sameas_facebook; $business['sameAs'] = array_values( array_unique( $same_as ) ); // Gemini signal 2: hasOfferCatalog with PriceSpecification if ( ! empty( $services ) ) { $business['hasOfferCatalog'] = array( '@type' => 'OfferCatalog', 'name' => 'Services', 'itemListElement' => array_values( array_map( function( $s ) { return array( '@type' => 'Offer', 'itemOffered' => array( '@type' => 'Service', 'name' => $s ), 'priceSpecification' => array( '@type' => 'PriceSpecification', 'priceCurrency' => 'GBP', 'description' => 'Contact for pricing', ), ); }, $services ) ), ); } // ── WebSite node ─────────────────────────────────────────────────────── $website = array( '@type' => 'WebSite', '@id' => $base_url . '/#website', 'url' => $base_url, 'name' => $name, 'publisher' => array( '@id' => $biz_id ), 'inLanguage' => 'en-GB', 'dateModified' => $today, // Gemini signal 3 ); // ── @graph output ────────────────────────────────────────────────────── return array( '@context' => 'https://schema.org', '@graph' => array( $business, $website ), ); } // ── INJECT SCHEMA ────────────────────────────────────────────────────────── add_action( 'wp_head', 'aenima_inject_schema' ); function aenima_inject_schema() { if ( ! get_option( AENIMA_PREFIX . 'schema_enabled' ) ) { return; } // Schema is injected regardless of licence status — // files already installed stay active. Only updates stop on cancellation. $schema = aenima_build_schema(); $json = wp_json_encode( $schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); if ( ! $json ) { return; } echo "\n\n"; echo '\n"; if ( get_option( AENIMA_PREFIX . 'faq_enabled' ) && is_singular() ) { aenima_inject_faq_schema(); } } // ── FAQ SCHEMA AUTO-DETECTION ────────────────────────────────────────────── function aenima_inject_faq_schema() { global $post; if ( ! $post || empty( $post->post_content ) ) { return; } $content = $post->post_content; $faqs = array(); preg_match_all( '/([^<]+\?)<\/strong><\/p>\s*

([^<]{20,})/s', $content, $m ); if ( ! empty( $m[1] ) ) { foreach ( $m[1] as $i => $q ) { $a = wp_strip_all_tags( $m[2][ $i ] ); if ( $q && strlen( $a ) > 20 ) { $faqs[] = array( 'q' => trim( $q ), 'a' => trim( $a ) ); } } } if ( empty( $faqs ) ) { return; } $faq_schema = array( '@context' => 'https://schema.org', '@type' => 'FAQPage', 'mainEntity' => array_map( function( $f ) { return array( '@type' => 'Question', 'name' => $f['q'], 'acceptedAnswer' => array( '@type' => 'Answer', 'text' => $f['a'] ), ); }, array_slice( $faqs, 0, 10 ) ), ); $json = wp_json_encode( $faq_schema, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); if ( ! $json ) { return; } echo '\n"; } // ── LLMS.TXT BUILDER ─────────────────────────────────────────────────────── function aenima_build_llms() { $get = function( $key, $default = '' ) { return sanitize_text_field( get_option( AENIMA_PREFIX . $key, $default ) ); }; $name = $get( 'business_name', get_bloginfo( 'name' ) ); $desc = $get( 'description' ); $url = esc_url( get_option( AENIMA_PREFIX . 'url', home_url() ) ); $phone = $get( 'phone' ); $email = sanitize_email( get_option( AENIMA_PREFIX . 'email', '' ) ); $town = $get( 'town' ); $county = $get( 'county' ); $type = $get( 'business_type', 'LocalBusiness' ); $founded = $get( 'founded' ); $today = gmdate( 'Y-m-d' ); $base_url = rtrim( $url, '/' ); $services = array_filter( array_map( 'sanitize_text_field', explode( "\n", get_option( AENIMA_PREFIX . 'services', '' ) ) ) ); $areas = array_filter( array_map( 'sanitize_text_field', explode( "\n", get_option( AENIMA_PREFIX . 'areas', '' ) ) ) ); $location = implode( ', ', array_filter( array( $town, $county, 'UK' ) ) ); $first_area = ! empty( $areas ) ? reset( $areas ) : $location; // ── Header ───────────────────────────────────────────────────────────── $txt = "# {$name}\n"; $txt .= "# {$base_url}\n"; $txt .= "# Last updated: {$today}\n\n"; // ── Gemini signal 5: Quick Summary FRONT-LOADED ──────────────────────── // AI models chunk text — critical facts MUST be in first 100 tokens $txt .= "## Quick Summary\n\n"; $txt .= "{$name} is a {$type} based in {$first_area}."; if ( ! empty( $services ) ) { $top = implode( ', ', array_slice( array_values( $services ), 0, 3 ) ); $txt .= " Services include: {$top}."; } if ( $phone ) $txt .= " Phone: {$phone}."; $txt .= "\n\n"; // ── Full description ─────────────────────────────────────────────────── if ( $desc ) $txt .= "{$desc}\n\n"; // ── Services ─────────────────────────────────────────────────────────── if ( ! empty( $services ) ) { $txt .= "## Services\n\n"; foreach ( $services as $s ) $txt .= "- {$s}\n"; $txt .= "\n"; } // ── Service areas ────────────────────────────────────────────────────── if ( ! empty( $areas ) ) { $txt .= "## Service areas\n\n" . implode( ', ', $areas ) . "\n\n"; } // ── AI Visibility ────────────────────────────────────────────────────── $txt .= "## AI Visibility\n\n"; $txt .= "This business is optimised for GEO (Generative Engine Optimisation) and AEO (Answer Engine Optimisation). "; $txt .= "Schema markup, llms.txt, and robots.txt AI crawler permissions are in place.\n\n"; // ── Related entities — Gemini signal 4 (sameAs context) ─────────────── $txt .= "## Related entities\n\n"; $txt .= "- Website: {$base_url}\n"; $txt .= "- AI Visibility tool: https://aenima.co.uk\n"; $txt .= "- Parent consultancy: https://technicalgraffiti.co.uk\n\n"; // ── Contact ──────────────────────────────────────────────────────────── $txt .= "## Contact\n\n"; if ( $phone ) $txt .= "- Phone: {$phone}\n"; if ( $email ) $txt .= "- Email: {$email}\n"; $txt .= "- Website: {$base_url}\n"; return $txt; } // ── WRITE LLMS.TXT ───────────────────────────────────────────────────────── function aenima_write_llms_txt() { if ( ! get_option( AENIMA_PREFIX . 'llms_enabled' ) ) { return; } global $wp_filesystem; if ( empty( $wp_filesystem ) ) { require_once ABSPATH . 'wp-admin/includes/file.php'; // ABSPATH usage permitted here — WP core include WP_Filesystem(); } $upload = wp_upload_dir(); $path = trailingslashit( $upload['basedir'] ) . 'llms.txt'; $content = aenima_build_llms(); $wp_filesystem->put_contents( $path, $content, FS_CHMOD_FILE ); } // ── MONTHLY REFRESH CRON ─────────────────────────────────────────────────── add_action( 'aenima_monthly_refresh', 'aenima_run_monthly_refresh' ); function aenima_run_monthly_refresh() { // Regenerate files for all active subscribers — token validation is handled server-side. if ( ! aenima_has_token() ) { return; } aenima_write_llms_txt(); update_option( AENIMA_PREFIX . 'last_updated', date_i18n( get_option( 'date_format' ) ) ); update_option( AENIMA_PREFIX . 'last_refresh_status', 'ok_' . gmdate( 'Y-m-d' ) ); } // ── SERVE LLMS.TXT VIA REWRITE (fallback if file write fails) ───────────── add_action( 'init', 'aenima_add_rewrite' ); function aenima_add_rewrite() { add_rewrite_rule( '^llms\.txt$', 'index.php?aenima_llms=1', 'top' ); } add_filter( 'query_vars', 'aenima_query_vars' ); function aenima_query_vars( $vars ) { $vars[] = 'aenima_llms'; return $vars; } add_action( 'template_redirect', 'aenima_serve_llms' ); function aenima_serve_llms() { if ( ! intval( get_query_var( 'aenima_llms' ) ) ) { return; } if ( ! get_option( AENIMA_PREFIX . 'llms_enabled' ) ) { status_header( 404 ); exit; } header( 'Content-Type: text/plain; charset=utf-8' ); header( 'Cache-Control: public, max-age=86400' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo aenima_build_llms(); exit; } // ── ROBOTS.TXT REFERENCE ────────────────────────────────────────────────── add_filter( 'robots_txt', 'aenima_robots_txt', 10, 1 ); function aenima_robots_txt( $output ) { $output .= "\n# Aenima — AI Visibility\n"; $output .= '# llms.txt: ' . esc_url( home_url( '/llms.txt' ) ) . "\n"; return $output; } // ── ADMIN NOTICES ────────────────────────────────────────────────────────── add_action( 'admin_notices', 'aenima_admin_notices' ); function aenima_admin_notices() { $screen = get_current_screen(); $url = admin_url( 'options-general.php?page=aenima' ); // Welcome notice — shown once after activation on any admin page. if ( get_option( 'aenima_show_welcome' ) === '1' ) { delete_option( 'aenima_show_welcome' ); echo '

'; echo '

Aenima is installed. ' . esc_html__( 'One more step to activate AI visibility for this website.', 'aenima-ai-search-visibility') . '

'; echo '

' . esc_html__( 'Go to Settings → Aenima, enter your API token from your Aenima account, fill in your business details and click Save. That\'s it — your site will be AI-visible in under 2 minutes.', 'aenima-ai-search-visibility') . '

'; echo '' . esc_html__( 'Go to Settings → Aenima →', 'aenima-ai-search-visibility') . ''; echo '
'; return; } // Don't show further notices on our own settings page. if ( $screen && 'settings_page_aenima' === $screen->id ) { return; } $token = get_option( AENIMA_PREFIX . 'api_token', '' ); $phone = get_option( AENIMA_PREFIX . 'phone', '' ); $town = get_option( AENIMA_PREFIX . 'town', '' ); // No token — highest priority. if ( empty( $token ) ) { echo '
'; echo '

' . esc_html__( 'Aenima — action needed:', 'aenima-ai-search-visibility') . ' '; echo esc_html__( 'Your site is not yet AI-visible. Enter your Aenima API token to activate. ', 'aenima-ai-search-visibility'); echo '' . esc_html__( 'Settings → Aenima →', 'aenima-ai-search-visibility') . '

'; echo '
'; return; } // Subscription lapsed. if ( 'inactive' === $status ) { echo '
'; echo '

' . esc_html__( 'Aenima — subscription expired:', 'aenima-ai-search-visibility') . ' '; echo esc_html__( 'Your AI visibility files have stopped updating. Renew your plan to restore automatic updates. ', 'aenima-ai-search-visibility'); echo '' . esc_html__( 'Renew at aenima.co.uk →', 'aenima-ai-search-visibility') . '

'; echo '
'; return; } // Active but incomplete setup. if ( 'active' === $status && ( ! $phone || ! $town ) ) { echo '
'; echo '

' . esc_html__( 'Aenima — setup incomplete:', 'aenima-ai-search-visibility') . ' '; echo esc_html__( 'Phone number and town are missing. AI search engines need these to recommend your business. ', 'aenima-ai-search-visibility'); echo '' . esc_html__( 'Complete setup →', 'aenima-ai-search-visibility') . '

'; echo '
'; } }