esc_url_raw( rest_url( 'aiss/v1/' ) ), 'restNonce' => wp_create_nonce( 'wp_rest' ), 'adminNonce' => wp_create_nonce( 'aiss_admin_nonce' ), 'nonce' => wp_create_nonce( 'aiss_admin_nonce' ), 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'adminUrl' => admin_url(), 'siteName' => get_bloginfo( 'name' ), 'vigiaActive' => is_plugin_active( 'vigia/vigia.php' ) ? '1' : '0', 'platforms' => ayudawp_aiss_get_platforms_meta(), 'strings' => array( 'loading' => __( 'Loading...', 'ai-share-summarize' ), 'noData' => __( 'No data yet.', 'ai-share-summarize' ), 'loadMore' => __( 'Load more', 'ai-share-summarize' ), /* translators: %1$s = current count, %2$s = total count */ 'showingOf' => __( 'Showing %1$s of %2$s', 'ai-share-summarize' ), 'clicks' => __( 'Clicks', 'ai-share-summarize' ), 'aiCrawls' => __( 'AI Crawls', 'ai-share-summarize' ), 'edit' => __( 'Edit', 'ai-share-summarize' ), 'allTime' => __( 'All time', 'ai-share-summarize' ), 'today' => __( 'Today', 'ai-share-summarize' ), /* translators: %d = number of days */ 'lastDays' => __( 'Last %d days', 'ai-share-summarize' ), 'confirmDeleteAll' => __( 'Are you sure you want to delete ALL analytics data? This action cannot be undone.', 'ai-share-summarize' ), 'deleting' => __( 'Deleting...', 'ai-share-summarize' ), 'deleteSuccess' => __( 'All analytics data has been deleted.', 'ai-share-summarize' ), 'deleteError' => __( 'Error deleting data. Please try again.', 'ai-share-summarize' ), /* Translatable type labels for platforms table (v1.7.0) */ 'typeAI' => __( 'AI', 'ai-share-summarize' ), 'typeSocial' => __( 'Social', 'ai-share-summarize' ), /* Comparison and export strings (v1.7.0) */ 'previousPeriod' => __( 'Previous period', 'ai-share-summarize' ), 'currentPeriod' => __( 'Current period', 'ai-share-summarize' ), 'exportError' => __( 'Export failed. Please try again.', 'ai-share-summarize' ), /* translators: %1$s = range start, %2$s = range end, %3$s = total */ 'pagerRange' => __( '%1$s–%2$s of %3$s', 'ai-share-summarize' ), 'vs' => __( 'vs', 'ai-share-summarize' ), /* Per-button breakdown in the platforms table (v2.6.0) */ 'showPosts' => __( 'Show the posts it was clicked from', 'ai-share-summarize' ), 'postsForButton' => __( 'Posts it was clicked from', 'ai-share-summarize' ), 'topPostsOnly' => __( 'Only the 20 posts with the most clicks are listed. The CSV export has all of them.', 'ai-share-summarize' ), 'loadError' => __( 'Could not load the data. Please try again.', 'ai-share-summarize' ), ), ) ); // Inline script for activation notice dismissal. wp_add_inline_script( 'jquery', ' jQuery(document).ready(function($) { $(document).on("click", ".notice[data-notice=\"ayudawp-aiss-activation\"] .notice-dismiss", function() { $.post(ajaxurl, { action: "ayudawp_dismiss_activation_notice", nonce: "' . esc_js( wp_create_nonce( 'ayudawp_dismiss_notice' ) ) . '" }); }); $(document).on("click", ".aiss-dismiss-ai-error", function() { var btn = $(this); var notice = btn.closest(".aiss-ai-error-notice"); $.post(ajaxurl, { action: "ayudawp_aiss_dismiss_ai_error", nonce: btn.data("nonce") }, function(response) { if (response && response.success) { notice.slideUp(180, function() { notice.remove(); }); } }); }); }); ' ); } /** * Add settings link to plugins page * * @param array $links Plugin action links. * @return array Modified links. */ public function ayudawp_add_settings_link( $links ) { // Add Analytics link. $analytics_link = '' . esc_html__( 'Analytics', 'ai-share-summarize' ) . ''; array_unshift( $links, $analytics_link ); // Add Settings link (appears first / leftmost). $settings_link = '' . esc_html__( 'Settings', 'ai-share-summarize' ) . ''; array_unshift( $links, $settings_link ); return $links; } /** * Show activation notice */ public function ayudawp_activation_notice() { if ( get_current_screen()->id !== 'plugins' || get_option( 'ayudawp_aiss_activation_notice_dismissed' ) ) { return; } if ( get_transient( 'ayudawp_aiss_just_activated' ) ) { ?>

ayudawp_register_settings_fields(); } /** * Register settings fields */ private function ayudawp_register_settings_fields() { // field id => [ label, section ]. $fields = array( 'placements' => array( esc_html__( 'Where the buttons appear', 'ai-share-summarize' ), 'ayudawp_aiss_placement' ), 'floating_bar' => array( esc_html__( 'Floating bar', 'ai-share-summarize' ), 'ayudawp_aiss_placement' ), 'mobile_compact' => array( esc_html__( 'Compact mode on phones', 'ai-share-summarize' ), 'ayudawp_aiss_placement' ), 'enabled_buttons' => array( esc_html__( 'Enabled buttons', 'ai-share-summarize' ), 'ayudawp_aiss_main' ), 'button_colors' => array( esc_html__( 'Style and icons', 'ai-share-summarize' ), 'ayudawp_aiss_main' ), 'button_size' => array( esc_html__( 'Size and dark mode', 'ai-share-summarize' ), 'ayudawp_aiss_main' ), 'layout' => array( esc_html__( 'Alignment and separators', 'ai-share-summarize' ), 'ayudawp_aiss_main' ), 'button_order' => array( esc_html__( 'Order within each group', 'ai-share-summarize' ), 'ayudawp_aiss_main' ), 'title' => array( esc_html__( 'Title above the buttons', 'ai-share-summarize' ), 'ayudawp_aiss_texts' ), 'section_titles' => array( esc_html__( 'Section titles', 'ai-share-summarize' ), 'ayudawp_aiss_texts' ), 'prompt' => array( esc_html__( 'Prompt sent with every AI button', 'ai-share-summarize' ), 'ayudawp_aiss_prompt' ), 'accounts' => array( esc_html__( 'Accounts', 'ai-share-summarize' ), 'ayudawp_aiss_advanced' ), 'output' => array( esc_html__( 'Markup and campaign tracking', 'ai-share-summarize' ), 'ayudawp_aiss_advanced' ), 'seo_integration' => array( esc_html__( 'SEO integration', 'ai-share-summarize' ), 'ayudawp_aiss_advanced' ), 'data_retention' => array( esc_html__( 'Analytics data', 'ai-share-summarize' ), 'ayudawp_aiss_advanced' ), ); foreach ( $fields as $field_id => $field ) { add_settings_field( $field_id, $field[0], array( $this, 'ayudawp_' . $field_id . '_callback' ), 'ayudawp_aiss_settings', $field[1] ); } // AI Summary fields, grouped since 2.5.0. field id => [ label, section ]. $summary_fields = array( 'ai_summary_mode' => array( esc_html__( 'How summaries are generated', 'ai-share-summarize' ), 'ayudawp_aiss_ai_summary' ), 'ai_summary_model' => array( esc_html__( 'AI model', 'ai-share-summarize' ), 'ayudawp_aiss_ai_summary' ), 'ai_summary_placement' => array( esc_html__( 'Content types and position', 'ai-share-summarize' ), 'ayudawp_aiss_summary_where' ), 'ai_summary_look' => array( esc_html__( 'Appearance', 'ai-share-summarize' ), 'ayudawp_aiss_summary_block' ), 'ai_summary_wording' => array( esc_html__( 'Label and format', 'ai-share-summarize' ), 'ayudawp_aiss_summary_block' ), 'ai_summary_visitor' => array( esc_html__( 'Let visitors generate it', 'ai-share-summarize' ), 'ayudawp_aiss_summary_visitor' ), 'ai_summary_custom' => array( esc_html__( 'Content below the summary', 'ai-share-summarize' ), 'ayudawp_aiss_summary_custom' ), ); foreach ( $summary_fields as $field_id => $field ) { add_settings_field( $field_id, $field[0], array( $this, 'ayudawp_' . $field_id . '_callback' ), 'ayudawp_aiss_summary_settings', $field[1] ); } } /** * Admin page content with tabs */ public function ayudawp_admin_page() { $active_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'analytics'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- reading which settings tab to paint, not acting on anything; the value is only compared against a fixed list of tab slugs. $page_url = admin_url( 'options-general.php?page=ai-share-summarize' ); // Dynamic page title based on active tab. The buttons tab keeps the // legacy 'settings' slug so bookmarked/external links don't break; // only its visible label says "Share Buttons". $page_title = 'Share Buttons & AI-powered Summaries'; if ( 'analytics' === $active_tab ) { $page_title .= ' — ' . esc_html__( 'Analytics', 'ai-share-summarize' ); } elseif ( 'ai-summary' === $active_tab ) { $page_title .= ' — ' . esc_html__( 'AI Summary', 'ai-share-summarize' ); } elseif ( 'settings' === $active_tab ) { $page_title .= ' — ' . esc_html__( 'Share Buttons', 'ai-share-summarize' ); } ?>

ayudawp_render_summary_tab(); } else { $this->ayudawp_render_settings_tab(); } ?>
render( 'horizontal' ); } ?>
' . esc_html__( 'Configure how and where to display the share buttons. The inline AI summary has its own tab: AI Summary.', 'ai-share-summarize' ); echo ' (' . esc_html__( 'You can also customize display using shortcodes as described in the', 'ai-share-summarize' ) . ' ' . esc_html__( 'plugin page', 'ai-share-summarize' ) . ')'; echo '

'; } // ========================================== // Settings field callbacks // ========================================== /** * Enabled buttons field */ public function ayudawp_enabled_buttons_callback() { $options = get_option( 'ayudawp_aiss_options' ); $enabled = isset( $options['enabled_buttons'] ) ? $options['enabled_buttons'] : array(); if ( ! is_array( $enabled ) ) { $enabled = array(); } $buttons = ayudawp_aiss_get_available_buttons(); $social_keys = ayudawp_aiss_get_social_buttons(); $ai_keys = ayudawp_aiss_get_ai_buttons(); $actions = ayudawp_aiss_get_action_buttons(); /* * The picker renders each option as the real button (v2.5.0): same * markup, same classes, same stylesheet, so what the admin ticks is * what the visitor sees. It replaces the row of bare SVG glyphs, which * showed the icon but nothing about size, colour or shape. */ $style = isset( $options['button_colors'] ) ? $options['button_colors'] : 'minimal'; $icon_style = isset( $options['icon_style'] ) ? $options['icon_style'] : 'circular'; $custom_bg = isset( $options['custom_color_bg'] ) ? $options['custom_color_bg'] : ''; $custom_text = isset( $options['custom_color_text'] ) ? $options['custom_color_text'] : ''; $wrapper_classes = array( 'ayudawp-share-buttons', 'aiss-picker-preview' ); if ( 'icons-only' === $style ) { $wrapper_classes[] = 'icons-only'; $wrapper_classes[] = $icon_style; } elseif ( 'minimal' !== $style ) { $wrapper_classes[] = $style; } $wrapper_classes[] = 'with-icons'; $groups = array( 'social' => array( 'label' => esc_html__( 'Social networks', 'ai-share-summarize' ), 'keys' => $social_keys, ), 'ai' => array( 'label' => esc_html__( 'AI assistants', 'ai-share-summarize' ), 'keys' => $ai_keys, ), ); // Browser actions are listed apart: they do not open a destination. So // is the Google preferred source button (v2.6.0), which is not a share. $google = array( 'google_preferred' ); $groups['social']['keys'] = array_values( array_diff( $groups['social']['keys'], $actions, $google ) ); echo '
'; foreach ( $groups as $group ) { echo '

' . esc_html( $group['label'] ) . '

'; echo '
'; foreach ( $group['keys'] as $key ) { if ( ! isset( $buttons[ $key ] ) ) { continue; } $this->ayudawp_render_button_choice( $key, $buttons[ $key ], $enabled, $style ); } echo '
'; } echo '

' . esc_html__( 'Browser actions', 'ai-share-summarize' ) . '

'; echo '
'; foreach ( $actions as $key ) { if ( ! isset( $buttons[ $key ] ) ) { continue; } $this->ayudawp_render_button_choice( $key, $buttons[ $key ], $enabled, $style ); } echo '
'; echo '

' . esc_html__( 'Google', 'ai-share-summarize' ) . '

'; echo '
'; foreach ( $google as $key ) { if ( ! isset( $buttons[ $key ] ) ) { continue; } $this->ayudawp_render_button_choice( $key, $buttons[ $key ], $enabled, $style ); } echo '
'; echo '
'; echo '

' . esc_html__( 'Select which buttons to display on the frontend. Each one is shown here with the style you have chosen below.', 'ai-share-summarize' ) . '

'; // The native share button behaves unlike every other one, so it gets // its own note right where it is ticked (v2.5.0). echo '

' . '' . esc_html__( 'Native share', 'ai-share-summarize' ) . ': ' . esc_html__( 'this one has no destination of its own. It opens the share sheet of the visitor device, the same one a mobile app uses, which reaches WhatsApp, Signal, Instagram, Messages, AirDrop or whatever they have installed, without a button for each. It only appears where the browser supports it and the site is served over HTTPS, so it stays hidden on a local http install and on desktop Firefox. Where it cannot run, clicking it copies the link instead.', 'ai-share-summarize' ) . '

'; // What the Google button does, and why it would not show (v2.6.0). echo '

' . '' . esc_html__( 'Google preferred source', 'ai-share-summarize' ) . ': ' . esc_html__( 'opens the Google tool where readers mark your site as a preferred source, so it shows up more in their Top Stories. It is a plain link: nothing loads from Google until someone clicks it. Clicks are counted in Analytics like any other button.', 'ai-share-summarize' ); $google_domain = ayudawp_aiss_get_google_preferred_domain(); if ( '' === $google_domain ) { echo ' ' . esc_html__( 'This site cannot use it, so it will not be shown:', 'ai-share-summarize' ) . ' '; $home_path = wp_parse_url( home_url(), PHP_URL_PATH ); if ( (int) get_option( 'blog_public', 1 ) < 1 ) { echo esc_html__( 'the site asks search engines not to index it (Settings > Reading).', 'ai-share-summarize' ); } elseif ( is_string( $home_path ) && '' !== trim( $home_path, '/' ) ) { echo esc_html__( 'Google only accepts a domain or a subdomain, and the address of this site has a path.', 'ai-share-summarize' ); } else { echo esc_html__( 'a filter on this site hides it.', 'ai-share-summarize' ); } } else { /* translators: %s is the domain sent to Google, e.g. example.com */ echo ' ' . esc_html( sprintf( __( 'Domain sent to Google: %s', 'ai-share-summarize' ), $google_domain ) ); } echo '

'; // Where it goes (v2.6.0): with the social networks, in a section of // its own at the end of the block, or only where a shortcode asks. $google_place = ayudawp_aiss_get_google_preferred_placement( $options ); $google_title = isset( $options['google_section_title'] ) ? (string) $options['google_section_title'] : ''; $google_opts = array( 'social' => __( 'With the social networks', 'ai-share-summarize' ), 'section' => __( 'In a section of its own, at the end of the block', 'ai-share-summarize' ), 'outside' => __( 'Outside the block, only where you place the shortcode', 'ai-share-summarize' ), ); // Side by side; the title is dimmed while it would not be used. echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo '
'; echo '

' . esc_html__( 'The title is only used when the button has a section of its own; without one, a thin line sets it apart. Outside the block, place it with this shortcode wherever you want it:', 'ai-share-summarize' ) . ' [ayudawp_share_buttons buttons="google_preferred"]

'; } /** * Render one checkbox of the button picker as the button it enables (v2.5.0) * * @param string $key Button key. * @param string $label Button label. * @param array $enabled Enabled buttons. * @param string $style Current visual style. */ private function ayudawp_render_button_choice( $key, $label, $enabled, $style ) { $classes = array( 'ayudawp-share-btn', str_replace( '_', '-', $key ) ); if ( in_array( $key, ayudawp_aiss_get_ai_buttons(), true ) ) { $classes[] = 'ai'; } $icon = AyudaWP_AISS_Icons::ayudawp_get_button_icon( $key, 16 ); echo ''; } /** * SEO Integration callback */ public function ayudawp_seo_integration_callback() { $options = get_option( 'ayudawp_aiss_options' ); $exclude_noindex = isset( $options['exclude_noindex'] ) ? $options['exclude_noindex'] : true; $seo_plugin = AyudaWP_AISS_SEO_Integration::ayudawp_detect_seo_plugin(); $has_noindexer = class_exists( 'Noindexer_Frontend' ); $has_visibility = AyudaWP_AISS_SEO_Integration::ayudawp_has_visibility(); ?>

Yoast SEO, Rank Math, All in One SEO, SEOPress, The SEO Framework, Visibility, NoIndexer

esc_html__( 'AI assistants first (default)', 'ai-share-summarize' ), 'ayudawp_social_first' => esc_html__( 'Social networks first', 'ai-share-summarize' ), 'ayudawp_mixed' => esc_html__( 'Mixed, one from each in turn', 'ai-share-summarize' ), ); foreach ( $orders as $key => $label ) { $checked = ( $order === $key ) ? 'checked="checked"' : ''; echo ''; } // Two-column sortable for custom internal order within each group (v1.6.0). $custom_order_ai = isset( $options['button_custom_order_ai'] ) ? $options['button_custom_order_ai'] : array(); $custom_order_social = isset( $options['button_custom_order_social'] ) ? $options['button_custom_order_social'] : array(); $enabled = isset( $options['enabled_buttons'] ) ? $options['enabled_buttons'] : array(); $all_buttons = ayudawp_aiss_get_available_buttons(); $social_keys = ayudawp_aiss_get_social_buttons(); $ai_keys = ayudawp_aiss_get_ai_buttons(); // Build sorted lists per group. $sorted_ai = self::ayudawp_build_sorted_list( $custom_order_ai, $enabled, $ai_keys, $all_buttons ); $sorted_social = self::ayudawp_build_sorted_list( $custom_order_social, $enabled, $social_keys, $all_buttons ); /* * Each row shows the real button, same as the picker above (v2.5.0): * the list used to draw a bare SVG next to the platform name, which was * the last place in the screen where a button did not look like itself. */ $style = isset( $options['button_colors'] ) ? $options['button_colors'] : 'minimal'; $icon_style = isset( $options['icon_style'] ) ? $options['icon_style'] : 'circular'; $wrapper_classes = array( 'ayudawp-share-buttons', 'aiss-order-preview', 'with-icons' ); if ( 'icons-only' === $style ) { $wrapper_classes[] = 'icons-only'; $wrapper_classes[] = $icon_style; } elseif ( 'minimal' !== $style ) { $wrapper_classes[] = $style; } /* * The Google preferred source button only has a place in this order * while it goes with the social networks (v2.6.0). In a section of its * own it is always last, and outside the block it is not in it. It is * still rendered, hidden, so changing the setting shows it again * without saving first. */ $google_place = ayudawp_aiss_get_google_preferred_placement( $options ); $columns = array( 'ai' => array( 'label' => esc_html__( 'AI platforms', 'ai-share-summarize' ), 'buttons' => $sorted_ai, ), 'social' => array( 'label' => esc_html__( 'Social platforms', 'ai-share-summarize' ), 'buttons' => $sorted_social, ), ); echo '
'; echo '

' . esc_html__( 'Drag and drop to reorder within each group. Only the buttons you enabled above are listed.', 'ai-share-summarize' ) . '

'; echo '
'; foreach ( $columns as $group => $column ) { echo '
'; echo '' . esc_html( $column['label'] ) . ''; echo '
    '; foreach ( $column['buttons'] as $btn ) { $classes = array( 'ayudawp-share-btn', str_replace( '_', '-', $btn ) ); if ( 'ai' === $group ) { $classes[] = 'ai'; } ?>
  • >
  • '; if ( 'social' === $group && in_array( 'google_preferred', $column['buttons'], true ) ) { $google_notes = array( 'section' => __( 'Google preferred source is not in this list: it goes in a section of its own, at the end of the block.', 'ai-share-summarize' ), 'outside' => __( 'Google preferred source is not in this list: it goes outside the block, only where you place its shortcode.', 'ai-share-summarize' ), ); foreach ( $google_notes as $place => $note ) { echo '

    ' . esc_html( $note ) . '

    '; } } echo '
'; } echo '
'; } /** * Build a sorted button list from custom order + enabled buttons * * @param array $custom_order Saved custom order. * @param array $enabled Currently enabled buttons. * @param array $group_keys Keys belonging to this group (ai or social). * @param array $all_buttons All available buttons. * @return array Sorted button keys. */ private static function ayudawp_build_sorted_list( $custom_order, $enabled, $group_keys, $all_buttons ) { $sorted = array(); if ( ! empty( $custom_order ) ) { foreach ( $custom_order as $btn ) { if ( in_array( $btn, $enabled, true ) && in_array( $btn, $group_keys, true ) && isset( $all_buttons[ $btn ] ) ) { $sorted[] = $btn; } } } foreach ( $enabled as $btn ) { if ( ! in_array( $btn, $sorted, true ) && in_array( $btn, $group_keys, true ) && isset( $all_buttons[ $btn ] ) ) { $sorted[] = $btn; } } return $sorted; } /** * Mobile compact mode (v2.5.0) */ public function ayudawp_mobile_compact_callback() { $options = get_option( 'ayudawp_aiss_options' ); $mode = isset( $options['mobile_compact'] ) ? $options['mobile_compact'] : 'single'; $visible = isset( $options['mobile_compact_visible'] ) ? (int) $options['mobile_compact_visible'] : 3; $visible = max( 1, min( 5, $visible ) ); $modes = array( 'single' => esc_html__( 'A single Share button that opens the rest (default)', 'ai-share-summarize' ), 'partial' => esc_html__( 'A few buttons plus a More button', 'ai-share-summarize' ), 'disabled' => esc_html__( 'Disabled: show every button', 'ai-share-summarize' ), ); echo '

' . esc_html__( 'How much room the buttons take on a phone. The desktop layout is not affected.', 'ai-share-summarize' ) . '

'; foreach ( $modes as $key => $label ) { echo ''; } ?>

ayudawp_placements_field_name( $key ); $listing_keys = array_intersect_key( $targets, array( 'home' => 1, 'archive' => 1 ) ); $singular = array_diff_key( $targets, $listing_keys ); $groups = array( array( 'label' => esc_html__( 'Single content', 'ai-share-summarize' ), 'targets' => $singular, ), ); if ( ! empty( $listing_keys ) ) { // WordPress calls these archives, so the screen does too. $groups[] = array( 'label' => esc_html__( 'Archives', 'ai-share-summarize' ), 'targets' => $listing_keys, ); } /* * Two columns: a site with several public post types plus the archives * makes for a tall single column, and this screen paints the table * twice (buttons and floating bar). */ echo '
'; foreach ( $groups as $group ) { echo '
'; echo '

' . esc_html( $group['label'] ) . '

'; foreach ( $group['targets'] as $target => $label ) { $on = isset( $placements[ $target ] ); $position = $on ? $placements[ $target ] : ayudawp_aiss_get_default_placement_position( $key ); $id = 'aiss-placement-' . $key . '-' . $target; ?>
>
'; } echo '
'; if ( 'placements' === $key ) { echo '

' . sprintf( /* translators: %s is the shortcode name. */ esc_html__( 'With nothing ticked, the buttons only appear where you place the %s shortcode.', 'ai-share-summarize' ), '[ayudawp_share_buttons]' ) . '

'; } } /** * Which option a placements table posts into (v2.5.0) * * The summary keeps its own option since 2.3.0, so its table has to post * there and not into the buttons one. * * @param string $key Placements map key. * @return string Option name. */ private function ayudawp_placements_field_name( $key ) { return ( 'ai_summary_placements' === $key ) ? 'ayudawp_aiss_summary_options' : 'ayudawp_aiss_options'; } /** * Floating bar (v2.5.0) * * Same table as the buttons, with the positions the bar actually has: an * edge of the viewport, not a place in the content. That is also how it is * switched on — a row ticked is a page where the bar shows — so there is no * separate on/off radio and no "use its own destinations" checkbox to fold * a second table away. */ public function ayudawp_floating_bar_callback() { $options = get_option( 'ayudawp_aiss_options' ); $autohide = ! empty( $options['floating_bar_autohide'] ); $hide_mobile = ! isset( $options['floating_bar_hide_mobile'] ) || ! empty( $options['floating_bar_hide_mobile'] ); $hide_inline = ! empty( $options['floating_bar_hide_with_inline'] ); echo '

' . esc_html__( 'A sticky bar with the same enabled buttons, in icon form, pinned to the edge of the screen. It does not have to appear where the block above appears: the block on posts and the bar on archives works.', 'ai-share-summarize' ) . '

'; $this->ayudawp_placements_callback( array( 'key' => 'floating_bar_placements' ) ); echo '

' . esc_html__( 'With nothing ticked the bar is off, which is how it comes.', 'ai-share-summarize' ) . '

'; ?>

esc_html__( 'Span, plain text (default)', 'ai-share-summarize' ), 'h3' => esc_html__( 'Heading 3 (h3)', 'ai-share-summarize' ), 'h4' => esc_html__( 'Heading 4 (h4)', 'ai-share-summarize' ), 'h5' => esc_html__( 'Heading 5 (h5)', 'ai-share-summarize' ), 'h6' => esc_html__( 'Heading 6 (h6)', 'ai-share-summarize' ), ); ?>

esc_html__( 'Minimal (default)', 'ai-share-summarize' ), 'brand' => esc_html__( 'Brand colours', 'ai-share-summarize' ), 'outline' => esc_html__( 'Outline (brand borders)', 'ai-share-summarize' ), 'dark' => esc_html__( 'For dark backgrounds', 'ai-share-summarize' ), 'custom' => esc_html__( 'Custom colors', 'ai-share-summarize' ), 'icons-only' => esc_html__( 'Icons only', 'ai-share-summarize' ), ); $show_icons = isset( $options['show_icons'] ) ? $options['show_icons'] : false; $icon_style = isset( $options['icon_style'] ) ? $options['icon_style'] : 'circular'; echo '
'; foreach ( $styles as $key => $label ) { echo ''; } echo '
'; ?>

'; // Custom color picker fields. $custom_bg = isset( $options['custom_color_bg'] ) ? $options['custom_color_bg'] : '#333333'; $custom_text = isset( $options['custom_color_text'] ) ? $options['custom_color_text'] : '#ffffff'; ?>
' . esc_html__( 'The preview in "Enabled buttons" above updates as you change these, before saving.', 'ai-share-summarize' ) . '

'; } /** * Analytics data: retention, one-off deletion and uninstall behaviour * * Reordered in 2.5.0. The destructive button used to sit at the far right * of the row, pushed there by `margin-left: auto`, which on a wide screen * left it stranded halfway across the screen from the setting it belongs * with. It now sits next to the retention period it complements, with the * uninstall choice, a different decision, below both. */ public function ayudawp_data_retention_callback() { $options = get_option( 'ayudawp_aiss_options' ); $retention = isset( $options['data_retention'] ) ? $options['data_retention'] : 'forever'; $delete_data = isset( $options['delete_data_on_uninstall'] ) ? $options['delete_data_on_uninstall'] : false; $retention_options = array( 'forever' => __( 'Forever (default)', 'ai-share-summarize' ), '1_month' => __( '1 month', 'ai-share-summarize' ), '3_months' => __( '3 months', 'ai-share-summarize' ), '6_months' => __( '6 months', 'ai-share-summarize' ), '1_year' => __( '1 year', 'ai-share-summarize' ), ); ?>

esc_html__( 'Normal (default)', 'ai-share-summarize' ), 'compact' => esc_html__( 'Compact', 'ai-share-summarize' ), 'large' => esc_html__( 'Large', 'ai-share-summarize' ), 'fluid' => esc_html__( 'Fluid: fill the available width', 'ai-share-summarize' ), ); $dark_modes = array( 'disabled' => esc_html__( 'Disabled (default)', 'ai-share-summarize' ), 'auto' => esc_html__( 'Automatic', 'ai-share-summarize' ), ); ?>
$label ) : ?>
$label ) : ?>

' . esc_html__( 'Tick the content types that get a summary, and where it goes on each. Nothing ticked means no summaries are generated automatically.', 'ai-share-summarize' ) . '

'; $this->ayudawp_placements_callback( array( 'key' => 'ai_summary_placements' ) ); echo '

' . esc_html__( 'The positions relative to the buttons fall back to the start of the content on posts where the buttons are not shown. This list is independent from where the buttons appear.', 'ai-share-summarize' ) . '

'; } /** * Appearance of the summary block, with a live preview (v2.5.0) * * Five styles times three icon positions times open or closed is more * combinations than anyone wants to discover by saving and reloading, so the * sample below is rendered with the front-end stylesheet and repainted as * the controls change. */ public function ayudawp_ai_summary_look_callback() { $options = ayudawp_aiss_get_summary_options(); $style = isset( $options['ai_summary_style'] ) ? $options['ai_summary_style'] : 'minimal'; $icon_pos = isset( $options['ai_summary_icon_position'] ) ? $options['ai_summary_icon_position'] : 'left'; $collapsed = isset( $options['ai_summary_collapsed_default'] ) ? $options['ai_summary_collapsed_default'] : true; $label = ! empty( $options['ai_summary_label'] ) ? $options['ai_summary_label'] : __( 'TL;DR (AI Generated)', 'ai-share-summarize' ); $styles = array( 'minimal' => esc_html__( 'Minimal (default)', 'ai-share-summarize' ), 'outline' => esc_html__( 'Outline', 'ai-share-summarize' ), 'brand' => esc_html__( 'Brand (filled)', 'ai-share-summarize' ), 'dark' => esc_html__( 'Dark', 'ai-share-summarize' ), 'custom' => esc_html__( 'Custom colors', 'ai-share-summarize' ), ); $icon_positions = array( 'left' => esc_html__( 'Left (default)', 'ai-share-summarize' ), 'right' => esc_html__( 'Right', 'ai-share-summarize' ), 'hidden' => esc_html__( 'Hidden', 'ai-share-summarize' ), ); $custom_bg = isset( $options['ai_summary_custom_bg'] ) ? $options['ai_summary_custom_bg'] : '#ffffff'; $custom_text = isset( $options['ai_summary_custom_text'] ) ? $options['ai_summary_custom_text'] : '#1a1a1a'; ?>
$style_label ) : ?>
$icon_label ) : ?>

ayudawp_render_summary_preview( $style, $icon_pos, $collapsed, $label, $custom_bg, $custom_text ); ?>

ayudawp-aiss-custom', 'ayudawp_aiss_custom_visible' ); ?>

'Permission denied.' ) ); } AyudaWP_AISS_Database::ayudawp_delete_all_data(); wp_send_json_success(); } /** * AJAX handler: Dismiss the "Last AI generation error" notice on Settings (v2.0.0) */ public function ayudawp_ajax_dismiss_ai_error() { check_ajax_referer( 'aiss_admin_nonce', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( array( 'message' => 'Permission denied.' ) ); } if ( class_exists( 'AyudaWP_AISS_AI_Summary' ) ) { AyudaWP_AISS_AI_Summary::store_last_ai_error( null ); } else { delete_option( 'ayudawp_aiss_last_ai_error' ); } wp_send_json_success(); } // ========================================== // AI Summary section (v2.0.0) // ========================================== /** * AI Summary section callback — explains the feature and AI client status * * Since 2.3.0 this section lives on its own tab (&tab=ai-summary), which * is the stable deep-link target for the command palette, the Abilities * API and external docs (it replaces the old in-page anchor). */ public function ayudawp_ai_summary_section_callback() { echo '

' . esc_html__( 'Automatically generate a short summary of each post and display it inline alongside the share buttons.', 'ai-share-summarize' ) . '

'; // Loud, early warning when automatic generation is effectively off // because the content-type list is empty: since the buttons-list // fallback was removed (2.3.0), an empty list genuinely means "no // content types", and without this notice the only symptom would be // summaries silently not appearing. if ( ayudawp_aiss_is_summary_active() && array() === ayudawp_aiss_get_summary_post_types() ) { echo '
' . '

' . esc_html__( 'Automatic summaries are off for every content type.', 'ai-share-summarize' ) . ' ' . esc_html__( 'No content type is selected in "Summaries by content type" below, so no summary will be generated or displayed automatically. Manual regeneration from the editor keeps working.', 'ai-share-summarize' ) . '

' . '
'; } echo '
'; if ( function_exists( 'wp_ai_client_prompt' ) ) { $connectors_url = admin_url( 'options-connectors.php' ); echo '

' . esc_html__( 'WP AI Client is available.', 'ai-share-summarize' ) . ' ' . sprintf( /* translators: %s is a link to the Connectors settings screen. */ esc_html__( 'Configure your AI provider in %s to enable high-quality summaries.', 'ai-share-summarize' ), '' . esc_html__( 'Settings > Connectors', 'ai-share-summarize' ) . '' ) . '

'; // Surface the last AI Client error (if any) so the admin can act on it. // The optional "Possible cause" hint lives inside the same notice // so the dismiss button removes both lines together — keeping a // floating hint visible after the user has dismissed its parent // error would be confusing. if ( class_exists( 'AyudaWP_AISS_AI_Summary' ) ) { $last_error = AyudaWP_AISS_AI_Summary::get_last_ai_error(); if ( $last_error ) { $nonce = wp_create_nonce( 'aiss_admin_nonce' ); $show_hint = ayudawp_aiss_is_canonical_ai_plugin_active(); $approvals_url = admin_url( 'tools.php?page=ai-connector-approval' ); echo '
'; echo '
'; echo '

' . '' . esc_html__( 'Last AI generation error:', 'ai-share-summarize' ) . ' ' . esc_html( $last_error['message'] ) . ' ' . esc_html( $last_error['code'] ) . '' . '

'; // Heuristic hint: when the canonical AI plugin is active, // its Connector Approval system can silently block our // calls without a clear error code. Point the admin // straight at the approvals screen so they can unblock // us without us having to ship our own HTTP client. if ( $show_hint ) { echo '

' . '' . esc_html__( 'Possible cause:', 'ai-share-summarize' ) . ' ' . sprintf( /* translators: %1$s/%2$s wrap a link to Tools > Connector Approvals. */ esc_html__( 'The canonical AI plugin is active. Its Connector Approval system can silently block calls from plugins it has not approved yet. Open %1$sTools > Connector Approvals%2$s and enable the toggle next to "Share Buttons & AI-powered Summaries".', 'ai-share-summarize' ), '', '' ) . '

'; } echo '
'; // .flex column wrapper echo ''; echo '
'; // .aiss-ai-error-notice } } } else { echo '

' . esc_html__( 'WP AI Client not detected.', 'ai-share-summarize' ) . ' ' . esc_html__( 'Requires WordPress 7.0 or later. Without it, only the basic extractive fallback will be used.', 'ai-share-summarize' ) . '

'; } echo '
'; echo '

' . esc_html__( 'Summaries are generated asynchronously when a post is published or updated, on the post types selected in "Summaries by content type" below. This tab saves independently from the share buttons settings.', 'ai-share-summarize' ) . '

'; } /** * AI summary generation mode field (v2.2.0) * * Single explicit selector that replaces the former "Enable AI Summary" + * "Use extractive fallback" checkbox pair. */ public function ayudawp_ai_summary_mode_callback() { $mode = ayudawp_aiss_get_summary_mode(); $modes = array( 'ai_fallback' => esc_html__( 'AI with extractive fallback (recommended)', 'ai-share-summarize' ), 'ai_only' => esc_html__( 'AI only (no fallback)', 'ai-share-summarize' ), 'extractive_only' => esc_html__( 'Extractive only (never contacts an AI provider)', 'ai-share-summarize' ), 'disabled' => esc_html__( 'Disabled', 'ai-share-summarize' ), ); $descriptions = array( 'ai_fallback' => esc_html__( 'Generate with your AI provider; if it is unavailable, fall back to the on-server extractive summary.', 'ai-share-summarize' ), 'ai_only' => esc_html__( 'Generate with your AI provider only. If it fails, no summary is produced.', 'ai-share-summarize' ), 'extractive_only' => esc_html__( 'Always use the on-server extractive summarizer. Zero cost, never contacts an AI provider.', 'ai-share-summarize' ), 'disabled' => esc_html__( 'Do not generate summaries at all.', 'ai-share-summarize' ), ); foreach ( $modes as $key => $label ) { ?>

Connectors when no provider is configured. */ public function ayudawp_ai_summary_model_callback() { $options = ayudawp_aiss_get_summary_options(); $selected = isset( $options['ai_summary_model'] ) ? (string) $options['ai_summary_model'] : ''; $available = ayudawp_aiss_get_available_models(); if ( empty( $available ) ) { $connectors_url = admin_url( 'options-connectors.php' ); ?>

Connectors', 'ai-share-summarize' ); ?>