Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions includes/Admin.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Admin {

const TC_REMOVED_KEY = 'tiob_tc_removed';
const TC_NEW_NOTICE_DISMISSED = 'tiob_new_tc_notice_dismissed';
const ONBOARDING_PROMO_NOTICE_DISMISSED = 'tiob_onboarding_promo_notice_dismissed';
const VISITED_LIBRARY_OPT = 'tiob_library_visited';

/**
Expand Down Expand Up @@ -88,6 +89,7 @@ public function init() {
add_action( 'wp_ajax_tpc_get_logs', array( $this, 'external_get_logs' ) );

add_action( 'wp_ajax_dismiss_new_tc_notice', array( $this, 'dismiss_new_tc_notice' ) );
add_action( 'wp_ajax_dismiss_onboarding_promo_notice', array( $this, 'dismiss_onboarding_promo_notice' ) );

$this->register_feedback_settings();

Expand Down Expand Up @@ -161,6 +163,86 @@ public function dismiss_new_tc_notice() {
$this->ensure_ajax_response( $response );
}

/**
* Dismiss onboarding promo notice.
*
* @return void
*/
public function dismiss_onboarding_promo_notice() {
$response = array(
'success' => false,
'code' => 'ti__ob_not_allowed',
'message' => 'Not allowed!',
);

if ( ! isset( $_REQUEST['nonce'] ) ) {
$this->ensure_ajax_response( $response );
return;
}

$nonce = sanitize_text_field( wp_unslash( $_REQUEST['nonce'] ) );

if ( ! wp_verify_nonce( $nonce, 'dismiss_onboarding_promo_notice' ) ) {
$this->ensure_ajax_response( $response );
return;
}

if ( ! current_user_can( 'install_plugins' ) ) {
$this->ensure_ajax_response( $response );
return;
}

$response['success'] = true;
unset( $response['code'] );
unset( $response['message'] );
Comment thread
harshitarora-in marked this conversation as resolved.

update_option( self::ONBOARDING_PROMO_NOTICE_DISMISSED, 'yes' );
$this->ensure_ajax_response( $response );
}

/**
* Decide if the onboarding promo notice should be shown.
*
* @return bool
*/
private function should_show_onboarding_promo_notice() {
return get_option( self::ONBOARDING_PROMO_NOTICE_DISMISSED, 'no' ) !== 'yes';
}

/**
* Decide if the business/agency variant of the onboarding promo text should be shown.
*
* @return bool
*/
private function should_show_business_agency_promo_text() {
$license_data = License::get_license_data();
$license_key = isset( $license_data->key ) ? strtolower( trim( (string) $license_data->key ) ) : '';
$license_tier = License::get_license_tier( 0 );
$raw_tier = isset( $license_data->tier ) ? absint( $license_data->tier ) : 0;
$neve_plan = apply_filters( 'product_neve_license_plan', -1 );

Comment on lines +217 to +223
if ( $license_key === '' || $license_key === 'free' ) {
return false;
}

if ( ! License::has_active_license() || ! $this->has_valid_addons() ) {
return false;
}

// Check Neve plan only if it's a valid category (not -1 default)
if ( -1 !== $neve_plan && in_array( $neve_plan, array( 1, 2, 3, 4, 5, 6, 7, 8, 9 ), true ) ) {
// Normalize Neve plan category to TPC tier using License::NEVE_CATEGORY_MAPPING
$normalized_neve_tier = isset( License::NEVE_CATEGORY_MAPPING[ $neve_plan ] ) ? License::NEVE_CATEGORY_MAPPING[ $neve_plan ] : -1;
return in_array( $normalized_neve_tier, array( 2, 3 ), true );
Comment on lines +232 to +236
}

if ( in_array( $raw_tier, array( 1, 2, 7, 12, 18 ), true ) ) {
return false;
}

return in_array( $license_tier, array( 2, 3 ), true );
}


/**
* Register hooks to prevent meta cloning for the templates.
Expand Down Expand Up @@ -789,6 +871,7 @@ private function get_localization() {
),
'cleanupAllowed' => ( ! empty( get_transient( Active_State::STATE_NAME ) ) ) ? 'yes' : 'no',
'onboarding' => array(),
'adminUrl' => admin_url(),
'hasFileSystem' => WP_Filesystem(),
'themesURL' => admin_url( 'themes.php' ),
'themeAction' => $this->get_theme_action(),
Expand All @@ -804,6 +887,7 @@ private function get_localization() {
'upsellNotifications' => $this->get_upsell_notifications(),
'isValidLicense' => $this->has_valid_addons(),
'licenseTIOB' => License::get_license_data(),
'onboardingShowProNoticeText' => $this->should_show_business_agency_promo_text(),
'emailSubscribe' => array(
'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
'nonce' => wp_create_nonce( 'skip_subscribe_nonce' ),
Expand Down Expand Up @@ -855,6 +939,11 @@ private function get_localization() {
'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
'nonce' => wp_create_nonce( 'dismiss_new_tc_notice' ),
),
'onboardingPromoNotice' => array(
'show' => $this->should_show_onboarding_promo_notice(),
'ajaxURL' => esc_url( admin_url( 'admin-ajax.php' ) ),
'nonce' => wp_create_nonce( 'dismiss_onboarding_promo_notice' ),
),
'onboardingPluginCompatibility' => array(
'hyve-lite' => is_php_version_compatible( '8.1' ),
),
Expand Down
7 changes: 5 additions & 2 deletions onboarding/src/Components/Header.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ const Header = ( { handleLogoClick, importing, step, trackingId } ) => {
step_id: step,
step_status: 'exit',
};
const site = tiobDash.onboarding.homeUrl || '';
const adminUrl =
tiobDash.onboarding?.adminUrl ||
tiobDash.adminUrl ||
( tiobDash.onboarding.homeUrl || '' ) + '/wp-admin/';

const trackingPromise = track( trackingId, data );

Expand All @@ -36,7 +39,7 @@ const Header = ( { handleLogoClick, importing, step, trackingId } ) => {
console.error( error );
} )
.finally( () => {
window.location.href = site + '/wp-admin';
window.location.href = adminUrl;
} );
};

Expand Down
96 changes: 96 additions & 0 deletions onboarding/src/Components/OnboardingPromoNotice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/* global tiobDash */
import { __, sprintf } from '@wordpress/i18n';
import { createInterpolateElement, useState } from '@wordpress/element';
import { ajaxAction } from '../utils/rest';

const OnboardingPromoNotice = () => {
const shouldShowNotice = Boolean( tiobDash.onboardingPromoNotice?.show );
const showProMessage = Boolean( tiobDash.onboardingShowProNoticeText );

const emailBody = sprintf(
/* translators: %s: double line break in the starter site request email template */
__(
'Hi Neve team,%1$sI\'m looking for a starter site for the following project:%1$sProject type: (e.g. Restaurant, Law Firm, SaaS)%1$sKey pages needed: (e.g. Home, About, Services, Contact)%1$sStyle preference: (e.g. Minimal, Bold, Corporate)%1$sAny references: (optional)%1$sThanks',
'templates-patterns-collection'
),
'\n\n'
);

const requestSiteLink =
'mailto:contact@themeisle.com?subject=' +
encodeURIComponent(
__( 'Starter Site Request', 'templates-patterns-collection' )
) +
'&body=' +
encodeURIComponent( emailBody );

const noticeMessage = showProMessage
? createInterpolateElement(
__(
'Fresh designs built for every niche. Can\'t find what you\'re looking for? As a Pro user, <requestSiteLink>request a site</requestSiteLink> and we\'ll build it for you.',
'templates-patterns-collection'
),
{
requestSiteLink: (
/* eslint-disable-next-line jsx-a11y/anchor-has-content */
<a
href={ requestSiteLink }
className="ob-onboarding-promo-link"
/>
),
}
)
: __(
Comment thread
harshitarora-in marked this conversation as resolved.
'From free to pro, fresh designs built for every niche. More coming soon.',
'templates-patterns-collection'
);

const [ isVisible, setIsVisible ] = useState( shouldShowNotice );

if ( ! isVisible ) {
return null;
}

const dismissNotice = () => {
setIsVisible( false );
ajaxAction(
tiobDash.onboardingPromoNotice.ajaxURL,
'dismiss_onboarding_promo_notice',
tiobDash.onboardingPromoNotice.nonce
).catch( () => null );
Comment on lines +54 to +60
Comment on lines +54 to +60
};

return (
<div className="ob-onboarding-promo" role="status">
<div className="ob-onboarding-promo-badge">
{ __( 'New', 'templates-patterns-collection' ) }
</div>
<div className="ob-onboarding-promo-content">
<h3>
{ sprintf(
/* translators: %s: number of new starter sites */
__(
'%s new starter sites, just landed.',
'templates-patterns-collection'
),
'80+'
) }
</h3>
<p>{ noticeMessage }</p>
</div>
<button
type="button"
className="ob-onboarding-promo-close"
onClick={ dismissNotice }
aria-label={ __(
'Dismiss notice',
'templates-patterns-collection'
) }
>
×
</button>
</div>
);
};

export default OnboardingPromoNotice;
2 changes: 2 additions & 0 deletions onboarding/src/Components/Steps/SiteList.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Toast from '../Toast';
import Filters from '../Filters';
import Sites from '../Sites';
import EditorSelector from '../EditorSelector';
import OnboardingPromoNotice from '../OnboardingPromoNotice';
import SVG from '../../utils/svg';

const SiteList = ( { showToast, setShowToast, setFetching } ) => {
Expand Down Expand Up @@ -53,6 +54,7 @@ const SiteList = ( { showToast, setShowToast, setFetching } ) => {
<EditorSelector />
</div>
<Filters />
<OnboardingPromoNotice />
<Sites />
{ ! tiobDash.isValidLicense && (
<Toast
Expand Down
105 changes: 105 additions & 0 deletions onboarding/src/scss/_onboarding-promo-notice.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
.ob-onboarding-promo {
display: flex;
align-items: center;
gap: 24px;
background: $primary;
border-radius: 16px;
padding: 18px 24px;
margin: 32px 0;
}

.ob-onboarding-promo-badge {
background: rgba(255, 255, 255, 0.2);
color: $inverted-text;
border-radius: 10px;
padding: 8px 14px;
text-transform: uppercase;
font-size: 14px;
line-height: 20px;
font-weight: 700;
letter-spacing: 0.06em;
flex-shrink: 0;
}

.ob-onboarding-promo-content {
flex: 1;

h3 {
margin: 0 0 6px;
color: $inverted-text;
font-size: 20px;
line-height: 30px;
font-weight: 700;
}

p {
margin: 0;
color: rgba(255, 255, 255, 0.92);
font-size: 15px;
line-height: 24px;
font-weight: 400;
}

.ob-onboarding-promo-link {
color: $inverted-text;
font-weight: 700;
text-decoration: underline;
}
}

.ob-onboarding-promo-close {
border: 0;
background: rgba(255, 255, 255, 0.2);
color: $inverted-text;
width: 40px;
height: 40px;
border-radius: 12px;
font-size: 24px;
line-height: 1;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}

@media (max-width: #{$laptop}) {
.ob-onboarding-promo {
padding: 16px;
gap: 16px;
}

.ob-onboarding-promo-badge {
font-size: 12px;
line-height: 18px;
padding: 6px 10px;
}

.ob-onboarding-promo-content {
h3 {
font-size: 18px;
line-height: 28px;
}

p {
font-size: 14px;
line-height: 22px;
}
}

.ob-onboarding-promo-close {
width: 36px;
height: 36px;
font-size: 20px;
}
}

@media (max-width: #{$tablet}) {
.ob-onboarding-promo {
flex-wrap: wrap;
}

.ob-onboarding-promo-close {
margin-left: auto;
}
}
1 change: 1 addition & 0 deletions onboarding/src/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
@import "scss/category-buttons";
@import "scss/search";
@import "scss/filters";
@import "scss/onboarding-promo-notice";
@import "scss/starter-site-card";
@import "scss/editor-selector";
@import "scss/site-settings";
Expand Down