array( 'name' => esc_html__( 'Free', 'ai-for-seo' ), 'credits' => 100, ), 's' => array( 'name' => esc_html__( 'Basic', 'ai-for-seo' ), 'credits' => 500, ), 'm' => array( 'name' => esc_html__( 'Pro', 'ai-for-seo' ), 'credits' => 1500, ), 'l' => array( 'name' => esc_html__( 'Premium', 'ai-for-seo' ), 'credits' => 5000, ), ); } /** * Normalize plan identifiers and textual plan names to the stored plan keys. * * @param mixed $plan Plan identifier or plan name. * @return string Normalized plan key, or an empty string for unknown plans. */ function ai4seo_normalize_plan_identifier( $plan ): string { if ( ! is_scalar( $plan ) ) { return ''; } // Keep all plan comparisons on the compact keys stored in the subscription environmental variable. $plan = sanitize_key( (string) $plan ); $plan_aliases = array( 'free' => 'free', 's' => 's', 'basic' => 's', 'm' => 'm', 'pro' => 'm', 'l' => 'l', 'premium' => 'l', ); return $plan_aliases[ $plan ] ?? ''; } /** * Function to retrieve the given plans amount of credits * * @param mixed $plan The plan value. * @return int */ function ai4seo_get_plan_credits( $plan ): int { $available_plans = ai4seo_get_available_plans(); $plan = ai4seo_normalize_plan_identifier( $plan ); return $available_plans[ $plan ]['credits'] ?? $available_plans['free']['credits']; } /** * Return the name of the given plan * * @param mixed $plan The plan value. * @return string */ function ai4seo_get_plan_name( $plan ): string { $available_plans = ai4seo_get_available_plans(); $plan = ai4seo_normalize_plan_identifier( $plan ); return $available_plans[ $plan ]['name'] ?? $available_plans['free']['name']; } /** * Return the current custom instruction character limit. * * @return int Maximum number of custom instruction characters for the current account. */ function ai4seo_get_custom_instructions_length_limit(): int { // Custom instructions are capped by subscription status, not by one-off credit balance. if ( ai4seo_user_has_active_subscription() ) { return AI4SEO_CUSTOM_INSTRUCTIONS_SUBSCRIPTION_LENGTH_LIMIT; } return AI4SEO_CUSTOM_INSTRUCTIONS_FREE_LENGTH_LIMIT; } /** * Return a plan badge, optionally forced into the clickable upgrade state. * * The forced mode lets inline upgrade prompts reuse the existing badge styling and modal behavior. * * @param string $plan Plan identifier. * @param bool $force_upgrade Whether the badge should open the upgrade modal even if the plan is active. * @return string Badge HTML. */ function ai4seo_get_plan_badge( $plan, bool $force_upgrade = false ): string { if ( ai4seo_prevent_loops( __FUNCTION__ ) ) { ai4seo_debug_message( 308030688, 'Prevented loop', true ); return ''; } // Resolve the display state once so regular feature badges and forced upgrade prompts share the same rendering path. $css_class = 'ai4seo-plan-badge'; $user_has_at_least_this_plan = ai4seo_user_has_at_least_plan( $plan ); $show_upgrade_state = $force_upgrade || ! $user_has_at_least_this_plan; $can_administer_plugin = ai4seo_can_administer_plugin(); $is_interactive_upgrade = $show_upgrade_state && $can_administer_plugin; $onclick = ''; // Keep the existing per-plan label and color mapping centralized in this helper. switch ( $plan ) { case 'free': $css_class .= ' ai4seo-plan-badge-free'; $badge_label = esc_html__( 'Free', 'ai-for-seo' ); $alt_text = esc_html__( 'Free plan', 'ai-for-seo' ); break; case 's': $css_class .= ' ai4seo-plan-badge-basic'; $badge_label = esc_html__( 'Basic', 'ai-for-seo' ); if ( $show_upgrade_state ) { $alt_text = esc_html__( 'You need the Basic Plan or higher to use this feature', 'ai-for-seo' ); } break; case 'm': $css_class .= ' ai4seo-plan-badge-pro'; $badge_label = esc_html__( 'Pro', 'ai-for-seo' ); if ( $show_upgrade_state ) { $alt_text = esc_html__( 'You need the Pro Plan or higher to use this feature', 'ai-for-seo' ); } break; case 'l': $css_class .= ' ai4seo-plan-badge-premium'; $badge_label = esc_html__( 'Premium', 'ai-for-seo' ); if ( $show_upgrade_state ) { $alt_text = esc_html__( 'You need the Premium Plan to use this feature', 'ai-for-seo' ); } break; default: return ''; } // Forced or insufficient-plan badges are buttons because they must open the credits/subscription modal. if ( ! $show_upgrade_state ) { $alt_text = esc_html__( 'You can use this feature with your current plan', 'ai-for-seo' ); } elseif ( $can_administer_plugin ) { $badge_label .= ' - ' . esc_html__( 'Upgrade now', 'ai-for-seo' ); $css_class .= ' ai4seo-clickable'; $onclick = 'ai4seo_open_get_more_credits_modal();'; } // Lower roles see the plan requirement as passive status text without a purchase trigger. if ( ! $is_interactive_upgrade ) { $output = ""; } else { $output = "' : ''; return $output; } /** * Return an inline subscription upgrade prompt with a pricing button. * * @param string $plan Minimum required subscription plan. * @param string $prompt_type Prompt text variant. * @param string $wrapper_css_class Optional wrapper CSS class. * @return string Upgrade prompt HTML. */ function ai4seo_get_subscription_upgrade_prompt_tag( string $plan, string $prompt_type = 'use_this_feature', string $wrapper_css_class = '' ): string { // Normalize aliases such as "basic" before selecting copy or comparing tier order. $ai4seo_normalized_plan = ai4seo_normalize_plan_identifier( $plan ); // Free or unknown plan identifiers should not produce a paid upgrade prompt. if ( '' === $ai4seo_normalized_plan || 'free' === $ai4seo_normalized_plan ) { return ''; } // Keep the plan name as the only sentence placeholder so translators control each full prompt variant. $ai4seo_plan_name = ai4seo_get_plan_name( $ai4seo_normalized_plan ); $ai4seo_plan_name_html = '' . esc_html( $ai4seo_plan_name ) . ''; $ai4seo_plan_has_higher_tier = in_array( $ai4seo_normalized_plan, array( 's', 'm' ), true ); // Use complete translation strings for the "or higher" variants instead of assembling sentence fragments. switch ( $prompt_type ) { case 'generation_length_options': // Free accounts need both paid thresholds explained, while Basic accounts only need the Pro threshold. $ai4seo_pro_plan_name_html = '' . esc_html( ai4seo_get_plan_name( 'm' ) ) . ''; if ( 's' === $ai4seo_normalized_plan ) { $ai4seo_upgrade_text = sprintf( /* translators: %1$s: Basic plan name wrapped in bold markup. %2$s: Pro plan name wrapped in bold markup. */ esc_html__( 'Option 4 requires a %1$s plan or higher. Option 5 requires a %2$s plan or higher.', 'ai-for-seo' ), $ai4seo_plan_name_html, $ai4seo_pro_plan_name_html ); } else { $ai4seo_upgrade_text = sprintf( /* translators: %s: Pro plan name wrapped in bold markup. */ esc_html__( 'Option 5 requires a %s plan or higher.', 'ai-for-seo' ), $ai4seo_pro_plan_name_html ); } break; case 'custom_instructions_1000_chars': // Keep the limit placeholder shared by both prompt variants so the copy stays consistent. $ai4seo_custom_instructions_subscription_length_limit_formatted = esc_html( ai4seo_format_number_i18n( AI4SEO_CUSTOM_INSTRUCTIONS_SUBSCRIPTION_LENGTH_LIMIT ) ); if ( $ai4seo_plan_has_higher_tier ) { $ai4seo_upgrade_text = sprintf( /* translators: %1$s: Subscription plan name wrapped in bold markup. %2$s: Character limit. */ esc_html__( 'Upgrade to %1$s or higher to enter up to %2$s chars.', 'ai-for-seo' ), $ai4seo_plan_name_html, $ai4seo_custom_instructions_subscription_length_limit_formatted ); } else { $ai4seo_upgrade_text = sprintf( /* translators: %1$s: Subscription plan name wrapped in bold markup. %2$s: Character limit. */ esc_html__( 'Upgrade to %1$s to enter up to %2$s chars.', 'ai-for-seo' ), $ai4seo_plan_name_html, $ai4seo_custom_instructions_subscription_length_limit_formatted ); } break; case 'use_this_feature': default: if ( $ai4seo_plan_has_higher_tier ) { $ai4seo_upgrade_text = sprintf( /* translators: %s: Subscription plan name wrapped in bold markup. */ esc_html__( 'Upgrade to %s or higher to use this feature.', 'ai-for-seo' ), $ai4seo_plan_name_html ); } else { $ai4seo_upgrade_text = sprintf( /* translators: %s: Subscription plan name wrapped in bold markup. */ esc_html__( 'Upgrade to %s to use this feature.', 'ai-for-seo' ), $ai4seo_plan_name_html ); } break; } $ai4seo_wrapper_css_class = trim( $wrapper_css_class ); $ai4seo_upgrade_prompt_html = $ai4seo_upgrade_text; // Lower roles receive only the plan requirement; pricing opens only after an administrator clicks. if ( ai4seo_can_administer_plugin() ) { $ai4seo_upgrade_button_html = ai4seo_get_icon_button_tag( 'crown', esc_html_x( 'Upgrade now', 'subscription upgrade prompt button', 'ai-for-seo' ), 'ai4seo-primary-button ai4seo-small-button', 'ai4seo_init_subscription_pricing(this);' ); $ai4seo_upgrade_prompt_html .= ' ' . $ai4seo_upgrade_button_html; } // Let callers opt into local layout without duplicating the prompt and button generation. if ( '' !== $ai4seo_wrapper_css_class ) { $ai4seo_upgrade_prompt_html = "" . $ai4seo_upgrade_prompt_html . ''; } return $ai4seo_upgrade_prompt_html; } // endregion // ___________________________________________________________________________________________.