Skip to content

Commit e56392b

Browse files
committed
chore: added link to stats, various upsell improvements
1 parent 335cc4d commit e56392b

9 files changed

Lines changed: 169 additions & 8 deletions

File tree

src/admin/class-admin-notices.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,15 @@ public function show_activation_notice() {
4747
<strong><?php esc_html_e( 'Cimo Image Optimizer activated.', 'cimo-image-optimizer' ); ?></strong>
4848
<?php esc_html_e( 'Your images are instantly optimized within your browser as you upload — only the optimized versions ever touch your site!', 'cimo-image-optimizer' ); ?>
4949
</p>
50+
<p class="cimo-activation-notice-secondary">
51+
<?php
52+
// Translators: The %s is replaced by the Cimo Premium link.
53+
printf(
54+
esc_html__( 'Apply this to your entire media library and user uploads with %s', 'cimo-image-optimizer' ),
55+
'<a href="' . esc_url( Cimo_Admin::pricing_url( 'activation-notice', 'admin' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Cimo Premium →', 'cimo-image-optimizer' ) . '</a>'
56+
);
57+
?>
58+
</p>
5059
<p>
5160
<a href="<?php echo esc_url( $dismiss_url ); ?>" class="button button-secondary">
5261
<?php esc_html_e( 'Dismiss', 'cimo-image-optimizer' ); ?>

src/admin/class-admin.php

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ public function __construct() {
2020
add_action( 'admin_menu', [ $this, 'add_admin_menu' ] );
2121
add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_admin_scripts' ] );
2222
add_filter( 'plugin_action_links_' . plugin_basename( CIMO_FILE ), [ $this, 'add_admin_action_links' ] );
23+
if ( CIMO_BUILD === 'free' ) {
24+
add_filter( 'plugin_row_meta', [ $this, 'add_plugin_row_meta' ], 10, 2 );
25+
}
2326
}
2427

2528
// Disable thumbnail generation
@@ -55,12 +58,49 @@ public function add_admin_menu() {
5558
}
5659
}
5760

61+
/**
62+
* Pricing URL with UTM parameters (free-build upsell surfaces).
63+
*
64+
* @param string $utm_content Optional utm_content value.
65+
* @param string $utm_medium Defaults to admin; use plugins-screen for Plugins screen links.
66+
* @return string
67+
*/
68+
public static function pricing_url( $utm_content = '', $utm_medium = 'admin' ) {
69+
$args = [
70+
'utm_source' => 'plugin',
71+
'utm_medium' => $utm_medium,
72+
'utm_campaign' => 'upgrade',
73+
];
74+
if ( is_string( $utm_content ) && $utm_content !== '' ) {
75+
$args['utm_content'] = $utm_content;
76+
}
77+
return add_query_arg( $args, 'https://wpcimo.com/pricing' );
78+
}
79+
5880
/**
5981
* Add a Settings link to the plugin action links.
6082
*/
6183
public function add_admin_action_links( $links ) {
6284
$settings_link = '<a href="' . esc_url( admin_url( 'options-general.php?page=' . CIMO_SETTINGS_SLUG ) ) . '">' . esc_html__( 'Settings', 'cimo-image-optimizer' ) . '</a>';
63-
array_unshift( $links, $settings_link );
85+
if ( CIMO_BUILD === 'free' ) {
86+
$upgrade_link = '<a href="' . esc_url( self::pricing_url( 'plugins-action', 'plugins-screen' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Upgrade', 'cimo-image-optimizer' ) . '</a>';
87+
return array_merge( [ $settings_link, $upgrade_link ], $links );
88+
}
89+
return array_merge( [ $settings_link ], $links );
90+
}
91+
92+
/**
93+
* Subtle Premium link on the Plugins screen (free build only).
94+
*
95+
* @param string[] $links Existing row meta links.
96+
* @param string $file Plugin basename.
97+
* @return string[]
98+
*/
99+
public function add_plugin_row_meta( $links, $file ) {
100+
if ( CIMO_BUILD !== 'free' || plugin_basename( CIMO_FILE ) !== $file ) {
101+
return $links;
102+
}
103+
$links[] = '<a href="' . esc_url( self::pricing_url( 'plugins-row', 'plugins-screen' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Cimo Premium — bulk optimize & more', 'cimo-image-optimizer' ) . '</a>';
64104
return $links;
65105
}
66106

src/admin/class-meta-box.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,11 @@ function cimo_get_media_type_label( $mimetype ) {
219219
}
220220

221221
echo '</ul>';
222+
if ( CIMO_BUILD === 'free' && ! $is_bulk_optimized ) {
223+
echo '<p class="cimo-media-premium-hint">';
224+
echo '<a href="' . esc_url( Cimo_Admin::pricing_url( 'attachment-meta', 'admin' ) ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'Apply this to your entire library →', 'cimo-image-optimizer' ) . '</a>';
225+
echo '</p>';
226+
}
222227
// echo '</div>';
223228
} else {
224229
echo '<p>' . esc_html__( 'Cimo did not optimize this attachment.', 'cimo-image-optimizer' ) . '</p>';

src/admin/class-script-loader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ public static function enqueue_cimo_assets() {
8383
'cimoSettings',
8484
[
8585
'restUrl' => rest_url( 'cimo/v1/' ),
86+
'settingsUrl' => admin_url( 'options-general.php?page=' . CIMO_SETTINGS_SLUG . '#cimo-stats' ),
8687
'nonce' => wp_create_nonce( 'wp_rest' ),
8788
'isFrontend' => ! is_admin(),
8889
'isLoggedIn' => is_user_logged_in(),

src/admin/css/admin-page.css

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,9 @@
203203
.cimo-settings-sidebar {
204204
background: #faf6ff;
205205
border: 1px solid #d4bbf1;
206+
position: sticky;
207+
top: 40px;
208+
align-self: start;
206209

207210
.components-button {
208211
width: 100%;
@@ -528,6 +531,11 @@
528531
order: 2;
529532
}
530533

534+
.cimo-settings-sidebar {
535+
position: static;
536+
top: auto;
537+
}
538+
531539
.cimo-stats-section {
532540
grid-template-columns: 1fr 1fr;
533541
row-gap: 40px;

src/admin/css/index.css

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,22 @@
4040
line-height: 1.2;
4141
}
4242

43+
.cimo-media-premium-hint {
44+
margin: 20px 0 0;
45+
font-size: 11px;
46+
line-height: 1.45;
47+
text-align: center;
48+
}
49+
50+
.cimo-media-premium-hint a {
51+
color: #6a788b;
52+
text-decoration: none;
53+
54+
&:hover {
55+
text-decoration: underline;
56+
}
57+
}
58+
4359
.cimo-compression-savings {
4460
font-size: 21px;
4561
font-weight: 700;
@@ -48,6 +64,37 @@
4864
text-align: center;
4965
}
5066

67+
.cimo-media-stats-hint {
68+
display: inline-flex;
69+
align-items: center;
70+
margin-left: 6px;
71+
color: #8c8f94;
72+
opacity: 0.65;
73+
text-decoration: none;
74+
line-height: 0;
75+
vertical-align: middle;
76+
transition: color 0.15s ease, opacity 0.15s ease;
77+
margin-top: -2px;
78+
79+
svg {
80+
width: 16px;
81+
height: 16px;
82+
stroke-width: 3px;
83+
}
84+
}
85+
86+
.cimo-media-stats-hint:hover,
87+
.cimo-media-stats-hint:focus {
88+
color: #2271b1;
89+
opacity: 1;
90+
outline: none;
91+
}
92+
93+
.cimo-media-stats-hint:focus-visible {
94+
box-shadow: 0 0 0 1px #2271b1;
95+
border-radius: 2px;
96+
}
97+
5198
.cimo-compression-savings-bytes {
5299
display: block;
53100
font-size: 13px;

src/admin/js/media-manager/sidebar-info.js

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { domReady } from '~cimo/shared/dom-ready'
22
import { getCachedMetadata } from '~cimo/shared/metadata-saver'
3+
import { buildPricingUrl } from '~cimo/shared/pricing-url'
34
import { escape } from '~cimo/shared/util'
45
import { __, sprintf } from '@wordpress/i18n'
56
import { applyFilters } from '@wordpress/hooks'
@@ -147,9 +148,22 @@ function injectCimoMetadata( {
147148

148149
const arrow = convertedFilesize < originalFilesize ? '↓' : ( convertedFilesize > originalFilesize ? '↑' : '' )
149150

151+
const settingsUrl =
152+
typeof window !== 'undefined' && window.cimoSettings?.settingsUrl
153+
? String( window.cimoSettings.settingsUrl )
154+
: ''
155+
156+
const statsHintSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-chart-no-axes-column-icon lucide-chart-no-axes-column"><path d="M5 21v-6"/><path d="M12 21V3"/><path d="M19 21V9"/></svg>'
157+
158+
const statsHintHtml = settingsUrl
159+
? `<a class="cimo-media-stats-hint" href="${ escape( settingsUrl ) }" title="${ escape( __( 'View site-wide stats in Cimo settings', 'cimo-image-optimizer' ) ) }" aria-label="${ escape( __( 'View site-wide stats in Cimo settings', 'cimo-image-optimizer' ) ) }">${ statsHintSvg }</a>`
160+
: ''
161+
150162
html += `
151163
<li class="cimo-compression-savings ${ escape( optimizationSavingsClass ) }">
152-
Saved ${ escape( optimizationSavings ) }%
164+
<span class="cimo-compression-savings-headline">
165+
Saved ${ escape( optimizationSavings ) }%${ statsHintHtml }
166+
</span>
153167
<span class="cimo-compression-savings-bytes">(${ escape( kbSaved ) })</span>
154168
</li>
155169
`
@@ -171,7 +185,6 @@ function injectCimoMetadata( {
171185
<li class="cimo-bulk-optimization-number">
172186
⚡️ Bulk optimized
173187
</li>
174-
175188
`
176189
}
177190

@@ -197,10 +210,21 @@ function injectCimoMetadata( {
197210
<li class="cimo-time">
198211
⚡️ Done in <span class="cimo-value">${ escape( conversionTimeDisplay ) }</span>
199212
</li>
200-
</ul>
201213
`
202214
}
203215

216+
html += '</ul>'
217+
218+
const showPremiumHint = typeof window !== 'undefined' &&
219+
window.cimoSettings &&
220+
! window.cimoSettings.isPremium &&
221+
! isBulkOptimized
222+
223+
if ( showPremiumHint ) {
224+
const premiumUrl = buildPricingUrl( 'attachment-modal' )
225+
html += `<p class="cimo-media-premium-hint"><a href="${ escape( premiumUrl ) }" target="_blank" rel="noopener noreferrer">${ escape( __( 'Apply this to your entire library →', 'cimo-image-optimizer' ) ) }</a></p>`
226+
}
227+
204228
customContent.innerHTML = html
205229
container.appendChild( customContent )
206230
}

src/admin/js/page/admin-settings.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import { applyFilters } from '@wordpress/hooks'
1010
import apiFetch from '@wordpress/api-fetch'
1111
import { __, sprintf } from '@wordpress/i18n'
12+
import { buildPricingUrl } from '~cimo/shared/pricing-url'
1213
import cimoLogo from './assets/logo-long.webp'
1314

1415
const buildType = applyFilters( 'cimo.admin.settings.buildType', 'free' )
@@ -349,7 +350,7 @@ const AdminSettings = () => {
349350
<img className="cimo-logo" src={ cimoLogo } alt={ __( 'Cimo Logo', 'cimo-image-optimizer' ) } height="35" />
350351

351352
{ /* Statistics Section */ }
352-
<div className="cimo-stats-section">
353+
<div className="cimo-stats-section" id="cimo-stats">
353354
<div className="cimo-stats-column cimo-stats-column-big">
354355
<h3>{ __( 'Total Storage Saved', 'cimo-image-optimizer' ) }</h3>
355356
<div className="cimo-stats-main">
@@ -390,7 +391,7 @@ const AdminSettings = () => {
390391
if ( match ) {
391392
const num = parseFloat( match[ 1 ] )
392393
const unit = match[ 2 ].toUpperCase()
393-
if ( unit === 'MB' && num > 100 ) {
394+
if ( unit === 'MB' && num > 5 ) {
394395
showRating = true
395396
}
396397
}
@@ -629,6 +630,7 @@ const AdminSettings = () => {
629630
<PremiumPlaceholder
630631
label={ __( 'Bulk optimize existing media in your Media Library.', 'cimo-image-optimizer' ) }
631632
learnMoreUrl="https://docs.wpcimo.com/article/788-bulk-optimization"
633+
pricingUtmContent="bulk"
632634
/>
633635
) }
634636
{ buildType === 'premium' && <>
@@ -667,6 +669,7 @@ const AdminSettings = () => {
667669
<PremiumPlaceholder
668670
label={ __( 'Show a low-quality preview while the image loads, then fade in the final image.', 'cimo-image-optimizer' ) }
669671
learnMoreUrl="https://docs.wpcimo.com/article/777-low-quality-image-placeholder"
672+
pricingUtmContent="lqip"
670673
/>
671674
) }
672675
{ buildType === 'premium' && <>
@@ -771,6 +774,7 @@ const AdminSettings = () => {
771774
<PremiumPlaceholder
772775
label={ __( 'Upgrade to Premium to compress and optimize video files on upload', 'cimo-image-optimizer' ) }
773776
learnMoreUrl="https://docs.wpcimo.com/article/775-video-optimization"
777+
pricingUtmContent="video"
774778
/>
775779
) }
776780
{ buildType === 'premium' && <>
@@ -890,6 +894,7 @@ const AdminSettings = () => {
890894
<PremiumPlaceholder
891895
label={ __( 'Upgrade to Premium to compress and optimize audio files on upload', 'cimo-image-optimizer' ) }
892896
learnMoreUrl="https://docs.wpcimo.com/article/776-audio-optimization"
897+
pricingUtmContent="audio"
893898
/>
894899
) }
895900
{ buildType === 'premium' && <>
@@ -952,6 +957,7 @@ const AdminSettings = () => {
952957
<PremiumPlaceholder
953958
label={ __( 'Upgrade to Premium to compress and optimize SVG files on upload', 'cimo-image-optimizer' ) }
954959
learnMoreUrl="https://docs.wpcimo.com/article/780-svg-support"
960+
pricingUtmContent="svg"
955961
/>
956962
) }
957963
{ buildType === 'premium' && <>
@@ -1011,6 +1017,7 @@ const AdminSettings = () => {
10111017
<PremiumPlaceholder
10121018
label={ __( 'Upgrade to Premium to enter stealth mode.', 'cimo-image-optimizer' ) }
10131019
learnMoreUrl="https://docs.wpcimo.com/article/782-stealth-mode"
1020+
pricingUtmContent="stealth"
10141021
/>
10151022
) }
10161023
{ buildType === 'premium' && <>
@@ -1135,7 +1142,7 @@ const AdminSettings = () => {
11351142

11361143
<div className="cimo-premium-cta">
11371144
<Button
1138-
href="https://wpcimo.com/pricing?utm_source=plugin&utm_medium=admin&utm_campaign=upgrade"
1145+
href={ buildPricingUrl( 'sidebar' ) }
11391146
variant="primary"
11401147
target="_blank"
11411148
rel="noopener noreferrer"
@@ -1156,6 +1163,7 @@ const AdminSettings = () => {
11561163
export default AdminSettings
11571164

11581165
const PremiumPlaceholder = props => {
1166+
const pricingHref = buildPricingUrl( props.pricingUtmContent || 'placeholder' )
11591167
return (
11601168
<div className="cimo-settings-premium-placeholder">
11611169
{ props.label }
@@ -1165,7 +1173,7 @@ const PremiumPlaceholder = props => {
11651173
<Button
11661174
variant="secondary"
11671175
className="cimo-premium-cta cimo-premium-cta-upgrade"
1168-
href="https://wpcimo.com/pricing"
1176+
href={ pricingHref }
11691177
target="_blank"
11701178
rel="noopener noreferrer"
11711179
>

src/shared/pricing-url.js

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const PRICING_BASE = 'https://wpcimo.com/pricing'
2+
3+
/**
4+
* Build pricing URL with UTM query parameters.
5+
*
6+
* @param {string} [utmContent] Feature surface id, e.g. `bulk`, `sidebar`.
7+
* @param {string} [utmMedium] Defaults to `admin`; use `plugins-screen` for Plugins list.
8+
* @return {string} Full pricing URL including query string.
9+
*/
10+
export function buildPricingUrl( utmContent = '', utmMedium = 'admin' ) {
11+
const params = new URLSearchParams()
12+
params.set( 'utm_source', 'plugin' )
13+
params.set( 'utm_medium', utmMedium )
14+
params.set( 'utm_campaign', 'upgrade' )
15+
if ( utmContent ) {
16+
params.set( 'utm_content', utmContent )
17+
}
18+
return `${ PRICING_BASE }?${ params.toString() }`
19+
}

0 commit comments

Comments
 (0)