PluginProbe
wpForo Forum / 3.1.6
wpForo Forum v3.1.6
3.1.6 3.1.5 3.1.4 3.1.2 3.1.1 3.1.0 3.0.9 3.0.8 3.0.7 trunk 1.0.0 1.0.1 1.0.2 1.1.0 1.1.1 1.1.2 1.2.0 1.3.0 1.3.1 1.4.0 1.4.1 1.4.10 1.4.11 1.4.12 1.4.13 All 138 releases
wpforo / admin / pages / tabs / ai-features-tab-overview.php

ai-features-tab-overview.php in wpForo Forum 3.1.6, at admin/pages/tabs/ai-features-tab-overview.php

2,888 lines 139.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * AI Features - Overview Tab
4 *
5 * Overview tab content showing connection status, subscription details, and pricing
6 *
7 * @package wpForo
8 * @subpackage Admin
9 */
10
11 if ( ! defined( 'ABSPATH' ) ) {
12 exit;
13 }
14
15 function wpforo_ai_render_not_connected_state() {
16 // Check if current site is localhost/development WITHOUT dev key
17 // If WPFORO_AI_DEV_KEY is defined, allow localhost connections
18 $is_localhost = wpforo_ai_is_localhost();
19 $has_dev_key = defined( 'WPFORO_AI_DEV_KEY' ) && WPFORO_AI_DEV_KEY;
20 $block_localhost = $is_localhost && ! $has_dev_key;
21 ?>
22 <div class="wpforo-ai-state wpforo-ai-not-connected">
23
24 <!-- Connection Status Box -->
25 <div class="wpforo-ai-box wpforo-ai-connection-box">
26 <div class="wpforo-ai-box-header" style="display: flex; justify-content: space-between; align-items: center;">
27 <h2 style="margin: 0;"><?php _e( 'Connection Status', 'wpforo' ); ?></h2>
28 <form method="post" action="" style="margin: 0;">
29 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
30 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
31 <button type="submit" class="button button-small" title="<?php esc_attr_e( 'Refresh Status', 'wpforo' ); ?>">
32 <span class="dashicons dashicons-update" style="vertical-align: middle;"></span>
33 </button>
34 </form>
35 </div>
36 <div class="wpforo-ai-box-body">
37 <div class="wpforo-ai-status-badge status-warning">
38 <span class="dashicons dashicons-warning"></span>
39 <?php _e( 'Not Connected', 'wpforo' ); ?>
40 </div>
41
42 <p class="wpforo-ai-description" style="display: none;">
43 <?php _e( 'Connect your forum to wpForo AI to unlock powerful AI features including semantic search, content creation, moderation, and intelligent assistance.', 'wpforo' ); ?>
44 </p>
45
46 <div class="wpforo-ai-callout">
47 <strong><?php _e( 'Start with 500 FREE credits, then subscribe to an AI Plan whenever you\'re ready! Activate AI features in one click!', 'wpforo' ); ?></strong>
48 </div>
49
50 <?php if ( $block_localhost ) : ?>
51 <div class="wpforo-ai-localhost-warning">
52 <span class="dashicons dashicons-warning"></span>
53 <?php _e( 'API key generation is only available for live websites. Please deploy your site to a public domain to connect to wpForo AI.', 'wpforo' ); ?>
54 </div>
55 <button type="button" class="button button-primary button-hero" disabled>
56 <span class="dashicons dashicons-admin-plugins" style="vertical-align: sub;"></span>
57 <?php _e( 'Connect to wpForo AI Features', 'wpforo' ); ?>
58 </button>
59 <?php else : ?>
60 <form method="post" action="" id="wpforo-ai-connect-form">
61 <?php wp_nonce_field( 'wpforo_ai_connect' ); ?>
62 <input type="hidden" name="wpforo_ai_action" value="connect">
63
64 <!-- Terms Agreement Checkbox -->
65 <div class="wpforo-ai-terms-agreement" style="margin-bottom: 20px; padding: 15px; background: #f8f9fa; border: 1px solid #ddd; border-radius: 4px;">
66 <label style="display: flex; align-items: flex-start; gap: 10px; cursor: pointer;">
67 <input type="checkbox" name="wpforo_ai_agree_terms" id="wpforo-ai-agree-terms" value="1" required style="margin-top: 3px;">
68 <span style="font-size: 13px; line-height: 1.5;">
69 <?php
70 printf(
71 __( 'I have read and agree to the %1$s and %2$s. I understand that my forum content will be processed by %3$s service as described in these documents.', 'wpforo' ),
72 '<a href="#" class="wpforo-ai-legal-link" data-document="terms" style="text-decoration: none;">' . __( 'Terms of Service', 'wpforo' ) . '</a>',
73 '<a href="#" class="wpforo-ai-legal-link" data-document="privacy" style="text-decoration: none;">' . __( 'Privacy Policy', 'wpforo' ) . '</a>',
74 '<a href="https://wpforo.com/gvectors-ai/" target="_blank" style="text-decoration: none;">' . __( 'gVectors AI', 'wpforo' ) . '</a>',
75 );
76 ?>
77 </span>
78 </label>
79 </div>
80
81 <button type="submit" class="button button-primary button-hero" id="wpforo-ai-connect-btn">
82 <span class="dashicons dashicons-admin-plugins" style="vertical-align: sub;"></span>
83 <?php _e( 'Connect to wpForo AI Features', 'wpforo' ); ?>
84 </button>
85 </form>
86 <?php endif; ?>
87
88 <!-- Legal Documents Modal -->
89 <div id="wpforo-ai-legal-modal" class="wpforo-ai-modal" style="display: none;">
90 <div class="wpforo-ai-modal-overlay"></div>
91 <div class="wpforo-ai-modal-container">
92 <div class="wpforo-ai-modal-header">
93 <h2 id="wpforo-ai-modal-title"></h2>
94 <button type="button" class="wpforo-ai-modal-close" aria-label="<?php esc_attr_e( 'Close', 'wpforo' ); ?>">
95 <span class="dashicons dashicons-no-alt"></span>
96 </button>
97 </div>
98 <div class="wpforo-ai-modal-body" id="wpforo-ai-modal-content">
99 <!-- Content loaded dynamically -->
100 </div>
101 <div class="wpforo-ai-modal-footer">
102 <button type="button" class="button button-primary wpforo-ai-modal-close-btn">
103 <?php _e( 'Close', 'wpforo' ); ?>
104 </button>
105 </div>
106 </div>
107 </div>
108 </div>
109 </div>
110
111 <!-- Getting Started Steps Box -->
112 <?php wpforo_ai_render_getting_started_steps( false ); ?>
113
114 <!-- Video Tutorials Box -->
115 <?php wpforo_ai_render_video_tutorials(); ?>
116
117 <!-- Features Preview Box -->
118 <div class="wpforo-ai-box wpforo-ai-features-preview-box">
119 <div class="wpforo-ai-box-header">
120 <h2><?php _e( 'wpForo AI Features', 'wpforo' ); ?></h2>
121 </div>
122 <div class="wpforo-ai-box-body">
123 <?php wpforo_ai_render_features_preview(); ?>
124 </div>
125 </div>
126
127 </div>
128 <?php
129 }
130
131 /**
132 * Render "Pending Approval" state
133 *
134 * Shown when tenant has registered but admin approval is required before
135 * they can use the API. The API key is saved but API calls are blocked.
136 *
137 * @param array $status Tenant status data
138 */
139 function wpforo_ai_render_pending_approval_state( $status ) {
140 $subscription = isset( $status['subscription'] ) ? $status['subscription'] : [];
141 $credits_total = isset( $subscription['credits_total'] ) ? $subscription['credits_total'] : 500;
142 ?>
143 <div class="wpforo-ai-state wpforo-ai-pending-approval">
144
145 <!-- Connection Status Box -->
146 <div class="wpforo-ai-box wpforo-ai-connection-box">
147 <div class="wpforo-ai-box-header" style="display: flex; justify-content: space-between; align-items: center;">
148 <h2 style="margin: 0;"><?php _e( 'Connection Status', 'wpforo' ); ?></h2>
149 <form method="post" action="" style="margin: 0;">
150 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
151 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
152 <button type="submit" class="button button-small" title="<?php esc_attr_e( 'Refresh Status', 'wpforo' ); ?>">
153 <span class="dashicons dashicons-update" style="vertical-align: middle;"></span>
154 </button>
155 </form>
156 </div>
157 <div class="wpforo-ai-box-body">
158 <div class="wpforo-ai-status-badge status-pending">
159 <span class="dashicons dashicons-clock"></span>
160 <?php _e( 'Awaiting Activation', 'wpforo' ); ?>
161 </div>
162
163 <p class="wpforo-ai-description">
164 <?php _e( 'Your API key has been generated and your account is registered. An administrator will review and activate your account shortly.', 'wpforo' ); ?>
165 </p>
166
167 <div class="wpforo-ai-callout wpforo-ai-callout-info">
168 <span class="dashicons dashicons-info"></span>
169 <?php
170 printf(
171 __( 'Once activated, you will have %s free credits to get started with AI features.', 'wpforo' ),
172 '<strong>' . number_format( $credits_total ) . '</strong>'
173 );
174 ?>
175 </div>
176
177 <div class="wpforo-ai-pending-actions">
178 <!-- Refresh Status Button -->
179 <form method="post" action="" style="display: inline-block; margin-top: 15px;">
180 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
181 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
182 <button type="submit" class="button">
183 <span class="dashicons dashicons-update" style="vertical-align: middle;"></span>
184 <?php _e( 'Check Activation Status', 'wpforo' ); ?>
185 </button>
186 </form>
187
188 <!-- Disconnect Button -->
189 <form method="post" action="" style="display: inline-block; margin-left: 10px;">
190 <?php wp_nonce_field( 'wpforo_ai_disconnect' ); ?>
191 <input type="hidden" name="wpforo_ai_action" value="disconnect">
192 <button type="submit" class="button wpforo-ai-disconnect-btn">
193 <?php _e( 'Cancel Registration', 'wpforo' ); ?>
194 </button>
195 </form>
196 </div>
197 </div>
198 </div>
199
200 <!-- Video Tutorials Box -->
201 <?php wpforo_ai_render_video_tutorials(); ?>
202
203 <!-- Features Preview Box -->
204 <div class="wpforo-ai-box wpforo-ai-features-preview-box">
205 <div class="wpforo-ai-box-header">
206 <h2><?php _e( 'Available After Activation', 'wpforo' ); ?></h2>
207 </div>
208 <div class="wpforo-ai-box-body">
209 <?php wpforo_ai_render_features_preview(); ?>
210 </div>
211 </div>
212
213 </div>
214 <?php
215 }
216
217 /**
218 * Render "Inactive" state
219 *
220 * Shown when an administrator has temporarily deactivated the tenant.
221 * API calls are blocked until the admin reactivates the account.
222 * No connect button should be shown since the account exists.
223 *
224 * @param array $status Tenant status data
225 */
226 function wpforo_ai_render_inactive_state( $status ) {
227 ?>
228 <div class="wpforo-ai-state wpforo-ai-inactive">
229
230 <!-- Connection Status Box -->
231 <div class="wpforo-ai-box wpforo-ai-connection-box">
232 <div class="wpforo-ai-box-header" style="display: flex; justify-content: space-between; align-items: center;">
233 <h2 style="margin: 0;"><?php _e( 'Connection Status', 'wpforo' ); ?></h2>
234 <form method="post" action="" style="margin: 0;">
235 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
236 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
237 <button type="submit" class="button button-small" title="<?php esc_attr_e( 'Refresh Status', 'wpforo' ); ?>">
238 <span class="dashicons dashicons-update" style="vertical-align: middle;"></span>
239 </button>
240 </form>
241 </div>
242 <div class="wpforo-ai-box-body">
243 <div class="wpforo-ai-status-badge status-inactive">
244 <span class="dashicons dashicons-marker"></span>
245 <?php _e( 'Temporarily Inactive', 'wpforo' ); ?>
246 </div>
247
248 <p class="wpforo-ai-description">
249 <?php _e( 'Your wpForo AI account has been temporarily deactivated by an administrator. AI features are currently unavailable.', 'wpforo' ); ?>
250 </p>
251
252 <div class="wpforo-ai-callout wpforo-ai-callout-warning">
253 <span class="dashicons dashicons-info"></span>
254 <?php
255 printf(
256 __( 'Please %s if you believe this is an error or if you need assistance reactivating your account.', 'wpforo' ),
257 '<a href="https://wpforo.com/login-register/?tab=login" target="_blank">' . __( 'open a support ticket', 'wpforo' ) . '</a>'
258 );
259 ?>
260 </div>
261
262 <div class="wpforo-ai-inactive-actions">
263 <!-- Refresh Status Button -->
264 <form method="post" action="" style="display: inline-block; margin-top: 15px;">
265 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
266 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
267 <button type="submit" class="button">
268 <span class="dashicons dashicons-update" style="vertical-align: middle;"></span>
269 <?php _e( 'Check Account Status', 'wpforo' ); ?>
270 </button>
271 </form>
272 </div>
273 </div>
274 </div>
275
276 <!-- Video Tutorials Box -->
277 <?php wpforo_ai_render_video_tutorials(); ?>
278
279 <!-- Features Preview Box (disabled state) -->
280 <div class="wpforo-ai-box wpforo-ai-features-preview-box" style="opacity: 0.6;">
281 <div class="wpforo-ai-box-header">
282 <h2><?php _e( 'Features Unavailable', 'wpforo' ); ?></h2>
283 </div>
284 <div class="wpforo-ai-box-body">
285 <?php wpforo_ai_render_features_preview(); ?>
286 </div>
287 </div>
288
289 </div>
290 <?php
291 }
292
293 /**
294 * Render "Free Trial" state
295 *
296 * @param array $status Tenant status data
297 * @param bool $is_post_purchase Whether this is a post-purchase page load
298 */
299 function wpforo_ai_render_free_trial_state( $status, $is_post_purchase = false ) {
300 $subscription = isset($status['subscription']) ? $status['subscription'] : [];
301 $tenant_id = isset($status['tenant_id']) ? $status['tenant_id'] : '';
302 $features = isset($status['features_enabled']) ? $status['features_enabled'] : [];
303 $usage = isset($status['usage_this_month']) ? $status['usage_this_month'] : [];
304
305 $credits_total = isset($subscription['credits_total']) ? $subscription['credits_total'] : 0;
306 $credits_remaining = isset($subscription['credits_remaining']) ? $subscription['credits_remaining'] : 0;
307 $credits_used = isset($subscription['credits_used']) ? $subscription['credits_used'] : 0;
308 $expires_at = isset($subscription['expires_at']) ? $subscription['expires_at'] : '';
309 $renews_at = isset($subscription['renews_at']) ? $subscription['renews_at'] : '';
310
311 $credits_percent = $credits_total > 0 ? round( ( $credits_remaining / $credits_total ) * 100 ) : 0;
312
313 wpforo_ai_render_connected_state( $status, 'free_trial', $is_post_purchase );
314 }
315
316 /**
317 * Render "Paid Plan" state
318 *
319 * @param array $status Tenant status data
320 * @param bool $is_post_purchase Whether this is a post-purchase page load
321 */
322 function wpforo_ai_render_paid_plan_state( $status, $is_post_purchase = false ) {
323 wpforo_ai_render_connected_state( $status, 'paid', $is_post_purchase );
324 }
325
326 /**
327 * Render connected state (shared between free trial and paid)
328 *
329 * @param array $status Tenant status data
330 * @param string $mode 'free_trial' or 'paid'
331 * @param bool $is_post_purchase Whether this is a post-purchase page load
332 */
333 function wpforo_ai_render_connected_state( $status, $mode = 'free_trial', $is_post_purchase = false ) {
334 $subscription = isset($status['subscription']) && is_array($status['subscription']) ? $status['subscription'] : [];
335 $tenant_id = isset($status['tenant_id']) ? $status['tenant_id'] : '';
336 $features = isset($status['features_enabled']) && is_array($status['features_enabled']) ? $status['features_enabled'] : [];
337 $usage = isset($status['usage_this_month']) && is_array($status['usage_this_month']) ? $status['usage_this_month'] : [];
338 $usage_lifetime = isset($status['usage_lifetime']) && is_array($status['usage_lifetime']) ? $status['usage_lifetime'] : [];
339 $plan = isset($subscription['plan']) ? $subscription['plan'] : 'free_trial';
340
341 $credits_total = isset($subscription['credits_total']) ? (int) $subscription['credits_total'] : 0;
342 $credits_baseline = isset($subscription['credits_baseline']) ? (int) $subscription['credits_baseline'] : $credits_total;
343 $credits_remaining = isset($subscription['credits_remaining']) ? (int) $subscription['credits_remaining'] : 0;
344 $credits_used = isset($subscription['credits_used']) ? (int) $subscription['credits_used'] : 0;
345 $max_credits = isset($subscription['max_credits']) ? (int) $subscription['max_credits'] : 0;
346 $expires_at = isset($subscription['expires_at']) ? $subscription['expires_at'] : '';
347 $renews_at = isset($subscription['renews_at']) ? $subscription['renews_at'] : '';
348
349 // Payment providers: detect all providers used by this tenant
350 // API returns payment_providers array (e.g., ["freemius", "paddle"]) and payment_provider string (most recent)
351 $payment_providers = isset($subscription['payment_providers']) && is_array($subscription['payment_providers']) ? $subscription['payment_providers'] : [];
352 $payment_provider = isset($subscription['payment_provider']) ? $subscription['payment_provider'] : '';
353 // Backwards compatibility: if API doesn't return payment_providers yet, build from single value
354 if ( empty( $payment_providers ) && $payment_provider ) {
355 $payment_providers = [ $payment_provider ];
356 }
357 // Legacy fallback: existing Freemius subscribers may not have payment_provider set
358 if ( empty( $payment_providers ) && $mode === 'paid' ) {
359 $payment_providers = [ 'freemius' ];
360 $payment_provider = 'freemius';
361 }
362
363 $credits_percent = $credits_baseline > 0 ? round( ( $credits_remaining / $credits_baseline ) * 100 ) : 0;
364 $is_free_trial = ( $mode === 'free_trial' );
365
366 // Get stored API key (global option, shared across all boards)
367 $api_key = WPF()->ai_client->get_api_key();
368 $api_key_masked = WPF()->ai_client->mask_api_key( WPF()->ai_client->decrypt_api_key( $api_key ) );
369
370 // Check bonus credits status
371 $bonus_credits_status = WPF()->ai_client->get_bonus_credits_status();
372 $bonus_credits_claimed = ! empty( $bonus_credits_status['claimed'] );
373 $bonus_credits_amount = $bonus_credits_claimed ? (int) $bonus_credits_status['amount'] : 0;
374
375 // Check eligibility for bonus credits (only if not claimed)
376 $bonus_credits_eligible = false;
377 if ( ! $bonus_credits_claimed ) {
378 $eligibility = WPF()->ai_client->check_bonus_credits_eligibility();
379 $bonus_credits_eligible = $eligibility['eligible'];
380 }
381
382 ?>
383 <div class="wpforo-ai-state wpforo-ai-connected <?php echo $is_free_trial ? 'wpforo-ai-free-trial' : 'wpforo-ai-paid-plan'; ?>">
384
385 <!-- Connection Status Box -->
386 <div class="wpforo-ai-box wpforo-ai-connection-box">
387 <div class="wpforo-ai-box-header">
388 <h2><?php _e( 'Connection Status', 'wpforo' ); ?></h2>
389 <form method="post" action="" class="wpforo-ai-refresh-form">
390 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
391 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
392 <button type="submit" class="button button-small" title="<?php esc_attr_e( 'Refresh Status', 'wpforo' ); ?>">
393 <span class="dashicons dashicons-update"></span>
394 <?php _e( 'Refresh', 'wpforo' ); ?>
395 </button>
396 </form>
397 </div>
398 <div class="wpforo-ai-box-body">
399 <div class="wpforo-ai-status-badge status-success">
400 <?php if ( $is_post_purchase ) : ?>
401 <span class="dashicons dashicons-update dashicons-spin"></span>
402 <?php _e( 'Subscription plan is being updated...', 'wpforo' ); ?>
403 <?php else : ?>
404 <span class="dashicons dashicons-yes-alt"></span>
405 <?php
406 if ( $is_free_trial ) {
407 _e( 'Connected (Free Trial)', 'wpforo' );
408 } else {
409 printf( __( 'Connected (%s Plan)', 'wpforo' ), esc_html( ucfirst( $plan ) ) );
410 }
411 ?>
412 <?php endif; ?>
413 </div>
414
415 <div class="wpforo-ai-connection-details">
416 <div class="detail-row">
417 <span class="detail-label"><?php _e( 'Tenant ID:', 'wpforo' ); ?></span>
418 <code class="detail-value"><?php echo esc_html( $tenant_id ); ?></code>
419 </div>
420 <div class="detail-row">
421 <span class="detail-label"><?php _e( 'API Key:', 'wpforo' ); ?></span>
422 <code class="detail-value wpforo-ai-key-masked" data-key-full="hidden"><?php echo esc_html( $api_key_masked ); ?></code>
423 </div>
424
425 <!-- License Activation Section (Freemius only) -->
426 <?php if ( in_array( 'freemius', $payment_providers, true ) ) : ?>
427 <div class="detail-row wpforo-ai-license-activation" style="flex-direction: column; align-items: flex-start;">
428 <a href="#" class="wpforo-ai-license-toggle" onclick="jQuery('.wpforo-ai-license-fields').slideToggle(200); jQuery(this).find('.dashicons').toggleClass('dashicons-arrow-right-alt2 dashicons-arrow-down-alt2'); return false;" style="text-decoration: none; color: #666; font-size: 13px;">
429 <span class="dashicons dashicons-arrow-right-alt2" style="vertical-align: middle; font-size: 16px; width: 16px; height: 16px;"></span>
430 <?php _e( 'Activate by License ID (Freemius payment only)', 'wpforo' ); ?>
431 </a>
432 <div class="wpforo-ai-license-fields" style="display: none; margin-top: 10px;">
433 <div class="license-input-wrapper">
434 <input type="text"
435 id="wpforo-ai-license-id"
436 class="regular-text"
437 placeholder="<?php esc_attr_e( 'Enter License ID from purchase email', 'wpforo' ); ?>"
438 style="width: 250px; margin-right: 10px; inherit; font-size: 14px;"
439 >
440 <button type="button" class="button button-secondary wpforo-ai-activate-license-btn">
441 <span class="dashicons dashicons-yes-alt" style="vertical-align: middle; font-size: 18px; line-height: 16px;"></span>
442 <?php _e( 'Activate License', 'wpforo' ); ?>
443 </button>
444 <span class="spinner" style="float: none; margin-top: 0;"></span>
445 </div>
446 <p class="description" style="margin-top: 5px; color: #111;">
447 <?php _e( 'If your Freemius plan was not activated automatically after purchase, enter your License ID here.', 'wpforo' ); ?>
448 <br>
449 <?php _e( 'You can find your License ID in the purchase confirmation email from Freemius.', 'wpforo' ); ?>
450 </p>
451 <div class="wpforo-ai-license-result" style="display: none; margin-top: 10px; min-width: 220px;"></div>
452 </div>
453 </div>
454 <?php endif; ?>
455
456 <!-- Paddle Transaction Activation Section (Paddle only) -->
457 <?php if ( in_array( 'paddle', $payment_providers, true ) ) : ?>
458 <div class="detail-row wpforo-ai-paddle-activation" style="flex-direction: column; align-items: flex-start;">
459 <a href="#" class="wpforo-ai-paddle-toggle" onclick="jQuery('.wpforo-ai-paddle-fields').slideToggle(200); jQuery(this).find('.dashicons').toggleClass('dashicons-arrow-right-alt2 dashicons-arrow-down-alt2'); return false;" style="text-decoration: none; color: #666; font-size: 13px;">
460 <span class="dashicons dashicons-arrow-right-alt2" style="vertical-align: middle; font-size: 16px; width: 16px; height: 16px;"></span>
461 <?php _e( 'Activate by Transaction ID (Paddle payment only)', 'wpforo' ); ?>
462 </a>
463 <div class="wpforo-ai-paddle-fields" style="display: none; margin-top: 10px;">
464 <div class="license-input-wrapper">
465 <input type="text"
466 id="wpforo-ai-paddle-txn-id"
467 class="regular-text"
468 placeholder="<?php esc_attr_e( 'e.g. txn_ . . . . ', 'wpforo' ); ?>"
469 style="width: 300px; margin-right: 10px; font-size: 14px;"
470 >
471 <button type="button" class="button button-secondary wpforo-ai-activate-paddle-txn-btn">
472 <span class="dashicons dashicons-yes-alt" style="vertical-align: middle; font-size: 18px; line-height: 16px;"></span>
473 <?php _e( 'Activate Transaction', 'wpforo' ); ?>
474 </button>
475 <span class="spinner" style="float: none; margin-top: 0;"></span>
476 </div>
477 <p class="description" style="margin-top: 5px; color: #111;">
478 <?php _e( 'If your Paddle payment was not registered automatically, enter your Transaction ID here.', 'wpforo' ); ?>
479 <br>
480 <?php _e( 'You can find the Transaction ID in invoice file of the payment confirmation email from Paddle.', 'wpforo' ); ?>
481 </p>
482 <div class="wpforo-ai-paddle-result" style="display: none; margin-top: 10px; min-width: 220px;"></div>
483 </div>
484 </div>
485 <?php endif; ?>
486
487 <div class="detail-row wpforo-ai-key-actions">
488 <?php if ( $bonus_credits_claimed ) : ?>
489 <!-- Bonus Credits Already Claimed -->
490 <span class="detail-label"><?php _e( 'Bonus Credits:', 'wpforo' ); ?></span>
491 <button type="button" class="button wpforo-ai-bonus-credits-btn claimed" disabled>
492 <span class="dashicons dashicons-awards"></span>
493 <?php printf( __( 'Granted Extra Free Credits %s', 'wpforo' ), number_format( $bonus_credits_amount ) ); ?>
494 </button>
495 <?php elseif ( $bonus_credits_eligible ) : ?>
496 <!-- Request Bonus Credits Button -->
497 <span class="detail-label"><?php _e( 'Bonus Credits:', 'wpforo' ); ?></span>
498 <button type="button" class="button wpforo-ai-bonus-credits-btn eligible">
499 <span class="dashicons dashicons-star-filled"></span>
500 <?php _e( 'Request Free Credits for Forum Content Indexing', 'wpforo' ); ?>
501 </button>
502 <span class="spinner wpforo-ai-bonus-spinner" style="float: none; margin-top: 0;"></span>
503 <?php endif; ?>
504 <!-- Disconnect Service -->
505 <button type="button" class="button button-secondary wpforo-ai-disconnect-btn">
506 <span class="dashicons dashicons-dismiss"></span>
507 <?php _e( 'Disconnect Service', 'wpforo' ); ?>
508 </button>
509 <!-- Disconnect and Remove All Data -->
510 <button type="button" class="button button-secondary wpforo-ai-disconnect-purge-btn" style="color: #b32d2e; border-color: #b32d2e;">
511 <span class="dashicons dashicons-trash"></span>
512 <?php _e( 'Disconnect and Remove All Data', 'wpforo' ); ?>
513 </button>
514 </div>
515 </div>
516
517 <!-- Credits Display -->
518 <div class="wpforo-ai-credits-section">
519 <div class="credits-header">
520 <h3><?php _e( 'AI Credits', 'wpforo' ); ?></h3>
521 <div class="credits-numbers">
522 <strong><?php echo number_format( $credits_remaining ); ?></strong>
523 <span>/</span>
524 <span><?php echo number_format( $credits_baseline ); ?></span>
525 <span class="credits-label"><?php _e( 'remaining', 'wpforo' ); ?></span>
526 </div>
527 </div>
528 <div class="credits-progress-bar">
529 <div class="credits-progress-fill <?php echo wpforo_ai_get_credit_status_class( $credits_percent ); ?>" style="width: <?php echo esc_attr( $credits_percent ); ?>%;"></div>
530 </div>
531 <div class="credits-info">
532 <?php
533 if ( $is_free_trial && ! empty( $expires_at ) ) {
534 printf(
535 __( 'Trial expires: %s', 'wpforo' ),
536 '<strong>' . esc_html( wpforo_ai_format_date( $expires_at ) ) . '</strong>'
537 );
538 } elseif ( ! empty( $renews_at ) ) {
539 printf(
540 __( 'Next billing: %s', 'wpforo' ),
541 '<strong>' . esc_html( wpforo_ai_format_date( $renews_at ) ) . '</strong>'
542 );
543 }
544 ?>
545 </div>
546 </div>
547 <?php if ( $max_credits > 0 && ! $is_free_trial ) : ?>
548 <div class="credits-cap-info" style="margin-top: 5px; font-size: 12px; color: #666; text-align: right;">
549 <span class="dashicons dashicons-info-outline" style="font-size: 14px; width: 14px; height: 14px; vertical-align: text-top;"></span>
550 <?php printf(
551 __( 'Maximum credit accumulation (one year of subscription plan credits): %s', 'wpforo' ),
552 '<strong>' . number_format( $max_credits ) . '</strong>'
553 ); ?>
554 </div>
555 <?php endif; ?>
556
557 <!-- Warning for Free Trial -->
558 <?php if ( $is_free_trial ) : ?>
559 <div class="wpforo-ai-warning-box">
560 <span class="dashicons dashicons-warning"></span>
561 <p>
562 <?php
563 printf(
564 __( 'You\'re on Free Trial. Expires on %s. Upgrade to continue using all AI features!', 'wpforo' ),
565 esc_html( wpforo_ai_format_date( $expires_at ) )
566 );
567 ?>
568 </p>
569 </div>
570 <?php else : ?>
571 <div class="wpforo-ai-success-box" style="display: none;">
572 <span class="dashicons dashicons-yes-alt"></span>
573 <p><?php printf( __( 'All features of %s plan are unlocked!', 'wpforo' ), $plan); ?></p>
574 </div>
575 <?php endif; ?>
576
577 <?php if ( ! $is_free_trial && ! empty( $payment_providers ) ) : ?>
578 <div class="wpforo-ai-payment-provider" style="margin-top: 8px; font-size: 13px; color: #555;">
579 <span class="dashicons dashicons-money-alt" style="font-size: 16px; width: 16px; height: 16px; vertical-align: text-bottom;"></span>
580 <?php
581 $provider_labels = array_map( function( $p ) { return '<strong>' . esc_html( ucfirst( $p ) ) . '</strong>'; }, $payment_providers );
582 printf( __( 'Payment: %s', 'wpforo' ), implode( ' + ', $provider_labels ) );
583 ?>
584 </div>
585 <?php endif; ?>
586
587 <!-- Action Buttons -->
588 <div class="wpforo-ai-actions">
589 <?php if ( $is_free_trial ) : ?>
590 <button type="button" class="button button-primary button-large" onclick="document.getElementById('wpforo-ai-plans').scrollIntoView({ behavior: 'smooth' })">
591 <span class="dashicons dashicons-cart"></span>
592 <?php _e( 'Upgrade Now / View Subscription Plans', 'wpforo' ); ?>&nbsp;
593 </button>
594 <?php else : ?>
595 <?php foreach ( $payment_providers as $provider ) : ?>
596 <a href="<?php echo esc_url( wpforo_ai_get_manage_subscription_url( $provider ) ); ?>" class="button button-secondary wpf-manage-subscription wpf-provider-<?php echo esc_attr( $provider ); ?>" target="_blank">
597 <span class="dashicons dashicons-admin-generic"></span>
598 <?php printf( __( 'Manage Subscription (%s)', 'wpforo' ), esc_html( ucfirst( $provider ) ) ); ?>
599 </a>
600 <?php endforeach; ?>
601 <?php if ( $plan === 'starter' || $plan === 'professional' ) : ?>
602 <button type="button" class="button button-secondary wpforo-ai-upgrade-btn" data-plan="business" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
603 <span class="dashicons dashicons-cart"></span>
604 <?php _e( 'Upgrade to Business', 'wpforo' ); ?>
605 </button>
606 <?php endif; ?>
607 <?php endif; ?>
608 </div>
609 </div>
610 </div>
611
612 <!-- Getting Started Steps Box -->
613 <?php wpforo_ai_render_getting_started_steps(); ?>
614
615 <!-- Video Tutorials Box -->
616 <?php wpforo_ai_render_video_tutorials(); ?>
617
618 <!-- Available Features Box -->
619 <div class="wpforo-ai-box wpforo-ai-features-box">
620 <div class="wpforo-ai-box-header">
621 <h2><?php echo $is_free_trial ? __( 'Available AI Features', 'wpforo' ) : __( 'Active AI Features', 'wpforo' ); ?></h2>
622 </div>
623 <div class="wpforo-ai-box-body">
624 <?php wpforo_ai_render_features_list( $features, $usage, $is_free_trial, $status ); ?>
625 </div>
626 </div>
627
628 <!-- Pricing Plans Box -->
629 <div id="wpforo-ai-plans" class="wpforo-ai-box wpforo-ai-upgrade-box">
630 <div class="wpforo-ai-box-header">
631 <h2><?php echo $is_free_trial ? __( 'Upgrade Your Plan', 'wpforo' ) : __( 'Subscription Plans', 'wpforo' ); ?></h2>
632 </div>
633 <div class="wpforo-ai-box-body">
634 <?php wpforo_ai_render_pricing_table( $tenant_id, $subscription ); ?>
635 </div>
636 </div>
637
638 <!-- Credit Packs Box (for paid users only) -->
639 <?php if ( ! $is_free_trial ) : ?>
640 <div class="wpforo-ai-box wpforo-ai-credit-packs-box">
641 <div class="wpforo-ai-box-header">
642 <h2><?php _e( 'Buy Additional Credits', 'wpforo' ); ?></h2>
643 </div>
644 <div class="wpforo-ai-box-body">
645 <?php wpforo_ai_render_credit_packs( $tenant_id ); ?>
646 </div>
647 </div>
648 <?php endif; ?>
649
650 <!-- Usage Statistics Box -->
651 <div class="wpforo-ai-box wpforo-ai-usage-box">
652 <div class="wpforo-ai-box-header">
653 <h2><?php _e( 'Usage Statistics', 'wpforo' ); ?></h2>
654 </div>
655 <div class="wpforo-ai-box-body">
656 <?php wpforo_ai_render_usage_stats( $usage, $credits_used, $usage_lifetime, $plan ); ?>
657 </div>
658 </div>
659
660 <!-- Account Information Box -->
661 <div class="wpforo-ai-box wpforo-ai-advanced-box">
662 <div class="wpforo-ai-box-header">
663 <h2><?php _e( 'Account Information', 'wpforo' ); ?></h2>
664 </div>
665 <div class="wpforo-ai-box-body">
666 <div class="wpforo-ai-advanced-info">
667 <div class="info-row">
668 <span class="info-label"><?php _e( 'Forum URL:', 'wpforo' ); ?></span>
669 <span class="info-value"><?php echo esc_html( get_site_url() ); ?></span>
670 </div>
671 <div class="info-row">
672 <span class="info-label"><?php _e( 'Admin Email:', 'wpforo' ); ?></span>
673 <span class="info-value"><?php echo esc_html( get_option( 'admin_email' ) ); ?></span>
674 </div>
675 <div class="info-row">
676 <span class="info-label"><?php _e( 'Tenant ID:', 'wpforo' ); ?></span>
677 <code class="info-value"><?php echo esc_html( $tenant_id ); ?></code>
678 </div>
679 </div>
680 </div>
681 </div>
682
683 </div>
684
685 <!-- Hidden Forms (triggered by buttons) -->
686 <div id="wpforo-ai-hidden-forms" style="display:none;">
687 <!-- Disconnect Form -->
688 <form id="wpforo-ai-disconnect-form" method="post" action="">
689 <?php wp_nonce_field( 'wpforo_ai_disconnect' ); ?>
690 <input type="hidden" name="wpforo_ai_action" value="disconnect">
691 <div class="wpforo-ai-disconnect-warning">
692 <span class="dashicons dashicons-warning"></span>
693 <p><strong><?php _e( 'Warning: This will disconnect your forum from wpForo AI service.', 'wpforo' ); ?></strong></p>
694 <p><?php _e( 'Your credits will be preserved and restored when you reconnect. Your indexed content will be deleted after 30 days. You can reconnect anytime with the same site URL.', 'wpforo' ); ?></p>
695 </div>
696 <p>
697 <label>
698 <input type="checkbox" name="confirm" value="1" required>
699 <?php _e( 'I understand and want to disconnect the service', 'wpforo' ); ?>
700 </label>
701 </p>
702 <p>
703 <label for="disconnect-reason"><?php _e( 'Reason (optional):', 'wpforo' ); ?></label>
704 <textarea id="disconnect-reason" name="reason" rows="3" class="large-text" placeholder="<?php esc_attr_e( 'Help us improve by telling us why you\'re disconnecting', 'wpforo' ); ?>"></textarea>
705 </p>
706 </form>
707
708 <!-- Disconnect and Remove All Data Form -->
709 <form id="wpforo-ai-disconnect-purge-form" method="post" action="">
710 <?php wp_nonce_field( 'wpforo_ai_disconnect' ); ?>
711 <input type="hidden" name="wpforo_ai_action" value="disconnect">
712 <input type="hidden" name="purge_data" value="1">
713 <div class="wpforo-ai-disconnect-warning" style="border-left-color: #b32d2e;">
714 <span class="dashicons dashicons-warning" style="color: #b32d2e;"></span>
715 <p><strong style="color: #b32d2e;"><?php _e( 'Warning: This will permanently delete ALL your data from gVectors AI servers.', 'wpforo' ); ?></strong></p>
716 <p><?php _e( 'This action will disconnect your forum and immediately delete all indexed content, embeddings, and tenant data from the AI service. This cannot be undone. Your credits will NOT be preserved.', 'wpforo' ); ?></p>
717 </div>
718 <p>
719 <label>
720 <input type="checkbox" name="confirm" value="1" required>
721 <?php _e( 'I understand that all my data will be permanently deleted and want to proceed', 'wpforo' ); ?>
722 </label>
723 </p>
724 <p>
725 <label for="disconnect-purge-reason"><?php _e( 'Reason (optional):', 'wpforo' ); ?></label>
726 <textarea id="disconnect-purge-reason" name="reason" rows="3" class="large-text" placeholder="<?php esc_attr_e( 'Help us improve by telling us why you\'re removing your data', 'wpforo' ); ?>"></textarea>
727 </p>
728 </form>
729 </div>
730 <?php
731 }
732
733 /**
734 * Render expired subscription state
735 *
736 * @param array $status Tenant status data with expired subscription
737 */
738 function wpforo_ai_render_expired_state( $status ) {
739 $tenant_id = wpfval( $status, 'tenant_id' ) ?: WPF()->ai_client->get_tenant_id();
740 $subscription = wpfval( $status, 'subscription' );
741 $expires_at = wpfval( $subscription, 'expires_at' );
742 $plan = wpfval( $subscription, 'plan' );
743 $is_trial = ( $plan === 'free_trial' );
744
745 ?>
746 <div class="wpforo-ai-state wpforo-ai-expired-state">
747 <div class="wpforo-ai-box wpforo-ai-error-box" style="border-left: 4px solid #d63638;">
748 <div class="wpforo-ai-box-header">
749 <h2><?php _e( 'Subscription Status', 'wpforo' ); ?></h2>
750 </div>
751 <div class="wpforo-ai-box-body">
752 <div class="wpforo-ai-status-badge status-error">
753 <span class="dashicons dashicons-warning"></span>
754 <?php echo $is_trial ? __( 'Trial Expired', 'wpforo' ) : __( 'Subscription Expired', 'wpforo' ); ?>
755 </div>
756
757 <div class="wpforo-ai-error-message" style="margin: 20px 0;">
758 <?php if ( $is_trial ) : ?>
759 <p><strong><?php _e( 'Your free trial has expired.', 'wpforo' ); ?></strong></p>
760 <p><?php _e( 'To continue using AI features, please upgrade to a paid plan.', 'wpforo' ); ?></p>
761 <?php else : ?>
762 <p><strong><?php _e( 'Your subscription has expired.', 'wpforo' ); ?></strong></p>
763 <p><?php _e( 'Please renew your subscription to continue using AI features.', 'wpforo' ); ?></p>
764 <?php endif; ?>
765
766 <?php if ( ! empty( $expires_at ) ) : ?>
767 <p class="wpforo-ai-expiry-date" style="color: #666; font-size: 13px;">
768 <?php
769 printf(
770 __( 'Expired on: %s', 'wpforo' ),
771 '<strong>' . esc_html( wpforo_ai_format_date( $expires_at ) ) . '</strong>'
772 );
773 ?>
774 </p>
775 <?php endif; ?>
776 </div>
777
778 <div class="wpforo-ai-error-actions">
779 <button type="button" class="button button-primary button-large" onclick="document.getElementById('wpforo-ai-plans').scrollIntoView({ behavior: 'smooth' })">
780 <span class="dashicons dashicons-cart"></span>
781 <?php _e( 'Upgrade Now / View Subscription Plans', 'wpforo' ); ?>&nbsp;
782 </button>
783
784 <form method="post" action="" style="display: inline;">
785 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
786 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
787 <button type="submit" class="button button-secondary">
788 <span class="dashicons dashicons-update"></span>
789 <?php _e( 'Check Status', 'wpforo' ); ?>
790 </button>
791 </form>
792 </div>
793
794 <div class="wpforo-ai-support-info" style="margin-top: 20px;">
795 <p style="color: #666; font-size: 13px;">
796 <?php
797 printf(
798 __( 'Need help? %s', 'wpforo' ),
799 '<a href="https://wpforo.com/login-register/?tab=login" target="_blank">' . __( 'Open Support Ticket', 'wpforo' ) . '</a>'
800 );
801 ?>
802 </p>
803 </div>
804 </div>
805 </div>
806
807 <!-- Video Tutorials Box -->
808 <?php wpforo_ai_render_video_tutorials(); ?>
809
810 <!-- Plans Section for expired users -->
811 <div id="wpforo-ai-plans" class="wpforo-ai-box" style="margin-top: 20px;">
812 <div class="wpforo-ai-box-header">
813 <h2><?php _e( 'Available Plans', 'wpforo' ); ?></h2>
814 </div>
815 <div class="wpforo-ai-box-body">
816 <?php wpforo_ai_render_pricing_table( 'free_trial' ); ?>
817 </div>
818 </div>
819 </div>
820 <?php
821 }
822
823 /**
824 * Render cancelled/refunded subscription state
825 *
826 * Shown when Freemius or Paddle webhook sets subscription_status to
827 * "cancelled" or "refunded". The user needs a clear explanation and
828 * actionable options: buy a new plan, disconnect, or check status.
829 *
830 * @param array $status Tenant status data from /tenant/status API
831 */
832 function wpforo_ai_render_cancelled_state( $status ) {
833 $subscription = wpfval( $status, 'subscription' );
834 $sub_status = wpfval( $subscription, 'status' );
835 $is_refunded = ( $sub_status === 'refunded' );
836 $tenant_id = wpfval( $status, 'tenant_id' ) ?: WPF()->ai_client->get_tenant_id();
837
838 $provider = wpfval( $subscription, 'payment_provider' );
839 if ( empty( $provider ) ) {
840 $provider = get_option( 'wpforo_ai_payment_provider', 'freemius' );
841 }
842
843 ?>
844 <div class="wpforo-ai-state wpforo-ai-cancelled-state">
845 <div class="wpforo-ai-box wpforo-ai-error-box" style="border-left: 4px solid #d63638;">
846 <div class="wpforo-ai-box-header">
847 <h2><?php _e( 'Subscription Status', 'wpforo' ); ?></h2>
848 </div>
849 <div class="wpforo-ai-box-body">
850 <div class="wpforo-ai-status-badge status-error">
851 <span class="dashicons dashicons-warning"></span>
852 <?php echo $is_refunded ? __( 'Subscription Refunded', 'wpforo' ) : __( 'Subscription Cancelled', 'wpforo' ); ?>
853 </div>
854
855 <div class="wpforo-ai-error-message" style="margin: 20px 0;">
856 <?php if ( $is_refunded ) : ?>
857 <p><strong><?php _e( 'Your subscription has been refunded.', 'wpforo' ); ?></strong></p>
858 <p><?php _e( 'AI features are currently disabled. You can purchase a new plan to reactivate the service, or disconnect to start fresh.', 'wpforo' ); ?></p>
859 <?php else : ?>
860 <p><strong><?php _e( 'Your subscription has been cancelled.', 'wpforo' ); ?></strong></p>
861 <p><?php _e( 'AI features are currently disabled. You can purchase a new plan to reactivate the service, or disconnect to start fresh.', 'wpforo' ); ?></p>
862 <?php endif; ?>
863
864 <p style="color: #666; font-size: 13px;">
865 <?php _e( 'Your indexed content is still preserved. If you purchase a new plan, your data will be restored automatically.', 'wpforo' ); ?>
866 </p>
867 </div>
868
869 <div class="wpforo-ai-error-actions">
870 <button type="button" class="button button-primary button-large" onclick="document.getElementById('wpforo-ai-plans').scrollIntoView({ behavior: 'smooth' })">
871 <span class="dashicons dashicons-cart"></span>
872 <?php _e( 'Purchase New Plan', 'wpforo' ); ?>&nbsp;
873 </button>
874
875 <form method="post" action="" style="display: inline;">
876 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
877 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
878 <button type="submit" class="button button-secondary">
879 <span class="dashicons dashicons-update"></span>
880 <?php _e( 'Check Status', 'wpforo' ); ?>
881 </button>
882 </form>
883
884 <a href="<?php echo esc_url( wpforo_ai_get_manage_subscription_url( $provider ) ); ?>" class="button button-secondary" target="_blank">
885 <span class="dashicons dashicons-admin-generic"></span>
886 <?php printf( __( 'Manage Subscription (%s)', 'wpforo' ), esc_html( ucfirst( $provider ) ) ); ?>
887 </a>
888 </div>
889
890 <!-- Disconnect options -->
891 <div style="margin-top: 25px; padding-top: 20px; border-top: 1px solid #e0e0e0;">
892 <p style="color: #666; font-size: 13px; margin-bottom: 10px;">
893 <?php _e( 'Want to start fresh? Disconnect to remove the current connection and register again.', 'wpforo' ); ?>
894 </p>
895 <button type="button" class="button button-secondary wpforo-ai-disconnect-btn">
896 <span class="dashicons dashicons-dismiss"></span>
897 <?php _e( 'Disconnect Service', 'wpforo' ); ?>
898 </button>
899 <button type="button" class="button button-secondary wpforo-ai-disconnect-purge-btn" style="color: #b32d2e; border-color: #b32d2e;">
900 <span class="dashicons dashicons-trash"></span>
901 <?php _e( 'Disconnect and Remove All Data', 'wpforo' ); ?>
902 </button>
903 </div>
904
905 <div class="wpforo-ai-support-info" style="margin-top: 20px;">
906 <p style="color: #666; font-size: 13px;">
907 <?php
908 printf(
909 __( 'Need help? %s', 'wpforo' ),
910 '<a href="https://wpforo.com/login-register/?tab=login" target="_blank">' . __( 'Open Support Ticket', 'wpforo' ) . '</a>'
911 );
912 ?>
913 </p>
914 </div>
915 </div>
916 </div>
917
918 <!-- Video Tutorials Box -->
919 <?php wpforo_ai_render_video_tutorials(); ?>
920
921 <!-- Plans Section -->
922 <div id="wpforo-ai-plans" class="wpforo-ai-box" style="margin-top: 20px;">
923 <div class="wpforo-ai-box-header">
924 <h2><?php _e( 'Available Plans', 'wpforo' ); ?></h2>
925 </div>
926 <div class="wpforo-ai-box-body">
927 <?php wpforo_ai_render_pricing_table( 'free_trial' ); ?>
928 </div>
929 </div>
930 </div>
931
932 <!-- Hidden Forms for Disconnect (triggered by JS buttons above) -->
933 <div id="wpforo-ai-hidden-forms" style="display:none;">
934 <form id="wpforo-ai-disconnect-form" method="post" action="">
935 <?php wp_nonce_field( 'wpforo_ai_disconnect' ); ?>
936 <input type="hidden" name="wpforo_ai_action" value="disconnect">
937 <div class="wpforo-ai-disconnect-warning">
938 <span class="dashicons dashicons-warning"></span>
939 <p><strong><?php _e( 'Warning: This will disconnect your forum from wpForo AI service.', 'wpforo' ); ?></strong></p>
940 <p><?php _e( 'Your credits will be preserved and restored when you reconnect. Your indexed content will be deleted after 30 days. You can reconnect anytime with the same site URL.', 'wpforo' ); ?></p>
941 </div>
942 <p>
943 <label>
944 <input type="checkbox" name="confirm" value="1" required>
945 <?php _e( 'I understand and want to disconnect the service', 'wpforo' ); ?>
946 </label>
947 </p>
948 <p>
949 <label for="disconnect-reason"><?php _e( 'Reason (optional):', 'wpforo' ); ?></label>
950 <textarea id="disconnect-reason" name="reason" rows="3" class="large-text" placeholder="<?php esc_attr_e( 'Help us improve by telling us why you\'re disconnecting', 'wpforo' ); ?>"></textarea>
951 </p>
952 </form>
953
954 <form id="wpforo-ai-disconnect-purge-form" method="post" action="">
955 <?php wp_nonce_field( 'wpforo_ai_disconnect' ); ?>
956 <input type="hidden" name="wpforo_ai_action" value="disconnect">
957 <input type="hidden" name="purge_data" value="1">
958 <div class="wpforo-ai-disconnect-warning" style="border-left-color: #b32d2e;">
959 <span class="dashicons dashicons-warning" style="color: #b32d2e;"></span>
960 <p><strong style="color: #b32d2e;"><?php _e( 'Warning: This will permanently delete ALL your data from gVectors AI servers.', 'wpforo' ); ?></strong></p>
961 <p><?php _e( 'This action will disconnect your forum and immediately delete all indexed content, embeddings, and tenant data from the AI service. This cannot be undone. Your credits will NOT be preserved.', 'wpforo' ); ?></p>
962 </div>
963 <p>
964 <label>
965 <input type="checkbox" name="confirm" value="1" required>
966 <?php _e( 'I understand that all my data will be permanently deleted and want to proceed', 'wpforo' ); ?>
967 </label>
968 </p>
969 <p>
970 <label for="disconnect-purge-reason"><?php _e( 'Reason (optional):', 'wpforo' ); ?></label>
971 <textarea id="disconnect-purge-reason" name="reason" rows="3" class="large-text" placeholder="<?php esc_attr_e( 'Help us improve by telling us why you\'re removing your data', 'wpforo' ); ?>"></textarea>
972 </p>
973 </form>
974 </div>
975 <?php
976 }
977
978 /**
979 * Render error state (generic errors, not expiry)
980 *
981 * @param WP_Error|array $error Error object or status data
982 */
983 function wpforo_ai_render_error_state( $error ) {
984 $is_wp_error = is_wp_error( $error );
985 $error_message = $is_wp_error ? $error->get_error_message() : __( 'Unable to connect to AI service.', 'wpforo' );
986
987 ?>
988 <div class="wpforo-ai-state wpforo-ai-error-state">
989 <div class="wpforo-ai-box wpforo-ai-error-box">
990 <div class="wpforo-ai-box-header">
991 <h2><?php _e( 'Connection Issue', 'wpforo' ); ?></h2>
992 </div>
993 <div class="wpforo-ai-box-body">
994 <div class="wpforo-ai-status-badge status-error">
995 <span class="dashicons dashicons-dismiss"></span>
996 <?php _e( 'Error', 'wpforo' ); ?>
997 </div>
998
999 <div class="wpforo-ai-error-message">
1000 <p><strong><?php echo esc_html( $error_message ); ?></strong></p>
1001 </div>
1002
1003 <div class="wpforo-ai-error-actions">
1004 <form method="post" action="">
1005 <?php wp_nonce_field( 'wpforo_ai_refresh_status' ); ?>
1006 <input type="hidden" name="wpforo_ai_action" value="refresh_status">
1007 <button type="submit" class="button button-primary">
1008 <span class="dashicons dashicons-update"></span>
1009 <?php _e( 'Retry Connection', 'wpforo' ); ?>
1010 </button>
1011 </form>
1012
1013 <?php if ( ! $is_wp_error ) : ?>
1014 <?php
1015 $err_provider = get_option( 'wpforo_ai_payment_provider', 'freemius' );
1016 ?>
1017 <a href="<?php echo esc_url( wpforo_ai_get_manage_subscription_url( $err_provider ) ); ?>" class="button button-secondary wpf-manage-subscription wpf-provider-<?php echo esc_attr( $err_provider ); ?>" target="_blank">
1018 <span class="dashicons dashicons-admin-generic"></span>
1019 <?php printf( __( 'Manage Subscription (%s)', 'wpforo' ), esc_html( ucfirst( $err_provider ) ) ); ?>
1020 </a>
1021 <?php endif; ?>
1022 </div>
1023
1024 <div class="wpforo-ai-support-info">
1025 <p>
1026 <?php
1027 printf(
1028 __( 'Need help? %s', 'wpforo' ),
1029 '<a href="https://wpforo.com/login-register/?tab=login" target="_blank">' . __( 'Open Support Ticket', 'wpforo' ) . '</a>'
1030 );
1031 ?>
1032 </p>
1033 </div>
1034 </div>
1035 </div>
1036 </div>
1037 <?php
1038 }
1039
1040 /**
1041 * Check if a feature is enabled based on plan hierarchy
1042 *
1043 * @param string $current_plan Current user's plan
1044 * @param string $feature_plan Feature's required plan
1045 * @return bool True if feature should be enabled
1046 */
1047 function wpforo_ai_is_feature_enabled_by_plan( $current_plan, $feature_plan ) {
1048 // Plan hierarchy (lower to higher)
1049 $plan_hierarchy = array(
1050 'free_trial' => 0,
1051 'starter' => 0, // Starter and free_trial are same level
1052 'professional' => 1,
1053 'business' => 2,
1054 'enterprise' => 3,
1055 );
1056
1057 $current_level = isset( $plan_hierarchy[ $current_plan ] ) ? $plan_hierarchy[ $current_plan ] : 0;
1058 $required_level = isset( $plan_hierarchy[ $feature_plan ] ) ? $plan_hierarchy[ $feature_plan ] : 0;
1059
1060 // Feature is enabled if current plan level >= required plan level
1061 return $current_level >= $required_level;
1062 }
1063
1064 /**
1065 * Render features list
1066 *
1067 * @param array $enabled_features List of enabled feature IDs
1068 * @param array $usage Usage statistics per feature
1069 * @param bool $is_free_trial Whether on free trial
1070 * @param array $status Tenant status data from API (required for plan detection)
1071 */
1072 function wpforo_ai_render_features_list( $enabled_features, $usage, $is_free_trial, $status = null ) {
1073 $all_features = wpforo_ai_get_all_features();
1074
1075 // Ensure $enabled_features is an array
1076 if ( ! is_array( $enabled_features ) ) {
1077 $enabled_features = [];
1078 }
1079
1080 // Ensure $usage is an array
1081 if ( ! is_array( $usage ) ) {
1082 $usage = [];
1083 }
1084
1085 // Get current plan from status (passed from parent function)
1086 $current_plan = 'free_trial';
1087 if ( isset( $status['subscription']['plan'] ) ) {
1088 $current_plan = $status['subscription']['plan'];
1089 } elseif ( ! $is_free_trial ) {
1090 // If not free trial but no plan set, assume starter
1091 $current_plan = 'starter';
1092 }
1093
1094 // Group features by plan
1095 $features_by_plan = [
1096 'starter' => [],
1097 'professional' => [],
1098 'business' => [],
1099 'enterprise' => [],
1100 ];
1101
1102 foreach ( $all_features as $feature_id => $feature ) {
1103 $feature_plan = isset( $feature['plan'] ) ? $feature['plan'] : 'professional';
1104 if ( isset( $features_by_plan[ $feature_plan ] ) ) {
1105 $features_by_plan[ $feature_plan ][ $feature_id ] = $feature;
1106 }
1107 }
1108
1109 // Plan display names
1110 $plan_names = [
1111 'starter' => __( 'Starter Features', 'wpforo' ),
1112 'professional' => __( 'Professional Features', 'wpforo' ),
1113 'business' => __( 'Business Features', 'wpforo' ),
1114 'enterprise' => __( 'Enterprise Features', 'wpforo' ),
1115 ];
1116
1117 // Render accordion for each plan
1118 echo '<div class="wpforo-ai-features-accordion">';
1119
1120 foreach ( $features_by_plan as $plan_level => $features ) {
1121 if ( empty( $features ) ) {
1122 continue;
1123 }
1124
1125 $plan_id = 'plan-' . $plan_level;
1126 $is_plan_unlocked = wpforo_ai_is_feature_enabled_by_plan( $current_plan, $plan_level );
1127 $is_current_plan = ( $current_plan === $plan_level );
1128 $plan_status_icon = $is_plan_unlocked ? 'dashicons-yes-alt' : 'dashicons-lock';
1129 $plan_status_class = $is_plan_unlocked ? 'plan-unlocked' : 'plan-locked';
1130
1131 echo '<div class="accordion-item ' . esc_attr( $plan_status_class ) . ( $is_current_plan ? ' current-plan' : '' ) . '">';
1132 echo '<button class="accordion-header" type="button" data-plan="' . esc_attr( $plan_level ) . '" aria-expanded="false" aria-controls="' . esc_attr( $plan_id ) . '">';
1133 echo '<span class="accordion-status-icon dashicons ' . esc_attr( $plan_status_icon ) . '"></span>';
1134 echo '<span class="accordion-title">' . esc_html( $plan_names[ $plan_level ] ) . '</span>';
1135 echo '<span class="accordion-icon dashicons dashicons-arrow-down-alt2"></span>';
1136 echo '</button>';
1137
1138 echo '<div class="accordion-content" id="' . esc_attr( $plan_id ) . '" style="display: none;">';
1139 echo '<ul class="wpforo-ai-features-list">';
1140
1141 foreach ( $features as $feature_id => $feature ) {
1142 // Check if feature is enabled based on plan hierarchy
1143 $is_enabled = in_array( $feature_id, $enabled_features ) || $is_plan_unlocked;
1144 $usage_count = (int) wpfval( $usage, $feature_id, 0 );
1145 $css_class = $is_enabled ? 'feature-enabled' : 'feature-locked';
1146
1147 echo '<li class="' . esc_attr( $css_class ) . '">';
1148 echo '<span class="feature-icon">' . wpforo_ai_get_feature_icon( $feature_id ) . '</span>';
1149 echo '<div class="feature-info">';
1150 echo '<strong>' . esc_html( $feature['name'] ) . '</strong>';
1151 echo '<p>' . esc_html( $feature['description'] ) . '</p>';
1152 echo '</div>';
1153
1154
1155
1156 echo '</li>';
1157 }
1158
1159 echo '</ul>';
1160 echo '</div>'; // .accordion-content
1161 echo '</div>'; // .accordion-item
1162 }
1163
1164 echo '</div>'; // .wpforo-ai-features-accordion
1165 }
1166
1167 /**
1168 * Render features preview list (for "What You'll Get" section)
1169 * Shows all features except enterprise plan when no API key is registered
1170 */
1171 function wpforo_ai_render_features_preview() {
1172 $features = wpforo_ai_get_all_features();
1173
1174 // Only WooCommerce Products indexing is coming soon
1175 $coming_soon_features = [ 'woocommerce_products_indexing' ];
1176
1177 // Plan display names and colors
1178 $plan_labels = [
1179 'starter' => [ 'label' => __( 'Free / Starter', 'wpforo' ), 'class' => 'plan-starter' ],
1180 'professional' => [ 'label' => __( 'Professional', 'wpforo' ), 'class' => 'plan-professional' ],
1181 'business' => [ 'label' => __( 'Business', 'wpforo' ), 'class' => 'plan-business' ],
1182 'enterprise' => [ 'label' => __( 'Enterprise', 'wpforo' ), 'class' => 'plan-enterprise' ],
1183 ];
1184
1185 echo '<ul class="wpforo-ai-features-list wpforo-ai-features-preview">';
1186
1187 foreach ( $features as $feature_id => $feature ) {
1188 // Skip enterprise features in preview
1189 if ( isset( $feature['plan'] ) && $feature['plan'] === 'enterprise' ) {
1190 continue;
1191 }
1192
1193 $is_coming_soon = in_array( $feature_id, $coming_soon_features, true );
1194 $class = $is_coming_soon ? 'feature-pending' : 'feature-enabled';
1195 $plan = $feature['plan'] ?? 'starter';
1196 $plan_info = $plan_labels[ $plan ] ?? $plan_labels['starter'];
1197
1198 echo '<li class="' . esc_attr( $class ) . ' ' . esc_attr( $plan_info['class'] ) . '">';
1199
1200 // Feature icon
1201 echo '<span class="feature-icon">' . wpforo_ai_get_feature_icon( $feature_id ) . '</span>';
1202
1203 // Feature info
1204 echo '<div class="feature-info">';
1205 echo '<strong>' . esc_html( $feature['name'] ) . '</strong>';
1206 if ( $is_coming_soon ) {
1207 echo '<span class="coming-soon-badge">' . esc_html__( 'Coming Soon', 'wpforo' ) . '</span>';
1208 }
1209 echo '<p>' . esc_html( $feature['description'] ) . '</p>';
1210 echo '</div>';
1211
1212 // Plan badge
1213 echo '<span class="plan-badge ' . esc_attr( $plan_info['class'] ) . '">' . esc_html( $plan_info['label'] ) . '</span>';
1214
1215 echo '</li>';
1216 }
1217
1218 // Add "More Coming Soon" teaser
1219 echo '<li class="feature-teaser">';
1220 echo '<span class="feature-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg></span>';
1221 echo '<div class="feature-info">';
1222 echo '<strong>' . __( 'And Many More AI Features Coming Soon!', 'wpforo' ) . '</strong>';
1223 echo '<p>' . __( 'This is just the beginning. We\'re actively developing additional AI features including sentiment analysis, member retention predictions, personalized content feeds, and advanced automation tools. Join our growing community and help shape the future of forum AI.', 'wpforo' ) . '</p>';
1224 echo '</div>';
1225 echo '<span class="plan-badge plan-enterprise">' . esc_html__( 'For All Plans', 'wpforo' ) . '</span>';
1226 echo '</li>';
1227
1228 echo '</ul>';
1229 }
1230
1231 /**
1232 * Render Getting Started Steps Box
1233 *
1234 * Displays a visual progress indicator showing the steps to use wpForo AI.
1235 * First step (Connect) is marked as completed when connected, shows "1" when not.
1236 *
1237 * @param bool $is_connected Whether the user is connected to AI services
1238 */
1239 function wpforo_ai_render_getting_started_steps( $is_connected = true ) {
1240 // Build URLs for each step
1241 $indexing_url = admin_url( 'admin.php?page=wpforo-ai&tab=rag_indexing' );
1242 $settings_url = admin_url( 'admin.php?page=wpforo-settings&wpf_tab=ai' );
1243 $spam_url = admin_url( 'admin.php?page=wpforo-settings&wpf_tab=ai#moderation_spam' );
1244 $forum_url = wpforo_home_url();
1245 $logs_url = admin_url( 'admin.php?page=wpforo-ai&tab=ai_logs' );
1246 ?>
1247 <div class="wpforo-ai-box wpforo-ai-getting-started-box">
1248 <div class="wpforo-ai-box-header">
1249 <h2><?php _e( 'Getting Started with wpForo AI', 'wpforo' ); ?></h2>
1250 </div>
1251 <div class="wpforo-ai-box-body">
1252 <div class="wpforo-ai-steps">
1253 <div class="wpforo-ai-step <?php echo $is_connected ? 'completed' : ''; ?>">
1254 <div class="wpforo-ai-step-icon">
1255 <?php if ( $is_connected ) : ?>
1256 <span class="dashicons dashicons-yes-alt"></span>
1257 <?php else : ?>
1258 <span class="wpforo-ai-step-number">1</span>
1259 <?php endif; ?>
1260 </div>
1261 <div class="wpforo-ai-step-label"><?php _e( 'Connect wpForo AI', 'wpforo' ); ?></div>
1262 </div>
1263 <div class="wpforo-ai-step-connector"></div>
1264 <?php if ( $is_connected ) : ?>
1265 <a href="<?php echo esc_url( $indexing_url ); ?>" class="wpforo-ai-step">
1266 <?php else : ?>
1267 <div class="wpforo-ai-step">
1268 <?php endif; ?>
1269 <div class="wpforo-ai-step-icon">
1270 <span class="wpforo-ai-step-number">2</span>
1271 </div>
1272 <div class="wpforo-ai-step-label" style="color: rgb(214, 39, 224);"><?php _e( 'Index Forum Content', 'wpforo' ); ?></div>
1273 <?php echo $is_connected ? '</a>' : '</div>'; ?>
1274 <div class="wpforo-ai-step-connector"></div>
1275 <?php if ( $is_connected ) : ?>
1276 <a href="<?php echo esc_url( $settings_url ); ?>" class="wpforo-ai-step">
1277 <?php else : ?>
1278 <div class="wpforo-ai-step">
1279 <?php endif; ?>
1280 <div class="wpforo-ai-step-icon">
1281 <span class="wpforo-ai-step-number">3</span>
1282 </div>
1283 <div class="wpforo-ai-step-label"><?php _e( 'Manage AI Features', 'wpforo' ); ?></div>
1284 <?php echo $is_connected ? '</a>' : '</div>'; ?>
1285 <div class="wpforo-ai-step-connector"></div>
1286 <?php if ( $is_connected ) : ?>
1287 <a href="<?php echo esc_url( $forum_url ); ?>" class="wpforo-ai-step" target="_blank">
1288 <?php else : ?>
1289 <div class="wpforo-ai-step">
1290 <?php endif; ?>
1291 <div class="wpforo-ai-step-icon">
1292 <span class="wpforo-ai-step-number">4</span>
1293 </div>
1294 <div class="wpforo-ai-step-label"><?php _e( 'Use', 'wpforo' ); ?><br><?php _e( 'AI Features', 'wpforo' ); ?></div>
1295 <?php echo $is_connected ? '</a>' : '</div>'; ?>
1296 <div class="wpforo-ai-step-connector"></div>
1297 <?php if ( $is_connected ) : ?>
1298 <a href="<?php echo esc_url( $spam_url ); ?>" class="wpforo-ai-step">
1299 <?php else : ?>
1300 <div class="wpforo-ai-step">
1301 <?php endif; ?>
1302 <div class="wpforo-ai-step-icon">
1303 <span class="wpforo-ai-step-number">5</span>
1304 </div>
1305 <div class="wpforo-ai-step-label"><?php _e( 'Enable AI Spam Protection', 'wpforo' ); ?></div>
1306 <?php echo $is_connected ? '</a>' : '</div>'; ?>
1307 <div class="wpforo-ai-step-connector"></div>
1308 <?php if ( $is_connected ) : ?>
1309 <a href="<?php echo esc_url( $logs_url ); ?>" class="wpforo-ai-step">
1310 <?php else : ?>
1311 <div class="wpforo-ai-step">
1312 <?php endif; ?>
1313 <div class="wpforo-ai-step-icon">
1314 <span class="wpforo-ai-step-number">6</span>
1315 </div>
1316 <div class="wpforo-ai-step-label"><?php _e( 'Monitor AI Usage', 'wpforo' ); ?></div>
1317 <?php echo $is_connected ? '</a>' : '</div>'; ?>
1318 </div>
1319 <div class="wpforo-ai-privacy-note">
1320 <p><span class="dashicons dashicons-shield" style="color: #0073aa;"></span> <strong><?php _e( 'Your Data Stays Yours', 'wpforo' ); ?></strong></p>
1321 <ul>
1322 <li><strong style="color: rgb(214, 39, 224);"><?php _e( 'Forum content indexing', 'wpforo' ); ?></strong> <?php _e( 'converts your forum content into mathematical vectors (embeddings) to power AI search and features.', 'wpforo' ); ?></li>
1323 <li><?php _e( 'Your data is never used to train AI models. We use pre-trained models from Amazon Bedrock.', 'wpforo' ); ?></li>
1324 <li><?php _e( 'By default your data embeddings are stored locally in your WordPress database.', 'wpforo' ); ?></li>
1325 </ul>
1326 </div>
1327 <div class="wpforo-ai-steps-cta">
1328 <a href="https://wpforo.com/docs/wpforo-v3/ai-features/#getting-started" target="_blank" class="button button-primary button-hero">
1329 <span class="dashicons dashicons-book" style="vertical-align: middle; margin-right: 5px;"></span>
1330 <?php _e( 'Read AI Features Documentation', 'wpforo' ); ?>
1331 </a>
1332 </div>
1333 </div>
1334 </div>
1335 <style>
1336 .wpforo-ai-privacy-note {
1337 background: #f0f7fc;
1338 border-left: 4px solid #0073aa;
1339 padding: 15px 20px;
1340 margin: 20px 0;
1341 border-radius: 0 4px 4px 0;
1342 }
1343 .wpforo-ai-privacy-note p {
1344 margin: 0 0 10px 0;
1345 font-size: 14px;
1346 }
1347 .wpforo-ai-privacy-note ul {
1348 margin: 0;
1349 padding-left: 20px;
1350 }
1351 .wpforo-ai-privacy-note li {
1352 margin-bottom: 5px;
1353 font-size: 13px;
1354 color: #444;
1355 }
1356 .wpforo-ai-getting-started-box {
1357 margin-bottom: 20px;
1358 }
1359 .wpforo-ai-steps-cta {
1360 text-align: center;
1361 margin-top: 10px;
1362 padding-top: 20px;
1363 border-top: 1px solid #e0e0e0;
1364 }
1365 .wpforo-ai-steps-cta .button-hero {
1366 font-size: 15px;
1367 padding: 10px 25px;
1368 height: auto;
1369 }
1370 .wpforo-ai-steps {
1371 display: flex;
1372 align-items: center;
1373 justify-content: center;
1374 padding: 30px 20px;
1375 gap: 0;
1376 }
1377 .wpforo-ai-step {
1378 display: flex;
1379 flex-direction: column;
1380 align-items: center;
1381 text-decoration: none;
1382 color: #1d2327;
1383 transition: transform 0.2s ease;
1384 }
1385 a.wpforo-ai-step:hover {
1386 transform: translateY(-3px);
1387 }
1388 a.wpforo-ai-step:hover .wpforo-ai-step-icon {
1389 background: #2271b1;
1390 color: #fff;
1391 border-color: #2271b1;
1392 }
1393 .wpforo-ai-step-icon {
1394 width: 50px;
1395 height: 50px;
1396 border-radius: 50%;
1397 background: #f0f0f1;
1398 border: 2px solid #c3c4c7;
1399 display: flex;
1400 align-items: center;
1401 justify-content: center;
1402 margin-bottom: 10px;
1403 transition: all 0.2s ease;
1404 }
1405 a.wpforo-ai-step .wpforo-ai-step-icon {
1406 background: #edfaef;
1407 border-color: #00a32a;
1408 }
1409 a.wpforo-ai-step .wpforo-ai-step-number {
1410 color: #00a32a;
1411 }
1412 .wpforo-ai-step.completed .wpforo-ai-step-icon {
1413 background: #00a32a;
1414 border-color: #00a32a;
1415 color: #fff;
1416 }
1417 .wpforo-ai-step.completed .wpforo-ai-step-icon .dashicons {
1418 font-size: 24px;
1419 width: 24px;
1420 height: 24px;
1421 }
1422 .wpforo-ai-step-number {
1423 font-size: 18px;
1424 font-weight: 600;
1425 color: #50575e;
1426 }
1427 a.wpforo-ai-step:hover .wpforo-ai-step-number {
1428 color: #fff;
1429 }
1430 .wpforo-ai-step-label {
1431 font-size: 13px;
1432 font-weight: 500;
1433 text-align: center;
1434 max-width: 100px;
1435 line-height: 1.3;
1436 }
1437 .wpforo-ai-step-connector {
1438 width: 40px;
1439 height: 2px;
1440 background: #c3c4c7;
1441 margin: 0 5px;
1442 margin-bottom: 30px;
1443 }
1444 @media (max-width: 900px) {
1445 .wpforo-ai-steps {
1446 flex-wrap: wrap;
1447 gap: 15px;
1448 }
1449 .wpforo-ai-step-connector {
1450 display: none;
1451 }
1452 }
1453 </style>
1454 <?php
1455 }
1456
1457 /**
1458 * Render Video Tutorials Box
1459 *
1460 * Displays 3 YouTube video tutorials in a 3-column grid layout.
1461 * Shown on the AI Features overview page between connection status and features list.
1462 */
1463 function wpforo_ai_render_video_tutorials() {
1464 $videos = [
1465 [
1466 'url' => 'https://www.youtube.com/watch?v=ZmNEAYSWg8M',
1467 'title' => __( 'wpForo AI Search', 'wpforo' ),
1468 ],
1469 [
1470 'url' => 'https://www.youtube.com/watch?v=Pq5BvlrkXwE',
1471 'title' => __( 'wpForo AI Topic Summary', 'wpforo' ),
1472 ],
1473 [
1474 'url' => 'https://www.youtube.com/watch?v=2NmKtJO6miQ',
1475 'title' => __( 'wpForo AI Translation', 'wpforo' ),
1476 ],
1477 ];
1478 ?>
1479 <div class="wpforo-ai-box wpforo-ai-video-tutorials-box">
1480 <div class="wpforo-ai-box-header">
1481 <h2><?php _e( 'wpForo AI Features in Action', 'wpforo' ); ?></h2>
1482 </div>
1483 <div class="wpforo-ai-box-body">
1484 <div class="wpforo-ai-videos-grid">
1485 <?php foreach ( $videos as $video ) : ?>
1486 <div class="wpforo-ai-video-item">
1487 <div class="wpforo-ai-video-wrapper">
1488 <?php echo wp_oembed_get( $video['url'] ); ?>
1489 </div>
1490 <h4 class="wpforo-ai-video-title"><?php echo esc_html( $video['title'] ); ?></h4>
1491 </div>
1492 <?php endforeach; ?>
1493 </div>
1494 <div class="wpforo-ai-videos-cta">
1495 <a href="https://wpforo.com/#ai-features" target="_blank" class="button button-primary button-hero">
1496 <span class="dashicons dashicons-video-alt3" style="vertical-align: middle; margin-right: 5px;"></span>
1497 <?php _e( 'See All AI Features', 'wpforo' ); ?>
1498 </a>
1499 </div>
1500 </div>
1501 </div>
1502 <style>
1503 .wpforo-ai-video-tutorials-box {
1504 margin-bottom: 20px;
1505 }
1506 .wpforo-ai-videos-cta {
1507 text-align: center;
1508 margin-top: 20px;
1509 padding-top: 20px;
1510 border-top: 1px solid #e0e0e0;
1511 }
1512 .wpforo-ai-videos-cta .button-hero {
1513 font-size: 15px;
1514 padding: 10px 25px;
1515 height: auto;
1516 }
1517 .wpforo-ai-videos-grid {
1518 display: grid;
1519 grid-template-columns: repeat(3, 1fr);
1520 gap: 20px;
1521 }
1522 .wpforo-ai-video-item {
1523 background: #f9f9f9;
1524 border-radius: 8px;
1525 overflow: hidden;
1526 }
1527 .wpforo-ai-video-wrapper {
1528 position: relative;
1529 padding-bottom: 56.25%;
1530 height: 0;
1531 overflow: hidden;
1532 }
1533 .wpforo-ai-video-wrapper iframe {
1534 position: absolute;
1535 top: 0;
1536 left: 0;
1537 width: 100%;
1538 height: 100%;
1539 border-radius: 8px 8px 0 0;
1540 }
1541 .wpforo-ai-video-title {
1542 margin: 0;
1543 padding: 12px 15px;
1544 font-size: 14px;
1545 font-weight: 600;
1546 color: #1d2327;
1547 text-align: center;
1548 background: #fff;
1549 border-top: 1px solid #e0e0e0;
1550 }
1551 @media (max-width: 1200px) {
1552 .wpforo-ai-videos-grid {
1553 grid-template-columns: repeat(2, 1fr);
1554 }
1555 }
1556 @media (max-width: 782px) {
1557 .wpforo-ai-videos-grid {
1558 grid-template-columns: 1fr;
1559 }
1560 }
1561 </style>
1562 <?php
1563 }
1564
1565 /**
1566 * Get all available features with metadata
1567 *
1568 * @return array Features array
1569 */
1570 function wpforo_ai_get_all_features() {
1571 return apply_filters( 'wpforo_ai_features', [
1572 'content_indexing' => [
1573 'name' => __( 'AI Knowledge Generation - Forum Content Indexing & Vectorization', 'wpforo' ),
1574 'description' => __( 'Index forum content to build a searchable vector database optimized for Retrieval Augmented Generation (RAG). This feature transforms unstructured forum discussions, threads, and posts into semantic vectors, enabling AI that truly understands your domain, products, and audience.', 'wpforo' ),
1575 'plan' => 'starter',
1576 'preview' => false,
1577 ],
1578 'vector_db_local_storage' => [
1579 'name' => __( 'AI Indexed Vector Database - Local Storage', 'wpforo' ),
1580 'description' => __( 'Store AI-generated vector embeddings locally on your WordPress server. Perfect for smaller forums or sites with storage capacity. Vectors are stored in your database, giving you full control over your data while enabling semantic search and AI features without external dependencies.', 'wpforo' ),
1581 'plan' => 'starter',
1582 'preview' => false,
1583 ],
1584 'semantic_search' => [
1585 'name' => __( "AI Powered Semantic Search", 'wpforo' ),
1586 'description' => __( "Traditional search fails when users don't know exact keywords. Stop losing members to \"no results found\". AI-powered semantic search understands what users mean, not just what they type. Find relevant discussions even with different wording, typos, or synonyms—delivering answers that actually help.", 'wpforo' ),
1587 'plan' => 'starter',
1588 'preview' => true,
1589 ],
1590 'search_enhance' => [
1591 'name' => __( 'AI Search Enhancement', 'wpforo' ),
1592 'description' => __( 'Elevate search results with AI-powered summaries and recommendations. When users search, AI analyzes the results and generates a contextual summary explaining how each result relates to the query. Get intelligent suggestions for related topics and better answers instantly.', 'wpforo' ),
1593 'plan' => 'starter',
1594 'preview' => true,
1595 ],
1596 'topic_summary' => [
1597 'name' => __( 'AI Topic Summarization', 'wpforo' ),
1598 'description' => __( 'Get instant AI-generated summaries of long forum discussions. Help members quickly understand the key points, main conclusions, and important details of any topic without reading through hundreds of replies. Perfect for catching up on active discussions or reviewing complex threads at a glance.', 'wpforo' ),
1599 'plan' => 'starter',
1600 'preview' => true,
1601 ],
1602 'smart_topic_suggestions' => [
1603 'name' => __( 'AI Topic Suggestions', 'wpforo' ),
1604 'description' => __( 'Enhance topic creation with intelligent suggestions. AI analyzes what members are typing and instantly recommends similar existing discussions, related topics, and potential answers. Reduce duplicate posts, improve search visibility, and help users discover solutions before they even ask—all in real-time.', 'wpforo' ),
1605 'plan' => 'starter',
1606 'preview' => true,
1607 ],
1608 'multi_language_translation' => [
1609 'name' => __( 'AI Multi-Language Translation', 'wpforo' ),
1610 'description' => __( 'Break language barriers and grow your global community. No more limiting your community to one language. Multi-language AI translation lets members from anywhere participate naturally. Each user sees content in their language, posts in their language, and AI bridges the gap—no manual translation needed.', 'wpforo' ),
1611 'plan' => 'starter',
1612 'preview' => true,
1613 ],
1614 'ai_spam_detection' => [
1615 'name' => __( 'AI Moderation - Spam Detection and User Banning', 'wpforo' ),
1616 'description' => __( 'Keep your forum clean with intelligent spam detection. AI automatically identifies spam content after post submission, blocking malicious posts before they appear while learning from your moderation decisions to improve accuracy.', 'wpforo' ),
1617 'plan' => 'starter',
1618 'preview' => true,
1619 ],
1620 'ai_toxicity_detection' => [
1621 'name' => __( 'AI Moderation - Content Safety & Toxicity Detection', 'wpforo' ),
1622 'description' => __( 'Protect your community from harmful content with advanced toxicity detection. AI analyzes posts for hate speech, harassment, personal attacks, threats, and other toxic behavior. Configurable severity thresholds let you set how aggressively to filter content, while automated actions like unapproval or user banning help maintain a respectful environment without constant manual moderation.', 'wpforo' ),
1623 'plan' => 'starter',
1624 'preview' => false,
1625 ],
1626 'ai_rule_compliance' => [
1627 'name' => __( 'AI Moderation - Rule Compliance & Policy Enforcement', 'wpforo' ),
1628 'description' => __( 'Automatically enforce your forum rules and community guidelines. AI checks every post against configurable policies including topic relevance, promotional content restrictions, and illegal content detection. Smart keyword pre-filtering catches obvious violations instantly without API calls, while nuanced cases receive full AI analysis. Define custom rules for your community and let AI ensure members stay on topic and follow your guidelines.', 'wpforo' ),
1629 'plan' => 'starter',
1630 'preview' => false,
1631 ],
1632 'forum_image_indexing' => [
1633 'name' => __( 'AI Knowledge Generation - Forum Image Indexing & Vectorization', 'wpforo' ),
1634 'description' => __( 'Unlock the power of visual content in your forum. AI automatically analyzes images embedded in posts—screenshots, diagrams, infographics, product photos—and generates rich semantic embeddings. Visual information is indexed alongside text, enabling AI search and chat to understand and retrieve content based on what images show, not just surrounding text. Perfect for technical forums, support communities, and visual-heavy discussions.', 'wpforo' ),
1635 'plan' => 'professional',
1636 'preview' => false,
1637 ],
1638 'forum_document_indexing' => [
1639 'name' => __( 'AI Knowledge Generation - Forum Document Indexing & Vectorization', 'wpforo' ),
1640 'description' => __( 'Transform document attachments into searchable knowledge. AI automatically extracts text from PDF, Word (DOCX), PowerPoint (PPTX), RTF, and plain text files attached to forum posts. Extracted content is chunked, embedded, and indexed alongside regular post text, making document contents fully searchable through AI semantic search and accessible to the AI chatbot. Ideal for forums with manuals, guides, reports, and technical documentation shared as attachments.', 'wpforo' ),
1641 'plan' => 'professional',
1642 'preview' => false,
1643 ],
1644 'ai_bot_reply' => [
1645 'name' => __( 'AI Bot Reply and Reply Suggestion', 'wpforo' ),
1646 'description' => __( 'Generate AI-powered replies manually with a single click or use the Suggest Reply button to get AI-generated content directly in the editor. Moderators can trigger bot replies from any post, or use the suggest feature to draft responses based on forum context, topic content, and AI knowledge base.', 'wpforo' ),
1647 'plan' => 'professional',
1648 'preview' => true,
1649 ],
1650 'ai_topic_generator' => [
1651 'name' => __( 'AI Tasks - Automated Topic Generation', 'wpforo' ),
1652 'description' => __( 'Keep your forum active with AI-generated topics! The AI analyzes your existing discussions and automatically creates engaging threads based on your instructions every day or in any time period you want. Topics appear naturally from AI created users or pre-defined users, sparking fresh conversations. The AI can search for trending news and current issues related to your community, then create timely, relevant topics that drive engagement.', 'wpforo' ),
1653 'plan' => 'professional',
1654 'preview' => true,
1655 ],
1656 'ai_reply_generator' => [
1657 'name' => __( 'AI Tasks - Automated Reply Generation', 'wpforo' ),
1658 'description' => __( 'Boost engagement with intelligent reply generation. AI monitors your forum for unanswered topics, analyzes context from existing discussions and knowledge base, and automatically posts helpful, relevant responses through bot users. Configure reply frequency, tone, and trigger conditions to maintain authentic community interaction.', 'wpforo' ),
1659 'plan' => 'professional',
1660 'preview' => true,
1661 ],
1662 'auto_tag_generation' => [
1663 'name' => __( 'AI Tasks - Automated Topic Tag Moderation', 'wpforo' ),
1664 'description' => __( 'Improve content discovery with smart tag management. Complete tag management powered by AI. Automatically generates relevant tags for new and existing topics, removes outdated or irrelevant tags, maintains consistent tag vocabulary, identifies duplicate tags, and suggests related keywords. Self-cleaning system ensures your tag structure stays organized as your forum evolves while leaving existing topics untouched to preserve forum integrity.', 'wpforo' ),
1665 'plan' => 'professional',
1666 'preview' => true,
1667 ],
1668 'analytics_insights' => [
1669 'name' => __( 'AI Analytics & Insights', 'wpforo' ),
1670 'description' => __( 'Stop guessing what your community wants. AI Analytics reveals hidden patterns in member behavior. Comprehensive AI-driven analytics for smarter community management. Monitor real-time engagement metrics, track topic performance, identify trending discussions, discover underserved content areas, and receive personalized growth recommendations. Advanced sentiment analysis, member retention insights, and predictive trends help you stay ahead.', 'wpforo' ),
1671 'plan' => 'professional',
1672 'preview' => true,
1673 ],
1674 'ai_assistant_chatbot' => [
1675 'name' => __( 'AI Chat Assistant', 'wpforo' ),
1676 'description' => __( '24/7 intelligent assistance for your forum members. Intelligent chatbot powered by your forum\'s content. Provides instant answers based on indexed discussions, suggests relevant topics, guides new members through common tasks, and escalates complex questions to moderators when needed. Learns from interactions, supports multiple languages, and maintains your community\'s tone and style.', 'wpforo' ),
1677 'plan' => 'business',
1678 'preview' => false,
1679 ],
1680 'vector_db_cloud_storage' => [
1681 'name' => __( 'AI Indexed Vector Database - Cloud Storage', 'wpforo' ),
1682 'description' => __( 'Scale your AI capabilities with cloud-based vector storage powered by AWS S3 Vectors. Ideal for large forums with thousands of posts and growing communities. Cloud storage provides unlimited scalability, faster query performance, automatic backups, and enterprise-grade reliability for your AI knowledge base.', 'wpforo' ),
1683 'plan' => 'business',
1684 'preview' => false,
1685 ],
1686 'extended_knowledge_base' => [
1687 'name' => __( 'Extended Knowledge Base', 'wpforo' ),
1688 'description' => __( 'Expand AI knowledge beyond forum content to include WordPress posts, pages, and products.', 'wpforo' ),
1689 'plan' => 'business',
1690 'preview' => false,
1691 ],
1692 'wordpress_content_indexing' => [
1693 'name' => __( 'WordPress Content Indexing', 'wpforo' ),
1694 'description' => __( 'Index WordPress posts and pages for comprehensive site-wide AI search.', 'wpforo' ),
1695 'plan' => 'business',
1696 'preview' => false,
1697 ],
1698 'custom_post_types_indexing' => [
1699 'name' => __( 'Custom Post Types Indexing', 'wpforo' ),
1700 'description' => __( 'Include custom post types in AI knowledge base for complete content coverage.', 'wpforo' ),
1701 'plan' => 'business',
1702 'preview' => false,
1703 ],
1704 'woocommerce_products_indexing' => [
1705 'name' => __( 'WooCommerce Products Indexing', 'wpforo' ),
1706 'description' => __( 'Index WooCommerce products to provide AI-powered product search and support.', 'wpforo' ),
1707 'plan' => 'business',
1708 'preview' => false,
1709 ],
1710 'custom_knowledge_indexing' => [
1711 'name' => __( 'Custom Knowledge Indexing', 'wpforo' ),
1712 'description' => __( 'Upload and index custom knowledge files (JSON, Markdown, Text) to enhance AI responses with your expert documentation, FAQs, and specialized content. Perfect for product manuals, internal guides, and domain-specific knowledge bases.', 'wpforo' ),
1713 'plan' => 'business',
1714 'preview' => false,
1715 ],
1716 'file_indexing' => [
1717 'name' => __( 'File Indexing (TXT, MD, JSON, PDF)', 'wpforo' ),
1718 'description' => __( 'Index plain text, Markdown, JSON, and PDF files into the AI knowledge base for richer answers from custom documentation and reference material. Scanned PDFs are auto-OCR\'d when the text layer is too sparse.', 'wpforo' ),
1719 'plan' => 'business',
1720 'preview' => false,
1721 ],
1722 'developer_features' => [
1723 'name' => __( 'Developer Features', 'wpforo' ),
1724 'description' => __( 'Advanced developer tools and API access for custom integrations.', 'wpforo' ),
1725 'plan' => 'enterprise',
1726 'preview' => false,
1727 ],
1728 'rest_api_access' => [
1729 'name' => __( 'REST API Access', 'wpforo' ),
1730 'description' => __( 'Full REST API access for custom applications and third-party integrations.', 'wpforo' ),
1731 'plan' => 'enterprise',
1732 'preview' => false,
1733 ],
1734 'custom_ai_models' => [
1735 'name' => __( 'Custom AI Models', 'wpforo' ),
1736 'description' => __( 'Use custom-trained AI models tailored to your specific community needs.', 'wpforo' ),
1737 'plan' => 'enterprise',
1738 'preview' => false,
1739 ],
1740 'custom_feature_development' => [
1741 'name' => __( 'Custom feature development', 'wpforo' ),
1742 'description' => __( 'Dedicated development resources for custom AI features unique to your forum.', 'wpforo' ),
1743 'plan' => 'enterprise',
1744 'preview' => false,
1745 ],
1746 'premium_support' => [
1747 'name' => __( 'Premium Support', 'wpforo' ),
1748 'description' => __( 'Priority support with dedicated account management and faster response times.', 'wpforo' ),
1749 'plan' => 'enterprise',
1750 'preview' => false,
1751 ],
1752 'dedicated_account_manager' => [
1753 'name' => __( 'Dedicated account manager', 'wpforo' ),
1754 'description' => __( 'Personal account manager for strategic guidance and priority assistance.', 'wpforo' ),
1755 'plan' => 'enterprise',
1756 'preview' => false,
1757 ],
1758 'enterprise_capabilities' => [
1759 'name' => __( 'Enterprise Capabilities', 'wpforo' ),
1760 'description' => __( 'Enterprise-grade features including SLA, compliance support, and advanced security.', 'wpforo' ),
1761 'plan' => 'enterprise',
1762 'preview' => false,
1763 ],
1764 ] );
1765 }
1766
1767 /**
1768 * Get SVG icon for a feature
1769 *
1770 * @param string $feature_id Feature identifier
1771 * @return string SVG icon markup
1772 */
1773 function wpforo_ai_get_feature_icon( $feature_id ) {
1774 $icons = [
1775 // Free Features - Vector Database Storage
1776 'vector_db_local_storage' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/><path d="M3 12c0 1.66 4 3 9 3s9-1.34 9-3"/><path d="M12 12v5"/><path d="M9 14.5l3 2.5 3-2.5"/></svg>',
1777 'vector_db_cloud_storage' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M17.5 19H9a7 7 0 1 1 6.71-9h1.79a4.5 4.5 0 1 1 0 9Z"/><path d="M12 13v5"/><path d="M9.5 15.5l2.5 2.5 2.5-2.5"/></svg>',
1778 // Starter Features
1779 'semantic_search' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.3-4.3"/><path d="M11 8a3 3 0 0 0-3 3"/></svg>',
1780 'content_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/><path d="M3 12c0 1.66 4 3 9 3s9-1.34 9-3"/></svg>',
1781 'image_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/></svg>',
1782 'document_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>',
1783 'multi_language_translation' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M12 2a14.5 14.5 0 0 0 0 20 14.5 14.5 0 0 0 0-20"/><path d="M2 12h20"/></svg>',
1784 'topic_summary' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72Z"/><path d="m14 7 3 3"/><path d="M5 6v4"/><path d="M19 14v4"/><path d="M10 2v2"/><path d="M7 8H3"/><path d="M21 16h-4"/><path d="M11 3H9"/></svg>',
1785 'smart_topic_suggestions' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>',
1786 'topic_suggestions' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>',
1787 'ai_topic_generator' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.375 2.625a2.121 2.121 0 1 1 3 3L12 15l-4 1 1-4Z"/></svg>',
1788 'ai_reply_generator' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/><path d="M8 10h8"/><path d="M8 14h4"/></svg>',
1789 'ai_bot_reply' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="10" x="3" y="11" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><path d="M8 16h0"/><path d="M16 16h0"/><path d="m2 2 2 2"/><path d="m22 2-2 2"/></svg>',
1790 'forum_image_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="18" x="3" y="3" rx="2" ry="2"/><circle cx="9" cy="9" r="2"/><path d="m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"/><path d="M14 3v4"/><path d="M21 10h-4"/></svg>',
1791 'forum_document_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/><path d="M14 2v4"/><path d="M20 9h-4"/></svg>',
1792 'automatic_faq_generation' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><path d="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3"/><path d="M12 17h.01"/></svg>',
1793 'auto_tag_generation' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12.586 2.586A2 2 0 0 0 11.172 2H4a2 2 0 0 0-2 2v7.172a2 2 0 0 0 .586 1.414l8.704 8.704a2.426 2.426 0 0 0 3.42 0l6.58-6.58a2.426 2.426 0 0 0 0-3.42z"/><circle cx="7.5" cy="7.5" r="1.5"/></svg>',
1794 'analytics_insights' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 3v18h18"/><path d="m19 9-5 5-4-4-3 3"/></svg>',
1795 // Professional Features - Content Moderation
1796 'ai_spam_detection' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z"/><path d="m9 12 2 2 4-4"/></svg>',
1797 'ai_toxicity_detection' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/></svg>',
1798 'ai_rule_compliance' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="m9 15 2 2 4-4"/></svg>',
1799 'unified_moderation' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/><path d="m9 12 2 2 4-4"/></svg>',
1800 'ai_assistant_chatbot' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="18" height="10" x="3" y="11" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/><path d="M8 16h0"/><path d="M16 16h0"/></svg>',
1801 // Business Features
1802 'extended_knowledge_base' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/><path d="M8 7h6"/><path d="M8 11h8"/></svg>',
1803 'wordpress_content_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"/><path d="M14 2v4a2 2 0 0 0 2 2h4"/><path d="M10 9H8"/><path d="M16 13H8"/><path d="M16 17H8"/></svg>',
1804 'custom_post_types_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="m12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83Z"/><path d="m22 17.65-9.17 4.16a2 2 0 0 1-1.66 0L2 17.65"/><path d="m22 12.65-9.17 4.16a2 2 0 0 1-1.66 0L2 12.65"/></svg>',
1805 'woocommerce_products_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><circle cx="8" cy="21" r="1"/><circle cx="19" cy="21" r="1"/><path d="M2.05 2.05h2l2.66 12.42a2 2 0 0 0 2 1.58h9.78a2 2 0 0 0 1.95-1.57l1.65-7.43H5.12"/></svg>',
1806 'custom_knowledge_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H19a1 1 0 0 1 1 1v18a1 1 0 0 1-1 1H6.5a1 1 0 0 1 0-5H20"/><path d="M8 11h8"/><path d="M8 7h6"/><circle cx="12" cy="15" r="1"/></svg>',
1807 'file_indexing' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/><path d="M8 13h8"/><path d="M8 17h5"/></svg>',
1808 // Enterprise Features
1809 'developer_features' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>',
1810 'rest_api_access' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M18 20V10"/><path d="M12 20V4"/><path d="M6 20v-6"/><circle cx="18" cy="7" r="3"/><circle cx="6" cy="11" r="3"/></svg>',
1811 'custom_ai_models' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2a4 4 0 0 0-4 4v2H6a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V10a2 2 0 0 0-2-2h-2V6a4 4 0 0 0-4-4z"/><circle cx="12" cy="14" r="2"/><path d="M12 16v2"/></svg>',
1812 'custom_feature_development' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>',
1813 'premium_support' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M3 11h3a2 2 0 0 1 2 2v3a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-5Zm0 0a9 9 0 1 1 18 0m0 0v5a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3Z"/></svg>',
1814 'dedicated_account_manager' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/></svg>',
1815 'enterprise_capabilities' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><rect width="16" height="20" x="4" y="2" rx="2" ry="2"/><path d="M9 22v-4h6v4"/><path d="M8 6h.01"/><path d="M16 6h.01"/><path d="M12 6h.01"/><path d="M12 10h.01"/><path d="M12 14h.01"/><path d="M16 10h.01"/><path d="M16 14h.01"/><path d="M8 10h.01"/><path d="M8 14h.01"/></svg>',
1816 ];
1817
1818 // Return the icon or a default one
1819 if ( isset( $icons[ $feature_id ] ) ) {
1820 return $icons[ $feature_id ];
1821 }
1822
1823 // Default icon (star)
1824 return '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2"/></svg>';
1825 }
1826
1827 /**
1828 * Render usage statistics
1829 *
1830 * @param array $usage Usage data (since last credit purchase)
1831 * @param int $total_credits Total credits used
1832 * @param array $usage_lifetime Lifetime usage data (optional)
1833 * @param string $current_plan Current subscription plan (optional)
1834 */
1835 function wpforo_ai_render_usage_stats( $usage, $total_credits, $usage_lifetime = [], $current_plan = 'free_trial' ) {
1836 // Ensure $total_credits is an integer
1837 $total_credits = (int) $total_credits;
1838
1839 $features = wpforo_ai_get_all_features();
1840 $has_lifetime = ! empty( $usage_lifetime );
1841
1842 echo '<div class="wpforo-ai-usage-stats">';
1843 echo '<div class="usage-summary">';
1844 echo '<div class="usage-stat-item">';
1845 echo '<span class="stat-icon dashicons dashicons-chart-bar"></span>';
1846 echo '<div class="stat-info">';
1847 echo '<strong>' . number_format( $total_credits ) . '</strong>';
1848 echo '<span class="stat-label">' . __( 'Lifetime Credits Used', 'wpforo' ) . '</span>';
1849 echo '</div>';
1850 echo '</div>';
1851 echo '</div>';
1852
1853 echo '<table class="wpforo-ai-usage-table">';
1854 echo '<thead>';
1855 echo '<tr>';
1856 echo '<th>' . __( 'Feature', 'wpforo' ) . '</th>';
1857 echo '<th>' . __( 'Since Last Purchase', 'wpforo' ) . '</th>';
1858 if ( $has_lifetime ) {
1859 echo '<th>' . __( 'Lifetime Total', 'wpforo' ) . '</th>';
1860 }
1861 echo '</tr>';
1862 echo '</thead>';
1863 echo '<tbody>';
1864
1865 // Get all features available for the current plan
1866 $plan_features = [];
1867 // Skip storage features and sub-indexing features (their credits are summed into content_indexing)
1868 $skip_features = [ 'vector_db_local_storage', 'vector_db_cloud_storage', 'forum_image_indexing', 'forum_document_indexing' ];
1869 foreach ( $features as $feature_id => $feature_data ) {
1870 // Skip storage features from usage statistics
1871 if ( in_array( $feature_id, $skip_features, true ) ) {
1872 continue;
1873 }
1874
1875 $feature_plan = isset( $feature_data['plan'] ) ? $feature_data['plan'] : 'starter';
1876 $feature_status = isset( $feature_data['status'] ) ? $feature_data['status'] : 'available';
1877
1878 // Only include features that are enabled for this plan and not "coming soon"
1879 if ( wpforo_ai_is_feature_enabled_by_plan( $current_plan, $feature_plan ) && $feature_status !== 'coming_soon' ) {
1880 $plan_features[] = $feature_id;
1881 }
1882 }
1883
1884 // If no plan features found, fall back to usage keys
1885 if ( empty( $plan_features ) ) {
1886 $plan_features = $has_lifetime ? array_keys( $usage_lifetime ) : array_keys( $usage );
1887 }
1888
1889 foreach ( $plan_features as $feature_id ) {
1890 $feature_name = '';
1891 if ( isset( $features[ $feature_id ]['name'] ) ) {
1892 $feature_name = $features[ $feature_id ]['name'];
1893 }
1894 if ( ! $feature_name ) {
1895 $feature_name = ucwords( str_replace( '_', ' ', $feature_id ) );
1896 }
1897
1898 // Get counts (since last purchase and lifetime)
1899 $count_since_purchase = isset( $usage[ $feature_id ] ) ? (int) $usage[ $feature_id ] : 0;
1900 $count_lifetime = $has_lifetime && isset( $usage_lifetime[ $feature_id ] ) ? (int) $usage_lifetime[ $feature_id ] : 0;
1901
1902 // For content_indexing, include image and document indexing credits
1903 if ( 'content_indexing' === $feature_id ) {
1904 $count_since_purchase += ( isset( $usage['multimodal_image_indexing'] ) ? (int) $usage['multimodal_image_indexing'] : 0 );
1905 $count_since_purchase += ( isset( $usage['document_indexing'] ) ? (int) $usage['document_indexing'] : 0 );
1906 if ( $has_lifetime ) {
1907 $count_lifetime += ( isset( $usage_lifetime['multimodal_image_indexing'] ) ? (int) $usage_lifetime['multimodal_image_indexing'] : 0 );
1908 $count_lifetime += ( isset( $usage_lifetime['document_indexing'] ) ? (int) $usage_lifetime['document_indexing'] : 0 );
1909 }
1910 }
1911
1912 echo '<tr>';
1913 echo '<td>' . esc_html( $feature_name ) . '</td>';
1914 echo '<td><strong>' . number_format( $count_since_purchase ) . '</strong></td>';
1915 if ( $has_lifetime ) {
1916 echo '<td><strong>' . number_format( $count_lifetime ) . '</strong></td>';
1917 }
1918 echo '</tr>';
1919 }
1920
1921 echo '</tbody>';
1922 echo '</table>';
1923 echo '</div>';
1924 }
1925
1926 /**
1927 * Render pricing table
1928 *
1929 * @param string $tenant_id Tenant ID for upgrade URLs
1930 * @param array $subscription Current subscription data (optional, for showing active plan)
1931 */
1932 function wpforo_ai_render_pricing_table( $tenant_id, $subscription = [] ) {
1933 // Get current plan and expiration date
1934 $current_plan = isset( $subscription['plan'] ) ? $subscription['plan'] : 'free_trial';
1935 $renews_at = isset( $subscription['renews_at'] ) ? $subscription['renews_at'] : '';
1936 $expires_at = isset( $subscription['expires_at'] ) ? $subscription['expires_at'] : '';
1937
1938 // Plan hierarchy for disabling lower plan buttons
1939 $plan_levels = [
1940 'free_trial' => 0,
1941 'free' => 0,
1942 'starter' => 1,
1943 'professional' => 2,
1944 'business' => 3,
1945 'enterprise' => 4,
1946 ];
1947 $current_level = isset( $plan_levels[ $current_plan ] ) ? $plan_levels[ $current_plan ] : 0;
1948
1949 // Fetch dynamic pricing from Freemius API (with fallback to defaults)
1950 $pricing = wpforo_ai_get_freemius_pricing();
1951 $plans = $pricing['plans'];
1952
1953 ?>
1954 <div class="wpforo-ai-callout" style="display: none;">
1955 <span class="dashicons dashicons-info"></span>
1956 <div>
1957 <strong><?php _e( 'Credit-Based Pricing', 'wpforo' ); ?></strong>
1958 <p><?php _e( 'Pay only for what you use with flexible credit-based pricing. Credits roll over month-to-month as long as you have an active subscription plan. Each plan allows credit accumulation up to one year of subscription plan credits. Start with 500 free credits, then choose a plan that fits your forum\'s activity level.', 'wpforo' ); ?><br><?php _e('You can select the quality of AI model for each feature individually: ', 'wpforo') ?></p>
1959 <ul style="list-style: square; padding: 0 18px; margin: 5px 0 0 0;">
1960 <li style="margin-bottom: 1px;"><?php _e( 'Fast (1 action = 1 credit)', 'wpforo' ); ?></li>
1961 <li style="margin-bottom: 1px;"><?php _e( 'Balanced (1 action = 2 credits)', 'wpforo' ); ?></li>
1962 <li style="margin-bottom: 1px;"><?php _e( 'Advanced (1 action = 3 credits)', 'wpforo' ); ?></li>
1963 <li style="margin-bottom: 1px;"><?php _e( 'Premium (1 action = 4 credits)', 'wpforo' ); ?></li>
1964 </ul>
1965 </div>
1966 </div>
1967 <div class="wpforo-ai-pricing-table">
1968 <table class="pricing-table-modern">
1969 <thead>
1970 <tr>
1971 <th class="feature-column"><?php _e( 'AI Features', 'wpforo' ); ?></th>
1972 <th class="plan-column plan-starter <?php echo $current_plan === 'starter' ? 'plan-active' : ''; ?>">
1973 <div class="plan-header">
1974 <?php if ( $current_plan === 'starter' ) : ?>
1975 <div class="plan-active-badge"><?php _e( 'YOUR PLAN', 'wpforo' ); ?></div>
1976 <?php endif; ?>
1977 <div class="plan-name"><?php _e( 'Starter', 'wpforo' ); ?></div>
1978 <div class="plan-price">
1979 <span class="currency">$</span><span class="price-amount"><?php echo esc_html( $plans['starter']['price'] ); ?></span><small class="billing-period">/month</small>
1980 </div>
1981 <div class="plan-credits">
1982 <span class="dashicons dashicons-awards"></span>
1983 <strong>+1,000</strong> <?php _e( 'credits', 'wpforo' ); ?>
1984 </div>
1985 </div>
1986 </th>
1987 <th class="plan-column plan-professional <?php echo $current_plan === 'professional' ? 'plan-active' : ''; ?>">
1988 <div class="plan-header">
1989 <?php if ( $current_plan === 'professional' ) : ?>
1990 <div class="plan-active-badge"><?php _e( 'YOUR PLAN', 'wpforo' ); ?></div>
1991 <?php else : ?>
1992 <div class="plan-popular-badge"><?php _e( 'POPULAR', 'wpforo' ); ?></div>
1993 <?php endif; ?>
1994 <div class="plan-name"><?php _e( 'Professional', 'wpforo' ); ?></div>
1995 <div class="plan-price">
1996 <span class="currency">$</span><span class="price-amount"><?php echo esc_html( $plans['professional']['price'] ); ?></span><small class="billing-period">/month</small>
1997 </div>
1998 <div class="plan-credits">
1999 <span class="dashicons dashicons-awards"></span>
2000 <strong>+3,000</strong> <?php _e( 'credits', 'wpforo' ); ?>
2001 </div>
2002 </div>
2003 </th>
2004 <th class="plan-column plan-business <?php echo $current_plan === 'business' ? 'plan-active' : ''; ?>">
2005 <div class="plan-header">
2006 <?php if ( $current_plan === 'business' ) : ?>
2007 <div class="plan-active-badge"><?php _e( 'YOUR PLAN', 'wpforo' ); ?></div>
2008 <?php endif; ?>
2009 <div class="plan-name"><?php _e( 'Business', 'wpforo' ); ?></div>
2010 <div class="plan-price">
2011 <span class="currency">$</span><span class="price-amount"><?php echo esc_html( $plans['business']['price'] ); ?></span><small class="billing-period">/month</small>
2012 </div>
2013 <div class="plan-credits">
2014 <span class="dashicons dashicons-awards"></span>
2015 <strong>+9,000</strong> <?php _e( 'credits', 'wpforo' ); ?>
2016 </div>
2017 </div>
2018 </th>
2019 <th class="plan-column plan-enterprise <?php echo $current_plan === 'enterprise' ? 'plan-active' : ''; ?>">
2020 <div class="plan-header">
2021 <?php if ( $current_plan === 'enterprise' ) : ?>
2022 <div class="plan-active-badge"><?php _e( 'YOUR PLAN', 'wpforo' ); ?></div>
2023 <?php endif; ?>
2024 <div class="plan-name"><?php _e( 'Enterprise', 'wpforo' ); ?></div>
2025 <div class="plan-price">
2026 <span class="price-amount" style="font-weight: 400; font-size: 16px;"><?php _e( 'Custom Price', 'wpforo' ); ?></span>
2027 </div>
2028 <div class="plan-credits">
2029 <span class="dashicons dashicons-awards"></span>
2030 <strong style="font-weight: 500;"><?php _e( 'Custom', 'wpforo' ); ?></strong> <?php _e( 'credits', 'wpforo' ); ?>
2031 </div>
2032 </div>
2033 </th>
2034 </tr>
2035 </thead>
2036 <tbody>
2037 <!-- CTA Row -->
2038 <tr class="cta-row">
2039 <td></td>
2040 <td>
2041 <?php if ( $current_plan === 'starter' ) : ?>
2042 <div class="plan-active-info">
2043 <span class="dashicons dashicons-yes-alt"></span>
2044 <strong><?php _e( 'Active', 'wpforo' ); ?></strong>
2045 <?php if ( $renews_at ) : ?>
2046 <small><?php printf( __( 'Renews %s', 'wpforo' ), esc_html( wpforo_ai_format_date( $renews_at ) ) ); ?></small>
2047 <?php endif; ?>
2048 </div>
2049 <?php elseif ( $plan_levels['starter'] < $current_level ) : ?>
2050 <button type="button" class="button button-secondary button-cta" disabled>
2051 <?php _e( 'Upgrade', 'wpforo' ); ?>
2052 </button>
2053 <?php else : ?>
2054 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="starter" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2055 <?php $current_plan === 'free_trial' ? _e( 'Get Started', 'wpforo' ) : _e( 'Upgrade', 'wpforo' ); ?>
2056 </button>
2057 <?php endif; ?>
2058 </td>
2059 <td>
2060 <?php if ( $current_plan === 'professional' ) : ?>
2061 <div class="plan-active-info">
2062 <!-- <span class="dashicons dashicons-yes-alt"></span> -->
2063 <strong><?php _e( 'Active', 'wpforo' ); ?></strong>
2064 <?php if ( $renews_at ) : ?>
2065 <small><?php printf( __( 'Renews %s', 'wpforo' ), esc_html( wpforo_ai_format_date( $renews_at ) ) ); ?></small>
2066 <?php endif; ?>
2067 </div>
2068 <?php elseif ( $plan_levels['professional'] < $current_level ) : ?>
2069 <button type="button" class="button button-secondary button-cta" disabled>
2070 <?php _e( 'Upgrade', 'wpforo' ); ?>
2071 </button>
2072 <?php else : ?>
2073 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="professional" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2074 <?php $current_plan === 'free_trial' ? _e( 'Get Started', 'wpforo' ) : _e( 'Upgrade', 'wpforo' ); ?>
2075 </button>
2076 <?php endif; ?>
2077 </td>
2078 <td>
2079 <?php if ( $current_plan === 'business' ) : ?>
2080 <div class="plan-active-info">
2081 <!-- <span class="dashicons dashicons-yes-alt"></span> -->
2082 <strong><?php _e( 'Active', 'wpforo' ); ?></strong>
2083 <?php if ( $renews_at ) : ?>
2084 <small><?php printf( __( 'Renews %s', 'wpforo' ), esc_html( wpforo_ai_format_date( $renews_at ) ) ); ?></small>
2085 <?php endif; ?>
2086 </div>
2087 <?php elseif ( $plan_levels['business'] < $current_level ) : ?>
2088 <button type="button" class="button button-secondary button-cta" disabled>
2089 <?php _e( 'Upgrade', 'wpforo' ); ?>
2090 </button>
2091 <?php else : ?>
2092 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="business" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2093 <?php $current_plan === 'free_trial' ? _e( 'Get Started', 'wpforo' ) : _e( 'Upgrade', 'wpforo' ); ?>
2094 </button>
2095 <?php endif; ?>
2096 </td>
2097 <td>
2098 <?php if ( $current_plan === 'enterprise' ) : ?>
2099 <div class="plan-active-info">
2100 <!-- <span class="dashicons dashicons-yes-alt"></span> -->
2101 <strong><?php _e( 'Active', 'wpforo' ); ?></strong>
2102 <?php if ( $renews_at ) : ?>
2103 <small><?php printf( __( 'Renews %s', 'wpforo' ), esc_html( wpforo_ai_format_date( $renews_at ) ) ); ?></small>
2104 <?php endif; ?>
2105 </div>
2106 <?php else : ?>
2107 <a href="https://wpforo.com/gvectors-ai/#gvai-contact" target="_blank" class="button button-secondary" style="padding: 5px 20px;">
2108 <?php _e( 'Contact Us', 'wpforo' ) ?>
2109 </a>
2110 <?php endif; ?>
2111 </td>
2112 </tr>
2113
2114 <!-- Core Features -->
2115 <tr class="feature-category">
2116 <td colspan="5"><span class="dashicons dashicons-yes-alt"></span> <?php _e( 'ALL Core AI Features', 'wpforo' ); ?></td>
2117 </tr>
2118 <tr>
2119 <td><?php _e( 'AI Knowledge - Content Text Indexing', 'wpforo' ); ?></td>
2120 <td><span class="checkmark">✓</span></td>
2121 <td><span class="checkmark">✓</span></td>
2122 <td><span class="checkmark">✓</span></td>
2123 <td><span class="checkmark">✓</span></td>
2124 </tr>
2125 <tr>
2126 <td><?php _e( 'AI Vector Database - Local Storage', 'wpforo' ); ?></td>
2127 <td><span class="checkmark">✓</span></td>
2128 <td><span class="checkmark">✓</span></td>
2129 <td><span class="checkmark">✓</span></td>
2130 <td><span class="checkmark">✓</span></td>
2131 </tr>
2132 <tr>
2133 <td><?php _e( 'AI Semantic Search', 'wpforo' ); ?></td>
2134 <td><span class="checkmark">✓</span></td>
2135 <td><span class="checkmark">✓</span></td>
2136 <td><span class="checkmark">✓</span></td>
2137 <td><span class="checkmark">✓</span></td>
2138 </tr>
2139 <tr>
2140 <td><?php _e( 'AI Search Enhancement', 'wpforo' ); ?></td>
2141 <td><span class="checkmark">✓</span></td>
2142 <td><span class="checkmark">✓</span></td>
2143 <td><span class="checkmark">✓</span></td>
2144 <td><span class="checkmark">✓</span></td>
2145 </tr>
2146 <tr>
2147 <td><?php _e( 'AI Topic Summarization', 'wpforo' ); ?></td>
2148 <td><span class="checkmark">✓</span></td>
2149 <td><span class="checkmark">✓</span></td>
2150 <td><span class="checkmark">✓</span></td>
2151 <td><span class="checkmark">✓</span></td>
2152 </tr>
2153 <tr>
2154 <td><?php _e( 'AI Topic Suggestions', 'wpforo' ); ?></td>
2155 <td><span class="checkmark">✓</span></td>
2156 <td><span class="checkmark">✓</span></td>
2157 <td><span class="checkmark">✓</span></td>
2158 <td><span class="checkmark">✓</span></td>
2159 </tr>
2160 <tr>
2161 <td><?php _e( 'AI Multi-Language Translation', 'wpforo' ); ?></td>
2162 <td><span class="checkmark">✓</span></td>
2163 <td><span class="checkmark">✓</span></td>
2164 <td><span class="checkmark">✓</span></td>
2165 <td><span class="checkmark">✓</span></td>
2166 </tr>
2167 <tr>
2168 <td><strong><?php _e( 'AI Auto Moderation', 'wpforo' ); ?></strong></td>
2169 <td><span class="checkmark">✓</span></td>
2170 <td><span class="checkmark">✓</span></td>
2171 <td><span class="checkmark">✓</span></td>
2172 <td><span class="checkmark">✓</span></td>
2173 </tr>
2174 <tr class="feature-item">
2175 <td><?php _e( 'Spam Detection and User Banning', 'wpforo' ); ?></td>
2176 <td><span class="checkmark">✓</span></td>
2177 <td><span class="checkmark">✓</span></td>
2178 <td><span class="checkmark">✓</span></td>
2179 <td><span class="checkmark">✓</span></td>
2180 </tr>
2181 <tr class="feature-item">
2182 <td><?php _e( 'Content Safety & Toxicity Detection', 'wpforo' ); ?></td>
2183 <td><span class="checkmark">✓</span></td>
2184 <td><span class="checkmark">✓</span></td>
2185 <td><span class="checkmark">✓</span></td>
2186 <td><span class="checkmark">✓</span></td>
2187 </tr>
2188 <tr class="feature-item">
2189 <td><?php _e( 'Rule Compliance & Policy Enforcement', 'wpforo' ); ?></td>
2190 <td><span class="checkmark">✓</span></td>
2191 <td><span class="checkmark">✓</span></td>
2192 <td><span class="checkmark">✓</span></td>
2193 <td><span class="checkmark">✓</span></td>
2194 </tr>
2195 <!-- Professional Features -->
2196 <tr class="feature-category">
2197 <td colspan="5"><span class="dashicons dashicons-shield-alt"></span> <?php _e( 'Professional Features', 'wpforo' ); ?></td>
2198 </tr>
2199
2200 <tr>
2201 <td><?php _e( 'AI Knowledge - Image Indexing', 'wpforo' ); ?></td>
2202 <td><span class="crossmark">✗</span></td>
2203 <td><span class="checkmark">✓</span></td>
2204 <td><span class="checkmark">✓</span></td>
2205 <td><span class="checkmark">✓</span></td>
2206 </tr>
2207 <tr>
2208 <td><?php _e( 'AI Knowledge - Document Indexing', 'wpforo' ); ?></td>
2209 <td><span class="crossmark">✗</span></td>
2210 <td><span class="checkmark">✓</span></td>
2211 <td><span class="checkmark">✓</span></td>
2212 <td><span class="checkmark">✓</span></td>
2213 </tr>
2214 <tr>
2215 <td><?php _e( 'AI Bot Reply', 'wpforo' ); ?></td>
2216 <td><span class="crossmark">✗</span></td>
2217 <td><span class="checkmark">✓</span></td>
2218 <td><span class="checkmark">✓</span></td>
2219 <td><span class="checkmark">✓</span></td>
2220 </tr>
2221 <tr>
2222 <td><?php _e( 'AI Reply Suggestion', 'wpforo' ); ?></td>
2223 <td><span class="crossmark">✗</span></td>
2224 <td><span class="checkmark">✓</span></td>
2225 <td><span class="checkmark">✓</span></td>
2226 <td><span class="checkmark">✓</span></td>
2227 </tr>
2228 <tr>
2229 <td><strong><?php _e( 'AI Tasks and Automations', 'wpforo' ); ?></strong></td>
2230 <td><span class="crossmark">✗</span></td>
2231 <td><span class="checkmark">✓</span></td>
2232 <td><span class="checkmark">✓</span></td>
2233 <td><span class="checkmark">✓</span></td>
2234 </tr>
2235 <tr class="feature-item">
2236 <td><?php _e( 'New Topic Creation', 'wpforo' ); ?></td>
2237 <td><span class="crossmark">✗</span></td>
2238 <td><span class="checkmark">✓</span></td>
2239 <td><span class="checkmark">✓</span></td>
2240 <td><span class="checkmark">✓</span></td>
2241 </tr>
2242 <tr class="feature-item">
2243 <td><?php _e( 'Auto Reply to Topics', 'wpforo' ); ?></td>
2244 <td><span class="crossmark">✗</span></td>
2245 <td><span class="checkmark">✓</span></td>
2246 <td><span class="checkmark">✓</span></td>
2247 <td><span class="checkmark">✓</span></td>
2248 </tr>
2249 <tr class="feature-item">
2250 <td><?php _e( 'Topic Tag Moderation', 'wpforo' ); ?></td>
2251 <td><span class="crossmark">✗</span></td>
2252 <td><span class="checkmark">✓</span></td>
2253 <td><span class="checkmark">✓</span></td>
2254 <td><span class="checkmark">✓</span></td>
2255 </tr>
2256 <tr>
2257 <td><strong><?php _e( 'AI Analytics & Insights', 'wpforo' ); ?></strong></td>
2258 <td><span class="crossmark">✗</span></td>
2259 <td><span class="checkmark">✓</span></td>
2260 <td><span class="checkmark">✓</span></td>
2261 <td><span class="checkmark">✓</span></td>
2262 </tr>
2263 <tr class="feature-item">
2264 <td><?php _e( 'AI Insights', 'wpforo' ); ?></td>
2265 <td><span class="crossmark">✗</span></td>
2266 <td><span class="checkmark">✓</span></td>
2267 <td><span class="checkmark">✓</span></td>
2268 <td><span class="checkmark">✓</span></td>
2269 </tr>
2270 <tr class="feature-item">
2271 <td><?php _e( 'AI Usage Analytics', 'wpforo' ); ?></td>
2272 <td><span class="crossmark">✗</span></td>
2273 <td><span class="checkmark">✓</span></td>
2274 <td><span class="checkmark">✓</span></td>
2275 <td><span class="checkmark">✓</span></td>
2276 </tr>
2277 <tr class="feature-item">
2278 <td><?php _e( 'Forum Activity', 'wpforo' ); ?></td>
2279 <td><span class="crossmark">✗</span></td>
2280 <td><span class="checkmark">✓</span></td>
2281 <td><span class="checkmark">✓</span></td>
2282 <td><span class="checkmark">✓</span></td>
2283 </tr>
2284 <tr class="feature-item">
2285 <td><?php _e( 'User Engagement', 'wpforo' ); ?></td>
2286 <td><span class="crossmark">✗</span></td>
2287 <td><span class="checkmark">✓</span></td>
2288 <td><span class="checkmark">✓</span></td>
2289 <td><span class="checkmark">✓</span></td>
2290 </tr>
2291 <tr class="feature-item">
2292 <td><?php _e( 'Content Performance', 'wpforo' ); ?></td>
2293 <td><span class="crossmark">✗</span></td>
2294 <td><span class="checkmark">✓</span></td>
2295 <td><span class="checkmark">✓</span></td>
2296 <td><span class="checkmark">✓</span></td>
2297 </tr>
2298
2299
2300 <!-- Business Features -->
2301 <tr class="feature-category">
2302 <td colspan="5"><span class="dashicons dashicons-portfolio"></span> <?php _e( 'Business Features', 'wpforo' ); ?></td>
2303 </tr>
2304 <tr>
2305 <td><?php _e( 'AI Chat Assistant', 'wpforo' ); ?></td>
2306 <td><span class="crossmark">✗</span></td>
2307 <td><span class="crossmark">✗</span></td>
2308 <td><span class="checkmark">✓</span></td>
2309 <td><span class="checkmark">✓</span></td>
2310 </tr>
2311 <tr>
2312 <td><?php _e( 'AI Vector Database - Cloud Storage', 'wpforo' ); ?></td>
2313 <td><span class="crossmark">✗</span></td>
2314 <td><span class="crossmark">✗</span></td>
2315 <td><span class="checkmark">✓</span></td>
2316 <td><span class="checkmark">✓</span></td>
2317 </tr>
2318 <tr>
2319 <td><strong><?php _e( 'Extended Knowledge Base', 'wpforo' ); ?></strong></td>
2320 <td><span class="crossmark">✗</span></td>
2321 <td><span class="crossmark">✗</span></td>
2322 <td><span class="checkmark">✓</span></td>
2323 <td><span class="checkmark">✓</span></td>
2324 </tr>
2325 <tr class="feature-item">
2326 <td><?php _e( 'WordPress Content indexing', 'wpforo' ); ?></td>
2327 <td><span class="crossmark">✗</span></td>
2328 <td><span class="crossmark">✗</span></td>
2329 <td><span class="checkmark">✓</span></td>
2330 <td><span class="checkmark">✓</span></td>
2331 </tr>
2332 <tr class="feature-item">
2333 <td><?php _e( 'Custom Post Types indexing', 'wpforo' ); ?> </td>
2334 <td><span class="crossmark">✗</span></td>
2335 <td><span class="crossmark">✗</span></td>
2336 <td><span class="checkmark">✓</span></td>
2337 <td><span class="checkmark">✓</span></td>
2338 </tr>
2339 <tr class="feature-item">
2340 <td><?php _e( 'WooCommerce indexing', 'wpforo' ); echo '<span class="coming-soon-badge">' . esc_html__( 'Coming Soon', 'wpforo' ) . '</span>'; ?></td>
2341 <td><span class="crossmark">✗</span></td>
2342 <td><span class="crossmark">✗</span></td>
2343 <td><span class="checkmark">✓</span></td>
2344 <td><span class="checkmark">✓</span></td>
2345 </tr>
2346 <tr>
2347 <td><strong><?php _e( 'Custom Knowledge Indexing', 'wpforo' ); ?></strong></td>
2348 <td><span class="crossmark">✗</span></td>
2349 <td><span class="crossmark">✗</span></td>
2350 <td><span class="checkmark">✓</span></td>
2351 <td><span class="checkmark">✓</span></td>
2352 </tr>
2353 <tr class="feature-item">
2354 <td><?php _e( 'File Indexing (TXT, MD, JSON, PDF)', 'wpforo' ); ?></td>
2355 <td><span class="crossmark">✗</span></td>
2356 <td><span class="crossmark">✗</span></td>
2357 <td><span class="checkmark">✓</span></td>
2358 <td><span class="checkmark">✓</span></td>
2359 </tr>
2360
2361 <!-- Enterprise Features -->
2362 <tr class="feature-category">
2363 <td colspan="5"><span class="dashicons dashicons-admin-tools"></span> <?php _e( 'Enterprise Features', 'wpforo' ); ?></td>
2364 </tr>
2365 <tr>
2366 <td><strong><?php _e( 'Developer Features', 'wpforo' ); ?></strong></td>
2367 <td><span class="crossmark">✗</span></td>
2368 <td><span class="crossmark">✗</span></td>
2369 <td><span class="crossmark">✗</span></td>
2370 <td><span class="checkmark">✓</span></td>
2371 </tr>
2372 <tr class="feature-item">
2373 <td><?php _e( 'REST API Access', 'wpforo' ); ?></td>
2374 <td><span class="crossmark">✗</span></td>
2375 <td><span class="crossmark">✗</span></td>
2376 <td><span class="crossmark">✗</span></td>
2377 <td><span class="checkmark">✓</span></td>
2378 </tr>
2379 <tr class="feature-item">
2380 <td><?php _e( 'Custom AI Models', 'wpforo' ); ?></td>
2381 <td><span class="crossmark">✗</span></td>
2382 <td><span class="crossmark">✗</span></td>
2383 <td><span class="crossmark">✗</span></td>
2384 <td><span class="checkmark">✓</span></td>
2385 </tr>
2386 <tr class="feature-item">
2387 <td><?php _e( 'Custom feature development', 'wpforo' ); ?></td>
2388 <td><span class="crossmark">✗</span></td>
2389 <td><span class="crossmark">✗</span></td>
2390 <td><span class="crossmark">✗</span></td>
2391 <td><span class="checkmark">✓</span></td>
2392 </tr>
2393 <tr>
2394 <td><strong><?php _e( 'Premium Support', 'wpforo' ); ?></strong></td>
2395 <td><span class="crossmark">✗</span></td>
2396 <td><span class="crossmark">✗</span></td>
2397 <td><span class="crossmark">✗</span></td>
2398 <td><span class="checkmark">✓</span></td>
2399 </tr>
2400 <tr class="feature-item">
2401 <td><?php _e( 'Dedicated account manager', 'wpforo' ); ?></td>
2402 <td><span class="crossmark">✗</span></td>
2403 <td><span class="crossmark">✗</span></td>
2404 <td><span class="crossmark">✗</span></td>
2405 <td><span class="checkmark">✓</span></td>
2406 </tr>
2407 <tr class="feature-item">
2408 <td><?php _e( 'Enterprise Capabilities', 'wpforo' ); ?></td>
2409 <td><span class="crossmark">✗</span></td>
2410 <td><span class="crossmark">✗</span></td>
2411 <td><span class="crossmark">✗</span></td>
2412 <td><span class="checkmark">✓</span></td>
2413 </tr>
2414
2415 <!-- Bottom CTA Row -->
2416 <tr class="cta-row">
2417 <td></td>
2418 <td>
2419 <?php if ( $current_plan === 'starter' ) : ?>
2420 <div class="plan-active-info">
2421 <span class="dashicons dashicons-yes-alt"></span>
2422 <?php _e( 'Active', 'wpforo' ); ?>
2423 </div>
2424 <?php elseif ( $plan_levels['starter'] < $current_level ) : ?>
2425 <button type="button" class="button button-secondary button-cta" disabled>
2426 <?php _e( 'Upgrade', 'wpforo' ); ?>
2427 </button>
2428 <?php else : ?>
2429 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="starter" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2430 <?php _e( 'Upgrade', 'wpforo' ); ?>
2431 </button>
2432 <?php endif; ?>
2433 </td>
2434 <td>
2435 <?php if ( $current_plan === 'professional' ) : ?>
2436 <div class="plan-active-info">
2437 <span class="dashicons dashicons-yes-alt"></span>
2438 <?php _e( 'Active', 'wpforo' ); ?>
2439 </div>
2440 <?php elseif ( $plan_levels['professional'] < $current_level ) : ?>
2441 <button type="button" class="button button-secondary button-cta" disabled>
2442 <?php _e( 'Upgrade', 'wpforo' ); ?>
2443 </button>
2444 <?php else : ?>
2445 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="professional" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2446 <?php _e( 'Upgrade', 'wpforo' ); ?>
2447 </button>
2448 <?php endif; ?>
2449 </td>
2450 <td>
2451 <?php if ( $current_plan === 'business' ) : ?>
2452 <div class="plan-active-info">
2453 <span class="dashicons dashicons-yes-alt"></span>
2454 <?php _e( 'Active', 'wpforo' ); ?>
2455 </div>
2456 <?php elseif ( $plan_levels['business'] < $current_level ) : ?>
2457 <button type="button" class="button button-secondary button-cta" disabled>
2458 <?php _e( 'Upgrade', 'wpforo' ); ?>
2459 </button>
2460 <?php else : ?>
2461 <button type="button" class="button button-secondary button-cta wpforo-ai-upgrade-btn" data-plan="business" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2462 <?php _e( 'Upgrade', 'wpforo' ); ?>
2463 </button>
2464 <?php endif; ?>
2465 </td>
2466 <td>
2467 <?php if ( $current_plan === 'enterprise' ) : ?>
2468 <div class="plan-active-info">
2469 <span class="dashicons dashicons-yes-alt"></span>
2470 <?php _e( 'Active', 'wpforo' ); ?>
2471 </div>
2472 <?php else : ?>
2473 <a href="https://wpforo.com/gvectors-ai/#gvai-contact" target="_blank" class="button button-secondary" style="padding: 5px 20px;">
2474 <?php _e( 'Contact Us', 'wpforo' ) ?>
2475 </a>
2476 <?php endif; ?>
2477 </td>
2478 </tr>
2479 </tbody>
2480 </table>
2481 </div>
2482
2483 <?php
2484 $enabled_providers = wpforo_ai_get_enabled_providers();
2485 $default_provider = wpforo_ai_get_default_provider();
2486 $show_toggle = count( $enabled_providers ) > 1;
2487 ?>
2488
2489 <?php if ( $show_toggle ) : ?>
2490 <!-- Payment Provider Toggle -->
2491 <div class="wpforo-ai-provider-toggle" style="margin-top: 15px; padding: 12px 20px; background: #f8f9fa; border: 1px solid #ddd; border-radius: 6px; display: flex; align-items: center; gap: 20px;">
2492 <span style="font-weight: 500; color: #333;">
2493 <span class="dashicons dashicons-money-alt" style="vertical-align: middle; margin-right: 4px;"></span>
2494 <?php _e( 'Payment Method:', 'wpforo' ); ?>
2495 </span>
2496 <?php if ( in_array( 'paddle', $enabled_providers, true ) ) : ?>
2497 <label style="display: flex; align-items: center; gap: 5px; cursor: pointer;">
2498 <input type="radio" name="wpforo_ai_payment_provider" value="paddle" <?php checked( $default_provider, 'paddle' ); ?>>
2499 <?php _e( 'Paddle (Credit Card, PayPal)', 'wpforo' ); ?>
2500 </label>
2501 <?php endif; ?>
2502 <?php if ( in_array( 'freemius', $enabled_providers, true ) ) : ?>
2503 <label style="display: flex; align-items: center; gap: 5px; cursor: pointer;">
2504 <input type="radio" name="wpforo_ai_payment_provider" value="freemius" <?php checked( $default_provider, 'freemius' ); ?>>
2505 <?php _e( 'Freemius', 'wpforo' ); ?>
2506 </label>
2507 <?php endif; ?>
2508 </div>
2509 <?php endif; ?>
2510
2511 <div class="wpforo-ai-powered-by">
2512 <span class="dashicons dashicons-lock"></span>
2513 <?php
2514 if ( ! $show_toggle && in_array( 'paddle', $enabled_providers, true ) ) {
2515 _e( 'Payment and Subscription Management is Powered by Paddle - Secure Checkout', 'wpforo' );
2516 } elseif ( ! $show_toggle && in_array( 'freemius', $enabled_providers, true ) ) {
2517 _e( 'Payment and Subscription Management is Powered by Freemius - Secure Checkout', 'wpforo' );
2518 } else {
2519 _e( 'Secure Payment Processing', 'wpforo' );
2520 }
2521 ?>
2522 </div>
2523
2524 <!-- Checkout Configurations -->
2525 <script type="text/javascript">
2526 <?php if ( in_array( 'freemius', $enabled_providers, true ) ) : ?>
2527 // Freemius checkout configurations for each plan
2528 window.wpforoFreemiusCheckout = {
2529 tenant_id: <?php echo json_encode( $tenant_id ); ?>,
2530 plans: {
2531 starter: <?php echo json_encode( wpforo_ai_get_upgrade_url( $tenant_id, 'starter' ) ); ?>,
2532 professional: <?php echo json_encode( wpforo_ai_get_upgrade_url( $tenant_id, 'professional' ) ); ?>,
2533 business: <?php echo json_encode( wpforo_ai_get_upgrade_url( $tenant_id, 'business' ) ); ?>,
2534 enterprise: <?php echo json_encode( wpforo_ai_get_upgrade_url( $tenant_id, 'enterprise' ) ); ?>
2535 }
2536 };
2537 <?php endif; ?>
2538
2539 <?php if ( in_array( 'paddle', $enabled_providers, true ) ) : ?>
2540 // Paddle checkout configurations
2541 <?php $paddle_pricing = wpforo_ai_get_paddle_pricing(); ?>
2542 window.wpforoPaddleCheckout = {
2543 tenant_id: <?php echo json_encode( $tenant_id ); ?>,
2544 plans: {
2545 starter: { price_id: <?php echo json_encode( $paddle_pricing['plans']['starter']['price_id'] ); ?> },
2546 professional: { price_id: <?php echo json_encode( $paddle_pricing['plans']['professional']['price_id'] ); ?> },
2547 business: { price_id: <?php echo json_encode( $paddle_pricing['plans']['business']['price_id'] ); ?> },
2548 enterprise: { price_id: <?php echo json_encode( $paddle_pricing['plans']['enterprise']['price_id'] ); ?> }
2549 },
2550 creditPacks: {
2551 '500': { price_id: <?php echo json_encode( $paddle_pricing['credit_packs']['500']['price_id'] ); ?> },
2552 '1500': { price_id: <?php echo json_encode( $paddle_pricing['credit_packs']['1500']['price_id'] ); ?> },
2553 '4500': { price_id: <?php echo json_encode( $paddle_pricing['credit_packs']['4500']['price_id'] ); ?> },
2554 '15000': { price_id: <?php echo json_encode( $paddle_pricing['credit_packs']['15000']['price_id'] ); ?> }
2555 }
2556 };
2557 <?php endif; ?>
2558
2559 // Active payment provider and enabled providers
2560 window.wpforoPaymentProvider = <?php echo json_encode( $default_provider ); ?>;
2561 window.wpforoEnabledProviders = <?php echo json_encode( $enabled_providers ); ?>;
2562 </script>
2563 <?php
2564 }
2565
2566 /**
2567 * Render credit packs section
2568 *
2569 * @param string $tenant_id Tenant ID for purchase URLs
2570 */
2571 function wpforo_ai_render_credit_packs( $tenant_id ) {
2572 // Fetch dynamic pricing from Freemius API (with fallback to defaults)
2573 $pricing = wpforo_ai_get_freemius_pricing();
2574 $credit_packs = $pricing['credit_packs'];
2575 ?>
2576 <div class="wpforo-ai-credit-packs-wrapper">
2577 <div class="credit-packs-header">
2578 <p class="credit-packs-description">
2579 <?php printf( __( 'Need more credits? Purchase one-time credit packs. Credits accumulate with your subscription credits up to your plan\'s maximum (one year of subscription plan credits) and can be used %s.', 'wpforo' ), '<span style="color: #990000">' . __('as long as you have an active subscription', 'wpforo' ) . '</span>' ); ?>
2580 </p>
2581 </div>
2582
2583 <div class="wpforo-ai-credit-packs-table">
2584 <!-- 500 Credits Pack -->
2585 <div class="credit-pack">
2586 <div class="credit-pack-header">
2587 <h4><?php _e( '500 Credits', 'wpforo' ); ?></h4>
2588 <div class="credit-pack-price">$<?php echo esc_html( number_format( $credit_packs['500']['price'], 0 ) ); ?><span class="credit-pack-period"><?php _e( 'one-time', 'wpforo' ); ?></span></div>
2589 </div>
2590 <div class="credit-pack-action">
2591 <button type="button" class="button button-large wpforo-ai-buy-credits-btn" data-pack="500" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2592 <?php _e( 'Buy Now', 'wpforo' ); ?>
2593 </button>
2594 </div>
2595 </div>
2596
2597 <!-- 1500 Credits Pack -->
2598 <div class="credit-pack">
2599 <div class="credit-pack-header">
2600 <h4><?php _e( '1,500 Credits', 'wpforo' ); ?></h4>
2601 <div class="credit-pack-price">$<?php echo esc_html( number_format( $credit_packs['1500']['price'], 0 ) ); ?><span class="credit-pack-period"><?php _e( 'one-time', 'wpforo' ); ?></span></div>
2602 </div>
2603 <div class="credit-pack-action">
2604 <button type="button" class="button button-large wpforo-ai-buy-credits-btn" data-pack="1500" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2605 <?php _e( 'Buy Now', 'wpforo' ); ?>
2606 </button>
2607 </div>
2608 </div>
2609
2610 <!-- 4500 Credits Pack -->
2611 <div class="credit-pack">
2612 <div class="credit-pack-header">
2613 <h4><?php _e( '4,500 Credits', 'wpforo' ); ?></h4>
2614 <div class="credit-pack-price">$<?php echo esc_html( number_format( $credit_packs['4500']['price'], 0 ) ); ?><span class="credit-pack-period"><?php _e( 'one-time', 'wpforo' ); ?></span></div>
2615 </div>
2616 <div class="credit-pack-action">
2617 <button type="button" class="button button-large wpforo-ai-buy-credits-btn" data-pack="4500" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2618 <?php _e( 'Buy Now', 'wpforo' ); ?>
2619 </button>
2620 </div>
2621 </div>
2622
2623 <!-- 15000 Credits Pack -->
2624 <div class="credit-pack">
2625 <div class="credit-pack-header">
2626 <h4><?php _e( '15,000 Credits', 'wpforo' ); ?></h4>
2627 <div class="credit-pack-price">$<?php echo esc_html( number_format( $credit_packs['15000']['price'], 0 ) ); ?><span class="credit-pack-period"><?php _e( 'one-time', 'wpforo' ); ?></span></div>
2628 </div>
2629 <div class="credit-pack-action">
2630 <button type="button" class="button button-large wpforo-ai-buy-credits-btn" data-pack="15000" data-tenant-id="<?php echo esc_attr( $tenant_id ); ?>">
2631 <?php _e( 'Buy Now', 'wpforo' ); ?>
2632 </button>
2633 </div>
2634 </div>
2635 </div>
2636
2637 <div class="wpforo-ai-credit-packs-note">
2638 <p><strong><?php _e( 'Important:', 'wpforo' ); ?></strong> <?php _e( 'Credit packs are one-time purchases that accumulate with your monthly subscription credits up to your plan\'s maximum accumulation limit (one year of subscription plan credits). Credits can only be used while you have an active subscription. If your subscription expires, your credits will remain in your account but cannot be used until you reactivate your subscription.', 'wpforo' ); ?></p>
2639 </div>
2640 </div>
2641
2642 <!-- Credit Pack Checkout Configurations -->
2643 <script type="text/javascript">
2644 <?php $credit_providers = wpforo_ai_get_enabled_providers(); ?>
2645 <?php if ( in_array( 'freemius', $credit_providers, true ) ) : ?>
2646 // Add credit pack configurations to existing wpforoFreemiusCheckout object
2647 if (typeof window.wpforoFreemiusCheckout === 'undefined') {
2648 window.wpforoFreemiusCheckout = { tenant_id: <?php echo json_encode( $tenant_id ); ?> };
2649 }
2650 window.wpforoFreemiusCheckout.creditPacks = {
2651 '500': <?php echo json_encode( wpforo_ai_get_credit_pack_config( $tenant_id, '500' ) ); ?>,
2652 '1500': <?php echo json_encode( wpforo_ai_get_credit_pack_config( $tenant_id, '1500' ) ); ?>,
2653 '4500': <?php echo json_encode( wpforo_ai_get_credit_pack_config( $tenant_id, '4500' ) ); ?>,
2654 '15000': <?php echo json_encode( wpforo_ai_get_credit_pack_config( $tenant_id, '15000' ) ); ?>
2655 };
2656 <?php endif; ?>
2657 </script>
2658 <?php
2659 }
2660
2661 /**
2662 * Get user data for Freemius checkout
2663 *
2664 * Returns the current WordPress user's email and name for pre-filling the checkout form.
2665 * Only uses actual first_name and last_name from user meta - no fallbacks to avoid wrong data.
2666 *
2667 * @return array User data with 'email', 'first', and 'last' keys
2668 */
2669 function wpforo_ai_get_freemius_user_data() {
2670 $current_user = wp_get_current_user();
2671
2672 // Get email - prefer current user's email, fallback to admin email
2673 $email = ! empty( $current_user->user_email ) ? $current_user->user_email : get_option( 'admin_email' );
2674
2675 // Get first name and last name from user meta only - no fallbacks
2676 // Empty is better than wrong data (like website title)
2677 $first_name = ! empty( $current_user->first_name ) ? $current_user->first_name : '';
2678 $last_name = ! empty( $current_user->last_name ) ? $current_user->last_name : '';
2679
2680 return [
2681 'email' => $email,
2682 'first' => $first_name,
2683 'last' => $last_name,
2684 ];
2685 }
2686
2687 /**
2688 * Get Freemius upgrade URL
2689 *
2690 * @param string $tenant_id Tenant ID
2691 * @param string $plan Plan name ('starter', 'professional', 'business', 'enterprise')
2692 * @return string Checkout URL
2693 */
2694 function wpforo_ai_get_upgrade_url( $tenant_id, $plan = 'professional' ) {
2695 // Freemius plugin configuration
2696 // wpForo AI Addon ID: 21923
2697 $freemius_plugin_id = wpforo_get_option( 'ai_freemius_plugin_id', '21923' );
2698
2699 // Ensure plugin_id is never empty
2700 if ( empty( $freemius_plugin_id ) ) {
2701 $freemius_plugin_id = '21923';
2702 }
2703
2704 // Fetch dynamic pricing from Freemius API (with fallback to defaults)
2705 $pricing = wpforo_ai_get_freemius_pricing();
2706 $plans = $pricing['plans'];
2707
2708 $config = [
2709 'starter' => [
2710 'plugin_id' => $freemius_plugin_id,
2711 'plan_id' => $plans['starter']['plan_id'],
2712 'pricing_id' => $plans['starter']['pricing_id'],
2713 ],
2714 'professional' => [
2715 'plugin_id' => $freemius_plugin_id,
2716 'plan_id' => $plans['professional']['plan_id'],
2717 'pricing_id' => $plans['professional']['pricing_id'],
2718 ],
2719 'business' => [
2720 'plugin_id' => $freemius_plugin_id,
2721 'plan_id' => $plans['business']['plan_id'],
2722 'pricing_id' => $plans['business']['pricing_id'],
2723 ],
2724 'enterprise' => [
2725 'plugin_id' => $freemius_plugin_id,
2726 'plan_id' => $plans['enterprise']['plan_id'],
2727 'pricing_id' => $plans['enterprise']['pricing_id'],
2728 ],
2729 ];
2730
2731 $plan_config = isset( $config[ $plan ] ) ? $config[ $plan ] : $config['professional'];
2732
2733 // Ensure plan_config is valid
2734 if ( ! is_array( $plan_config ) ) {
2735 $plan_config = $config['professional'];
2736 }
2737
2738 // Get API Gateway webhook URL
2739 $webhook_url = WPF()->ai_client->get_api_base_url() . '/v1/freemius/webhook';
2740
2741 // Build config object for JavaScript (not a URL)
2742 $plugin_id = isset( $plan_config['plugin_id'] ) && ! empty( $plan_config['plugin_id'] ) ? $plan_config['plugin_id'] : '21923';
2743 $plan_id = isset( $plan_config['plan_id'] ) && ! empty( $plan_config['plan_id'] ) ? $plan_config['plan_id'] : $plans['professional']['plan_id'];
2744 $pricing_id = isset( $plan_config['pricing_id'] ) && ! empty( $plan_config['pricing_id'] ) ? $plan_config['pricing_id'] : $plans['professional']['pricing_id'];
2745
2746 return [
2747 'plugin_id' => $plugin_id,
2748 'plan_id' => $plan_id,
2749 'pricing_id' => $pricing_id,
2750 'public_key' => 'pk_bbb26ca8c136ce743c4661e2dd23f', // Freemius Public Key
2751 'billing_cycle' => 'monthly',
2752 'currency' => 'usd',
2753 'success' => admin_url( 'admin.php?page=wpforo-ai&upgraded=1&plan=' . $plan ),
2754 'cancel' => admin_url( 'admin.php?page=wpforo-ai' ),
2755 'webhook_url' => $webhook_url,
2756 'user' => wpforo_ai_get_freemius_user_data(),
2757 'metadata' => [
2758 'tenant_id' => $tenant_id, // CRITICAL: Pass tenant_id so webhook can identify tenant
2759 ],
2760 ];
2761 }
2762
2763 /**
2764 * Get Freemius credit pack configuration
2765 *
2766 * @param string $tenant_id Tenant ID
2767 * @param string $pack Pack size ('500', '1500', '4500', '15000')
2768 * @return array Checkout configuration
2769 */
2770 function wpforo_ai_get_credit_pack_config( $tenant_id, $pack = '1500' ) {
2771 // Freemius plugin configuration
2772 // AI Credits Addon ID: 21955 (different from main wpForo AI plugin 21923)
2773 $freemius_addon_id = wpforo_get_option( 'ai_freemius_addon_id', '21955' );
2774
2775 // Ensure addon_id is never empty
2776 if ( empty( $freemius_addon_id ) ) {
2777 $freemius_addon_id = '21955';
2778 }
2779
2780 // Fetch dynamic pricing from Freemius API (with fallback to defaults)
2781 $pricing = wpforo_ai_get_freemius_pricing();
2782 $credit_packs = $pricing['credit_packs'];
2783
2784 // Credit pack add-on plan IDs from Freemius
2785 $config = [
2786 '500' => [
2787 'plugin_id' => $freemius_addon_id,
2788 'plan_id' => $credit_packs['500']['plan_id'],
2789 'pricing_id' => $credit_packs['500']['pricing_id'],
2790 ],
2791 '1500' => [
2792 'plugin_id' => $freemius_addon_id,
2793 'plan_id' => $credit_packs['1500']['plan_id'],
2794 'pricing_id' => $credit_packs['1500']['pricing_id'],
2795 ],
2796 '4500' => [
2797 'plugin_id' => $freemius_addon_id,
2798 'plan_id' => $credit_packs['4500']['plan_id'],
2799 'pricing_id' => $credit_packs['4500']['pricing_id'],
2800 ],
2801 '15000' => [
2802 'plugin_id' => $freemius_addon_id,
2803 'plan_id' => $credit_packs['15000']['plan_id'],
2804 'pricing_id' => $credit_packs['15000']['pricing_id'],
2805 ],
2806 ];
2807
2808 $pack_config = isset( $config[ $pack ] ) ? $config[ $pack ] : $config['1500'];
2809
2810 // Ensure pack_config is valid
2811 if ( ! is_array( $pack_config ) ) {
2812 $pack_config = $config['1500'];
2813 }
2814
2815 // Get API Gateway webhook URL
2816 $webhook_url = WPF()->ai_client->get_api_base_url() . '/v1/freemius/webhook';
2817
2818 // Build config object for JavaScript (not a URL)
2819 $plugin_id = isset( $pack_config['plugin_id'] ) && ! empty( $pack_config['plugin_id'] ) ? $pack_config['plugin_id'] : '21955';
2820 $plan_id = isset( $pack_config['plan_id'] ) && ! empty( $pack_config['plan_id'] ) ? $pack_config['plan_id'] : $credit_packs['1500']['plan_id'];
2821 $pricing_id = isset( $pack_config['pricing_id'] ) && ! empty( $pack_config['pricing_id'] ) ? $pack_config['pricing_id'] : $credit_packs['1500']['pricing_id'];
2822
2823 return [
2824 'plugin_id' => $plugin_id,
2825 'plan_id' => $plan_id,
2826 'pricing_id' => $pricing_id,
2827 'public_key' => 'pk_d241fb18a0097c75e4de7c12d8b67', // AI Credits Addon Public Key
2828 'billing_cycle' => 'one-time',
2829 'currency' => 'usd',
2830 'success' => admin_url( 'admin.php?page=wpforo-ai&credits_purchased=1&pack=' . $pack ),
2831 'cancel' => admin_url( 'admin.php?page=wpforo-ai' ),
2832 'webhook_url' => $webhook_url,
2833 'user' => wpforo_ai_get_freemius_user_data(),
2834 'metadata' => [
2835 'tenant_id' => $tenant_id, // CRITICAL: Pass tenant_id so webhook can identify tenant
2836 'is_addon' => true, // Flag to distinguish add-on from subscription
2837 ],
2838 ];
2839 }
2840
2841 /**
2842 * Get manage subscription URL based on payment provider
2843 *
2844 * For Paddle: customer-portal.paddle.com/cpl_{ID} (seller-specific portal with email login)
2845 * For Freemius: customers.gvectors.com (Freemius customer portal)
2846 *
2847 * @return string Manage subscription URL
2848 */
2849 function wpforo_ai_get_manage_subscription_url( $provider = '' ) {
2850 // If no provider specified, use the stored default
2851 if ( ! $provider ) {
2852 $provider = get_option( 'wpforo_ai_payment_provider', '' );
2853 }
2854
2855 if ( $provider === 'paddle' ) {
2856 // Paddle customer portal with seller-specific CPL ID
2857 // Shows email login page where customers get a magic link
2858 $url = 'https://customer-portal.paddle.com/cpl_01f49qd36rqh2vswk36847drxt';
2859 } else {
2860 $url = 'https://customers.gvectors.com';
2861 }
2862
2863 return apply_filters( 'wpforo_ai_manage_subscription_url', $url, $provider );
2864 }
2865
2866 /**
2867 * Get CSS class for credit status based on percentage remaining
2868 *
2869 * @param int $percent Percentage remaining
2870 * @return string CSS class
2871 */
2872 function wpforo_ai_get_credit_status_class( $percent ) {
2873 if ( $percent >= 50 ) {
2874 return 'status-good';
2875 } elseif ( $percent >= 20 ) {
2876 return 'status-warning';
2877 } else {
2878 return 'status-critical';
2879 }
2880 }
2881
2882 /**
2883 * Format date for display
2884 *
2885 * @param string $date ISO 8601 date string
2886 * @return string Formatted date
2887 */
2888