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' ); } ?>' . esc_html( $group['label'] ) . '
'; echo '' . esc_html__( 'Browser actions', 'ai-share-summarize' ) . '
'; echo '' . esc_html__( 'Google', 'ai-share-summarize' ) . '
'; 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 ''
. 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"]
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 '' . esc_html__( 'Drag and drop to reorder within each group. Only the buttons you enabled above are listed.', 'ai-share-summarize' ) . '
'; echo '' . esc_html( $note ) . '
'; } } 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 '' . 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; ?>' . 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]'
) . '
' . 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__( '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'; ?>
ayudawp-aiss-custom',
'ayudawp_aiss_custom_visible'
);
?>
' . 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' ) . '
' . '' . 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 ''
. '' . esc_html__( 'Last AI generation error:', 'ai-share-summarize' ) . ' '
. esc_html( $last_error['message'] )
. ' ' . esc_html( $last_error['code'] ) . ''
. '
' . '' . 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 '' . 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 '' . 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' ); ?>