diff --git a/includes/Admin.php b/includes/Admin.php
index 46e4aa21..a9e59f2a 100755
--- a/includes/Admin.php
+++ b/includes/Admin.php
@@ -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';
/**
@@ -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();
@@ -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'] );
+
+ 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 );
+
+ 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 );
+ }
+
+ 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.
@@ -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(),
@@ -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' ),
@@ -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' ),
),
diff --git a/onboarding/src/Components/Header.js b/onboarding/src/Components/Header.js
index 3c460bcc..cf0dff04 100644
--- a/onboarding/src/Components/Header.js
+++ b/onboarding/src/Components/Header.js
@@ -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 );
@@ -36,7 +39,7 @@ const Header = ( { handleLogoClick, importing, step, trackingId } ) => {
console.error( error );
} )
.finally( () => {
- window.location.href = site + '/wp-admin';
+ window.location.href = adminUrl;
} );
};
diff --git a/onboarding/src/Components/OnboardingPromoNotice.js b/onboarding/src/Components/OnboardingPromoNotice.js
new file mode 100644
index 00000000..9ddfee31
--- /dev/null
+++ b/onboarding/src/Components/OnboardingPromoNotice.js
@@ -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,
{ noticeMessage }
+