Skip to content

Commit 6c7138c

Browse files
committed
Merge remote-tracking branch 'origin/develop' into trunk
2 parents 098cbf8 + 5ce1383 commit 6c7138c

21 files changed

Lines changed: 545 additions & 204 deletions

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
A simple plugin to add [JSON Web Token (JWT)](https://tools.ietf.org/html/rfc7519) Authentication to the WP REST API.
44

5+
Tested up to WordPress 6.9.1.
6+
57
To know more about JSON Web Tokens, please visit [http://jwt.io](http://jwt.io).
68

79
## Description

admin/class-jwt-auth-admin.php

Lines changed: 49 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -301,15 +301,27 @@ public function register_menu_page()
301301
[$this, 'render_admin_page']
302302
);
303303

304-
// Add Token Dashboard submenu item
305-
add_submenu_page(
306-
'options-general.php',
307-
__('Token Dashboard', 'jwt-auth'),
308-
__(' ↳ Token Details 👑', 'jwt-auth'),
309-
'manage_options',
310-
'jwt_token_dashboard',
311-
[$this, 'render_token_dashboard_page']
312-
);
304+
if (jwt_auth_should_show_upsell()) {
305+
add_submenu_page(
306+
'options-general.php',
307+
__('Token Dashboard', 'jwt-auth'),
308+
__(' ↳ Token Details 👑', 'jwt-auth'),
309+
'manage_options',
310+
'jwt_token_dashboard',
311+
[$this, 'render_token_dashboard_page']
312+
);
313+
}
314+
}
315+
316+
/**
317+
* Ensure install date tracking exists.
318+
*
319+
* @since 1.5.0
320+
* @return void
321+
*/
322+
public function track_install_date()
323+
{
324+
jwt_auth_track_install_date();
313325
}
314326

315327
/**
@@ -616,12 +628,14 @@ function ($tag, $handle) {
616628
);
617629
}
618630

631+
$upsell_metrics = jwt_auth_get_upsell_metrics();
632+
619633
// Provide WordPress API configuration to React app
620634
if ($is_dev_mode) {
621635
// For dev mode, we need to add the config manually since we're not using wp_enqueue_script
622636
add_action(
623637
'admin_footer',
624-
function () {
638+
function () use ($upsell_metrics) {
625639
$config = [
626640
'apiUrl' => rest_url('jwt-auth/v1/admin/settings'),
627641
'nonce' => wp_create_nonce('wp_rest'),
@@ -635,6 +649,11 @@ function () {
635649
'pluginCount' => count(get_option('active_plugins', [])),
636650
'signingAlgorithm' => 'HS256',
637651
],
652+
'upsell' => [
653+
'shouldShowUpsell' => (bool) $upsell_metrics['shouldShowUpsell'],
654+
'daysActive' => (int) $upsell_metrics['daysActive'],
655+
'tokensCreated' => (int) $upsell_metrics['tokensCreated'],
656+
],
638657
];
639658
echo '<script>window.jwtAuthConfig = '.wp_json_encode($config).';</script>';
640659
},
@@ -649,14 +668,19 @@ function () {
649668
'nonce' => wp_create_nonce('wp_rest'),
650669
'siteUrl' => get_bloginfo('url'),
651670
'settings' => get_option('jwt_auth_options', ['share_data' => false]),
652-
'siteProfile' => [
653-
'phpVersion' => PHP_VERSION,
654-
'wordpressVersion' => get_bloginfo('version'),
655-
'isProCompatible' => version_compare(PHP_VERSION, '7.4', '>='),
656-
'isWooCommerceDetected' => class_exists('WooCommerce'),
657-
'pluginCount' => count(get_option('active_plugins', [])),
658-
'signingAlgorithm' => 'HS256',
659-
],
671+
'siteProfile' => [
672+
'phpVersion' => PHP_VERSION,
673+
'wordpressVersion' => get_bloginfo('version'),
674+
'isProCompatible' => version_compare(PHP_VERSION, '7.4', '>='),
675+
'isWooCommerceDetected' => class_exists('WooCommerce'),
676+
'pluginCount' => count(get_option('active_plugins', [])),
677+
'signingAlgorithm' => 'HS256',
678+
],
679+
'upsell' => [
680+
'shouldShowUpsell' => (bool) $upsell_metrics['shouldShowUpsell'],
681+
'daysActive' => (int) $upsell_metrics['daysActive'],
682+
'tokensCreated' => (int) $upsell_metrics['tokensCreated'],
683+
],
660684
]
661685
);
662686
}
@@ -810,28 +834,7 @@ public function render_token_dashboard_page()
810834
*/
811835
public function add_action_link(array $links, string $file): array
812836
{
813-
814-
if ($file === 'jwt-authentication-for-wp-rest-api/jwt-auth.php') {
815-
// Fixed CTA for high-traffic plugin list (no rotation)
816-
$selected_variation = [
817-
'text' => '<b>Add Token Dashboard</b>',
818-
'utm_content' => 'token-dashboard-primary',
819-
];
820-
821-
$base_pro_url = 'https://jwtauth.pro/upgrade';
822-
$utm_params = [
823-
'utm_source' => 'plugin-list',
824-
'utm_medium' => 'action-link',
825-
'utm_campaign' => 'feature-highlight',
826-
'utm_content' => $selected_variation['utm_content'],
827-
];
828-
829-
$pro_link_url = (string) add_query_arg($utm_params, $base_pro_url);
830-
$pro_link_style = 'style="color: #00a32a; font-weight: 700; text-decoration: none;" onmouseover="this.style.color=\'#008a20\';" onmouseout="this.style.color=\'#00a32a\';"';
831-
832-
$pro_link_text = $selected_variation['text'];
833-
$links[] = '<a href="'.esc_url($pro_link_url).'" target="_blank" '.$pro_link_style.' rel="noopener noreferrer">'.$pro_link_text.'</a>';
834-
}
837+
unset($file);
835838

836839
return $links;
837840
}
@@ -1085,6 +1088,7 @@ public function get_dashboard_data($request)
10851088
}
10861089

10871090
$dismissal_data = $dismissal_response->get_data();
1091+
$upsell_metrics = jwt_auth_get_upsell_metrics();
10881092

10891093
// Return consolidated data
10901094
return new WP_REST_Response(
@@ -1093,6 +1097,11 @@ public function get_dashboard_data($request)
10931097
'jwtStatus' => $status_data,
10941098
'surveyStatus' => $survey_status_data,
10951099
'surveyDismissal' => $dismissal_data,
1100+
'upsell' => [
1101+
'shouldShowUpsell' => (bool) $upsell_metrics['shouldShowUpsell'],
1102+
'daysActive' => (int) $upsell_metrics['daysActive'],
1103+
'tokensCreated' => (int) $upsell_metrics['tokensCreated'],
1104+
],
10961105
],
10971106
200
10981107
);

admin/ui/src/components/Dashboard.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ export default function Dashboard() {
1616
const [configStatus, setConfigStatus] = useState<ConfigurationStatus | null>(null)
1717
const [isSurveyCtaVisible, setIsSurveyCtaVisible] = useState(false)
1818
const [shouldShowSurveyCta, setShouldShowSurveyCta] = useState(false)
19+
const [shouldShowUpsell, setShouldShowUpsell] = useState(false)
20+
const [tokensCreated, setTokensCreated] = useState(0)
21+
const [daysActive, setDaysActive] = useState(0)
22+
const [hasLoadedDashboardData, setHasLoadedDashboardData] = useState(false)
1923
const [surveyCompleted, setSurveyCompleted] = useState(false)
2024
const [isLoadingDismissal, setIsLoadingDismissal] = useState(false)
2125

@@ -60,15 +64,23 @@ export default function Dashboard() {
6064
setShareData(dashboardData.settings.share_data ?? false)
6165
setConfigStatus(dashboardData.jwtStatus)
6266
setSurveyCompleted(dashboardData.surveyStatus.completed ?? false)
67+
setShouldShowUpsell(dashboardData.upsell?.shouldShowUpsell ?? false)
68+
setTokensCreated(dashboardData.upsell?.tokensCreated ?? 0)
69+
setDaysActive(dashboardData.upsell?.daysActive ?? 0)
6370
setShouldShowSurveyCta(
64-
(dashboardData.surveyDismissal.shouldShow ?? false) &&
71+
(dashboardData.upsell?.shouldShowUpsell ?? false) &&
72+
(dashboardData.surveyDismissal.shouldShow ?? false) &&
6573
!(dashboardData.surveyStatus.completed ?? false)
6674
)
6775
}
6876
} catch (error) {
6977
if (!isCancelled) {
7078
console.error('Failed to load dashboard data:', error)
7179
}
80+
} finally {
81+
if (!isCancelled) {
82+
setHasLoadedDashboardData(true)
83+
}
7284
}
7385
}
7486

@@ -80,6 +92,17 @@ export default function Dashboard() {
8092
}
8193
}, [])
8294

95+
useEffect(() => {
96+
if (
97+
hasLoadedDashboardData &&
98+
!shouldShowUpsell &&
99+
(currentPage === 'token-dashboard' || currentPage === 'survey')
100+
) {
101+
setCurrentPage('overview')
102+
window.history.replaceState(null, '', '#overview')
103+
}
104+
}, [currentPage, hasLoadedDashboardData, shouldShowUpsell])
105+
83106
// Listen for hash changes to support back/forward navigation
84107
useEffect(() => {
85108
const handleHashChange = () => {
@@ -150,7 +173,12 @@ export default function Dashboard() {
150173
/>
151174
)
152175
case 'token-dashboard':
153-
return <TokenDashboard onBackToDashboard={() => handlePageChange('overview')} />
176+
return (
177+
<TokenDashboard
178+
onBackToDashboard={() => handlePageChange('overview')}
179+
shouldShowUpsell={shouldShowUpsell}
180+
/>
181+
)
154182
case 'overview':
155183
default: {
156184
const isJwtConfigured = configStatus?.configuration?.secret_key_configured ?? false
@@ -161,7 +189,11 @@ export default function Dashboard() {
161189
<div className="jwt-grid jwt-grid-cols-1 lg:jwt-grid-cols-2 jwt-gap-8">
162190
<ConfigurationHealthCheck configStatus={configStatus} />
163191
{isJwtConfigured ? (
164-
<SystemEnvironment configStatus={configStatus} />
192+
<SystemEnvironment
193+
configStatus={configStatus}
194+
tokensCreated={tokensCreated}
195+
daysActive={daysActive}
196+
/>
165197
) : (
166198
<SetupConfiguration />
167199
)}
@@ -176,13 +208,19 @@ export default function Dashboard() {
176208

177209
return (
178210
<div className="jwt-flex jwt-flex-col jwt-min-h-screen jwt-bg-gray-50">
179-
<Topbar currentPage={currentPage} onPageChange={handlePageChange} />
211+
<Topbar
212+
currentPage={currentPage}
213+
onPageChange={handlePageChange}
214+
shouldShowUpsell={shouldShowUpsell}
215+
tokensCreated={tokensCreated}
216+
/>
180217
<main className="jwt-flex-1 jwt-p-6 sm:jwt-p-8 lg:jwt-p-12 jwt-container jwt-mx-auto">
181218
{renderPage()}
182219
</main>
183220
<FloatingSurveyCTA
184221
isVisible={
185222
isSurveyCtaVisible &&
223+
shouldShowUpsell &&
186224
currentPage !== 'survey' &&
187225
currentPage !== 'token-dashboard' &&
188226
!isLoadingDismissal

admin/ui/src/components/dashboard/system-environment.tsx

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ import type { ConfigurationStatus } from '@/lib/wordpress-api'
66

77
interface SystemEnvironmentProps {
88
configStatus: ConfigurationStatus | null
9+
tokensCreated: number
10+
daysActive: number
911
}
1012

11-
export const SystemEnvironment = ({ configStatus }: SystemEnvironmentProps) => {
13+
export const SystemEnvironment = ({
14+
configStatus,
15+
tokensCreated,
16+
daysActive,
17+
}: SystemEnvironmentProps) => {
1218
if (!configStatus) {
1319
return (
1420
<InfoCard title="System Environment Check" description="Loading system information...">
@@ -21,6 +27,8 @@ export const SystemEnvironment = ({ configStatus }: SystemEnvironmentProps) => {
2127

2228
const { system } = configStatus
2329
const allCompatible = system.php_compatible
30+
const trackingPeriodLabel =
31+
daysActive <= 0 ? 'since today' : daysActive === 1 ? 'since 1 day' : `since ${daysActive} days`
2432

2533
return (
2634
<InfoCard
@@ -49,8 +57,10 @@ export const SystemEnvironment = ({ configStatus }: SystemEnvironmentProps) => {
4957
<span className="jwt-mr-2">{system.mysql_version}</span>
5058
<Check />
5159
</StatusRow>
52-
<StatusRow label="Post Max Size">
53-
<span className="jwt-mr-2">{system.post_max_size}</span>
60+
<StatusRow label={<span className="jwt-font-bold jwt-text-slate-800">Tokens Generated</span>}>
61+
<span className="jwt-mr-2">
62+
<span className="jwt-font-bold">{tokensCreated}</span> {trackingPeriodLabel}
63+
</span>
5464
<Check />
5565
</StatusRow>
5666
</InfoCard>

admin/ui/src/components/dashboard/token-dashboard.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,17 @@ import { buildProUrl } from '@/lib/utils'
1414

1515
interface TokenDashboardProps {
1616
onBackToDashboard: () => void
17+
shouldShowUpsell: boolean
1718
}
1819

19-
export const TokenDashboard = ({ onBackToDashboard: _onBackToDashboard }: TokenDashboardProps) => {
20+
export const TokenDashboard = ({
21+
onBackToDashboard: _onBackToDashboard,
22+
shouldShowUpsell,
23+
}: TokenDashboardProps) => {
24+
if (!shouldShowUpsell) {
25+
return null
26+
}
27+
2028
const proUrl = buildProUrl({
2129
source: 'token-dashboard',
2230
medium: 'placeholder',

0 commit comments

Comments
 (0)