admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'aije_insert_link' ) ) ) . ';', 'before' ); } } /* ===== Admin-Menü ===== */ public function tools_menu() { add_management_page( esc_html__( 'WP Rankify', 'ai-json-extractor-auto-embed-lite' ), esc_html__( 'WP Rankify', 'ai-json-extractor-auto-embed-lite' ), 'manage_options', 'aije-lite', array( $this, 'render_tools' ) ); } public function render_tools() { if ( ! current_user_can( 'manage_options' ) ) { return; } $licensed = self::license_is_valid(); $tabs = array( 'dashboard' => esc_html__( 'Dashboard', 'ai-json-extractor-auto-embed-lite' ), 'settings' => esc_html__( 'Einstellungen', 'ai-json-extractor-auto-embed-lite' ), 'tracking' => esc_html__( 'Tracking & Analytics', 'ai-json-extractor-auto-embed-lite' ), 'gsc' => esc_html__( 'Google Suche', 'ai-json-extractor-auto-embed-lite' ), 'llms' => esc_html__( 'llms.txt', 'ai-json-extractor-auto-embed-lite' ), 'license' => esc_html__( 'Lizenz', 'ai-json-extractor-auto-embed-lite' ), ); $tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'dashboard'; echo '
'; echo '

' . esc_html__( 'WP Rankify', 'ai-json-extractor-auto-embed-lite' ) . ' (AI Auto Embed)

'; echo ''; echo '

⭐ ' . esc_html__( 'WP Rankify bewerten', 'ai-json-extractor-auto-embed-lite' ) . '

'; if ( $licensed ) { echo '

' . esc_html__( 'Lizenz aktiv.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } $admin_dir = plugin_dir_path( AIJE_PLUGIN_FILE ) . 'admin/'; switch ( $tab ) { case 'dashboard': require $admin_dir . 'tab-dashboard.php'; break; case 'gsc': require $admin_dir . 'tab-gsc.php'; break; case 'llms': require $admin_dir . 'tab-llms.php'; break; case 'license': require $admin_dir . 'tab-license.php'; break; case 'tracking': require $admin_dir . 'tab-tracking.php'; break; case 'settings': default: require $admin_dir . 'tab-settings.php'; break; } echo '
'; } /* ===== Metaboxen ===== */ public function add_score_metabox() { foreach ( $this->get_opts()['enabled_post_types'] as $t ) { add_meta_box( 'aije_score', esc_html__( 'WP Rankify – Readiness Score', 'ai-json-extractor-auto-embed-lite' ), array( $this, 'render_score_metabox' ), $t, 'side', 'high' ); } } public function render_score_metabox( $post ) { $analysis = $this->calculate_ai_analysis( $post ); $score = $analysis['score']; $cats = $analysis['categories']; wp_nonce_field( 'aije_ai_nonce', 'aije_ai_nonce_field' ); $color = $score >= 75 ? '#27ae60' : ( $score >= 50 ? '#e67e22' : '#e74c3c' ); $label = $score >= 75 ? __( 'Gut', 'ai-json-extractor-auto-embed-lite' ) : ( $score >= 50 ? __( 'Optimierbar', 'ai-json-extractor-auto-embed-lite' ) : __( 'Kritisch', 'ai-json-extractor-auto-embed-lite' ) ); echo '
'; echo '
' . esc_html( $score ) . '
'; echo '
' . esc_html( $label ) . '
'; echo '
'; echo '
' . esc_html__( 'Kategorien', 'ai-json-extractor-auto-embed-lite' ) . '
'; $bar_colors = array( 'content' => '#3498db', 'eeat' => '#9b59b6', 'technical' => '#1abc9c', 'linking' => '#e67e22' ); $link_stats = $this->get_link_stats( $post->ID ); foreach ( $cats as $key => $cat ) { $bar_color = $bar_colors[ $key ] ?? '#999'; echo '
'; echo '
'; echo '' . esc_html( $cat['label'] ) . ' (' . esc_html( $cat['weight'] ) . '%)'; if ( 'linking' === $key ) { $tip = sprintf( /* translators: 1: aktuelle Links, 2: empfohlene Links, 3: Wortanzahl */ __( 'Faustregel: ca. 1 interner Link pro 200–250 Wörter. Bei %3$d Wörtern werden ~%2$d empfohlen, aktuell sind es %1$d.', 'ai-json-extractor-auto-embed-lite' ), $link_stats['links'], $link_stats['recommended'], $link_stats['word_count'] ); echo ' — 🔗 ' . esc_html( $link_stats['links'] ) . '/' . esc_html( $link_stats['recommended'] ); echo $link_stats['remaining'] > 0 ? ' · ' . esc_html( sprintf( _n( 'noch %d sinnvoll', 'noch %d sinnvoll', $link_stats['remaining'], 'ai-json-extractor-auto-embed-lite' ), $link_stats['remaining'] ) ) : ' · ' . esc_html__( 'Empfehlung erreicht', 'ai-json-extractor-auto-embed-lite' ); echo ''; } echo ''; echo '' . esc_html( $cat['score'] ) . ''; echo '
'; echo '
'; echo '
'; } if ( ! empty( $analysis['issues'] ) ) { echo '
'; echo '
' . esc_html__( 'Optimierungspotenzial', 'ai-json-extractor-auto-embed-lite' ) . '
'; $severity_styles = array( 'high' => 'background:#fdecea;color:#c0392b;', 'medium' => 'background:#fef9e7;color:#b7770d;', 'low' => 'background:#eafaf1;color:#1e8449;' ); $severity_labels = array( 'high' => __( 'Hoch', 'ai-json-extractor-auto-embed-lite' ), 'medium' => __( 'Mittel', 'ai-json-extractor-auto-embed-lite' ), 'low' => __( 'Gering', 'ai-json-extractor-auto-embed-lite' ) ); $cat_icons = array( 'content' => '✍', 'eeat' => '🏅', 'technical' => '⚙', 'linking' => '🔗' ); $all_advice = array(); foreach ( $analysis['issues'] as $idx => $issue ) { $all_advice[ $idx ] = $this->build_issue_advice( $issue, $post, $analysis ); } $total_issues = count( $analysis['issues'] ); $scrollable = $total_issues > 3; $max_h = $scrollable ? 'max-height:340px;overflow-y:auto;padding-right:4px;' : ''; echo '
'; foreach ( $analysis['issues'] as $idx => $issue ) { $sev_style = $severity_styles[ $issue['severity'] ] ?? ''; $sev_label = $severity_labels[ $issue['severity'] ] ?? ''; $icon = $cat_icons[ $issue['category'] ] ?? '•'; $border_c = $bar_colors[ $issue['category'] ] ?? '#ccc'; echo '
'; echo '
'; echo '' . esc_html( $icon ) . ' ' . esc_html( $issue['msg'] ) . ''; echo '' . esc_html( $sev_label ) . ''; echo '
'; echo ''; echo '
'; } echo '
'; if ( $scrollable ) { echo '
' . sprintf( esc_html__( '%d Hinweise – scrollen ↕', 'ai-json-extractor-auto-embed-lite' ), $total_issues ) . '
'; } echo ''; } $this->render_inbound_links_box( $this->get_inbound_link_report( $post ), $post->ID ); $this->render_meta_generator_box( $post ); $this->render_topic_analysis_box( $post ); // Advice-Overlay + JS aus separater Datei require plugin_dir_path( AIJE_PLUGIN_FILE ) . 'admin/metabox-overlay.php'; } /** * "Wer verlinkt hierher?" — zeigt, welche anderen Beiträge bereits auf * diesen hier verlinken, und welche thematisch passenden Beiträge das * noch nicht tun (Lücken für gezieltes internes Verlinken). */ private function render_inbound_links_box( $inbound, $post_id ) { $D = 'ai-json-extractor-auto-embed-lite'; echo '
'; echo '
🔗 ' . esc_html__( 'Wer verlinkt hierher?', $D ) . '
'; // Wie oft verlinkt DIESER Beitrag selbst schon auf andere Seiten // (ausgehend) — unabhängig von der Frage, wer auf ihn zurückverlinkt. // Plus Empfehlung nach Faustregel (~1 Link/200–250 Wörter). $own_stats = $this->get_link_stats( $post_id ); echo '
📊 ' . esc_html( sprintf( _n( 'Dieser Beitrag verlinkt selbst aktuell auf %d anderen Beitrag', 'Dieser Beitrag verlinkt selbst aktuell auf %d andere Beiträge', $own_stats['links'], $D ), $own_stats['links'] ) ); echo ' (' . ( $own_stats['remaining'] > 0 ? esc_html( sprintf( _n( 'noch %d sinnvoll, Ziel ~%d', 'noch %d sinnvoll, Ziel ~%d', $own_stats['remaining'], $D ), $own_stats['remaining'], $own_stats['recommended'] ) ) : esc_html__( 'Empfehlung erreicht', $D ) ) . ').
'; if ( ! empty( $inbound['linking_from'] ) ) { $count = count( $inbound['linking_from'] ); echo '
✓ ' . esc_html( sprintf( _n( '%d Beitrag verlinkt bereits hierher:', '%d Beiträge verlinken bereits hierher:', $count, $D ), $count ) ) . '
'; echo ''; } else { echo '
✗ ' . esc_html__( 'Noch kein anderer Beitrag verlinkt hierher.', $D ) . '
'; } if ( ! empty( $inbound['missing_related'] ) ) { echo '
⚠ ' . esc_html__( 'Thematisch passend, verlinkt aber noch nicht:', $D ) . '
'; echo ''; echo '
' . esc_html__( '„Backlink setzen“ bearbeitet direkt den anderen Beitrag – nicht diesen hier.', $D ) . '
'; $i18n_js = wp_json_encode( array( 'reload' => __( 'Bitte Seite neu laden.', $D ), 'inserting' => __( 'Wird eingefügt...', $D ), 'done' => __( '✓ Gesetzt!', $D ), 'error' => __( '✗ Fehler', $D ), ) ); echo ''; } } public function add_toggle_metabox() { foreach ( $this->get_opts()['enabled_post_types'] as $t ) { add_meta_box( 'aije_toggle', esc_html__( 'AI JSON – Ausgabe', 'ai-json-extractor-auto-embed-lite' ), array( $this, 'render_toggle_metabox' ), $t, 'side', 'default' ); } } public function add_ki_highlight_metabox() { foreach ( $this->get_opts()['enabled_post_types'] as $t ) { add_meta_box( 'aije_ki_highlight', esc_html__( 'WP Rankify – KI-Suche', 'ai-json-extractor-auto-embed-lite' ), array( $this, 'render_ki_highlight_metabox' ), $t, 'side', 'high' ); } } public function render_ki_highlight_metabox( $post ) { $active = get_post_meta( $post->ID, '_aije_ki_highlight', true ); $yoast = get_post_meta( $post->ID, '_yoast_wpseo_is_cornerstone', true ); $rankmath = get_post_meta( $post->ID, 'rank_math_pillar_content', true ); $via_seo = ! empty( $yoast ) || $rankmath === 'on'; wp_nonce_field( 'aije_ki_highlight', 'aije_ki_highlight_nonce' ); echo ''; if ( $via_seo ) { $via_label = ! empty( $yoast ) ? __( 'Yoast SEO (Cornerstone Content)', 'ai-json-extractor-auto-embed-lite' ) : __( 'Rank Math (Pillar Content)', 'ai-json-extractor-auto-embed-lite' ); echo '

✓ ' . sprintf( esc_html__( 'Bereits markiert in %s.', 'ai-json-extractor-auto-embed-lite' ), esc_html( $via_label ) ) . '

'; } } public function render_toggle_metabox( $post ) { $no = get_post_meta( $post->ID, self::META_NO_EMBED, true ); wp_nonce_field( 'aije_toggle', 'aije_toggle_nonce' ); echo ''; echo '

' . esc_html__( 'Deaktiviert JSON-Embed und Person-Schema für diesen Beitrag.', 'ai-json-extractor-auto-embed-lite' ) . '

'; } public function save_post_meta( $post_id ) { if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) { return; } if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } // Toggle (JSON-Embed deaktivieren) if ( isset( $_POST['aije_toggle_nonce'] ) && wp_verify_nonce( wp_unslash( $_POST['aije_toggle_nonce'] ), 'aije_toggle' ) ) { $no = ! empty( $_POST['aije_no_embed'] ) ? '1' : ''; if ( $no ) { update_post_meta( $post_id, self::META_NO_EMBED, '1' ); } else { delete_post_meta( $post_id, self::META_NO_EMBED ); } } // KI-Suche hervorheben if ( isset( $_POST['aije_ki_highlight_nonce'] ) && wp_verify_nonce( wp_unslash( $_POST['aije_ki_highlight_nonce'] ), 'aije_ki_highlight' ) ) { if ( ! empty( $_POST['aije_ki_highlight'] ) ) { update_post_meta( $post_id, '_aije_ki_highlight', '1' ); } else { delete_post_meta( $post_id, '_aije_ki_highlight' ); } delete_transient( 'aije_llms_txt' ); } } public function add_preview_metabox() { foreach ( $this->get_opts()['enabled_post_types'] as $t ) { add_meta_box( 'aije_preview', esc_html__( 'AI JSON – Vorschau (readonly)', 'ai-json-extractor-auto-embed-lite' ), array( 'AIJE_Lite_100', 'render_preview_metabox_cb' ), $t, 'side', 'default' ); } } public static function render_preview_metabox_cb( $post ) { $self = new self(); $data = $self->extract_payload( $post ); $flags = 0; if ( defined( 'JSON_UNESCAPED_UNICODE' ) ) { $flags |= JSON_UNESCAPED_UNICODE; } if ( defined( 'JSON_UNESCAPED_SLASHES' ) ) { $flags |= JSON_UNESCAPED_SLASHES; } if ( defined( 'JSON_PRETTY_PRINT' ) ) { $flags |= JSON_PRETTY_PRINT; } $json = function_exists( 'wp_json_encode' ) ? wp_json_encode( $data, $flags ) : json_encode( $data ); echo ''; $pto = get_post_type_object( $post->post_type ); $base = ( ! empty( $pto->rest_base ) ) ? $pto->rest_base : $post->post_type; $api_url = rest_url( 'wp/v2/' . $base . '/' . $post->ID ); if ( ! empty( $api_url ) ) { $url_out = ( $post->post_status === 'publish' ) ? $api_url : add_query_arg( 'context', 'edit', $api_url ); echo '

' . esc_html__( 'REST API öffnen', 'ai-json-extractor-auto-embed-lite' ) . '

'; } } /* ===== SEO-Meta-Box ===== */ public function add_seo_metabox() { $o = $this->get_opts(); $resolved = $this->get_active_seo_plugin(); if ( $resolved !== 'own' ) { return; } $conflict = ''; if ( defined( 'WPSEO_VERSION' ) ) { $conflict = 'Yoast SEO'; } if ( defined( 'RANK_MATH_VERSION' ) ) { $conflict = 'RankMath'; } if ( defined( 'AIOSEO_VERSION' ) ) { $conflict = 'AIOSEO'; } foreach ( $o['enabled_post_types'] as $t ) { add_meta_box( 'aije_seo_meta', __( 'WP Rankify – SEO', 'ai-json-extractor-auto-embed-lite' ) . ( $conflict ? ' ⚠ ' . sprintf( __( 'Konflikt mit %s', 'ai-json-extractor-auto-embed-lite' ), $conflict ) : '' ), array( $this, 'render_seo_metabox' ), $t, 'normal', 'high' ); } } public function render_seo_metabox( $post ) { wp_nonce_field( 'aije_seo_meta', 'aije_seo_meta_nonce' ); $conflict = ''; if ( defined( 'WPSEO_VERSION' ) ) { $conflict = 'Yoast SEO'; } if ( defined( 'RANK_MATH_VERSION' ) ) { $conflict = 'RankMath'; } if ( defined( 'AIOSEO_VERSION' ) ) { $conflict = 'AIOSEO'; } if ( $conflict ) { echo '
⚠ ' . sprintf( esc_html__( '%s ist noch aktiv.', 'ai-json-extractor-auto-embed-lite' ), esc_html( $conflict ) ) . ' ' . sprintf( esc_html__( 'Deaktiviere %s oder wähle in den', 'ai-json-extractor-auto-embed-lite' ), esc_html( $conflict ) ) . ' ' . esc_html__( 'Einstellungen', 'ai-json-extractor-auto-embed-lite' ) . ' ' . esc_html__( '„Auto-Erkennung".', 'ai-json-extractor-auto-embed-lite' ) . '
'; } $seo_title = get_post_meta( $post->ID, '_aije_seo_title', true ); $meta_desc = get_post_meta( $post->ID, '_aije_metadesc', true ); $robots = get_post_meta( $post->ID, '_aije_robots', true ) ?: 'index,follow'; $canonical = get_post_meta( $post->ID, '_aije_canonical', true ) ?: get_permalink( $post->ID ); $title_len = mb_strlen( $seo_title ); $desc_len = mb_strlen( $meta_desc ); $title_col = ( $title_len >= 50 && $title_len <= 65 ) ? '#22c55e' : ( $title_len > 0 ? '#f59e0b' : '#ef4444' ); $desc_col = ( $desc_len >= 120 && $desc_len <= 160 ) ? '#22c55e' : ( $desc_len > 0 ? '#f59e0b' : '#ef4444' ); echo '
'; echo '
' . sprintf( esc_html__( '%d / 65 Zeichen', 'ai-json-extractor-auto-embed-lite' ), $title_len ) . '
'; echo '
' . sprintf( esc_html__( '%d / 160 Zeichen', 'ai-json-extractor-auto-embed-lite' ), $desc_len ) . '
'; if ( ! empty( $seo_title ) || ! empty( $meta_desc ) ) { $purl = get_permalink( $post->ID ); echo '
' . esc_html__( 'Google-Vorschau', 'ai-json-extractor-auto-embed-lite' ) . '
' . esc_html( mb_substr( $seo_title ?: get_the_title( $post ), 0, 65 ) ) . '
' . esc_url( $purl ) . '
' . esc_html( mb_substr( $meta_desc, 0, 160 ) ) . '
'; } echo '
'; echo '
'; ?> $id !== $post_id ) ) ); wp_send_json_success(); } private function render_dashboard_list( $type, $filter = '' ) { $types = $this->get_opts()['enabled_post_types']; $excluded_ids = get_option( 'aije_excluded_posts', array() ); $posts = get_posts( array( 'post_type' => $types, 'posts_per_page' => -1, 'post_status' => 'publish', 'post__not_in' => $excluded_ids ?: array( 0 ) ) ); $colors = array( 'bad' => '#e74c3c', 'medium' => '#e67e22', 'good' => '#27ae60', 'filter' => '#0073aa' ); $filter_map = array( 'no_image' => array( 'no_featured_image' ), 'no_meta' => array( 'meta_desc_length_suboptimal', 'meta_desc_too_short', 'no_meta_desc' ), 'too_short' => array( 'content_too_short', 'content_slightly_short' ), 'no_eeat' => array( 'no_job_title' ), 'no_h2' => array( 'no_h2' ), 'no_internal' => array( 'no_internal_links' ), ); // Matching läuft über den stabilen 'key' aus trait-score.php, nicht über den (übersetzten) 'msg'-Text echo ''; } private function render_exclude_js() { ?>