render(
$this->viewData()
);
return $view ?? ob_get_clean();
}
public static function register()
{
parent::register();
// Add wildcard customer profile pages
// add a custom permalink endpoint
add_action('init', function () {
$pageSlug = (new StoreSettings())->getCustomerDashboardPageSlug();
$customerProfilePageId = (new StoreSettings())->getCustomerProfilePageId();
static::$slug = $pageSlug;
if($customerProfilePageId && $pageSlug) {
add_rewrite_rule(
'^'.$pageSlug.'/(.+)?$',
'index.php?page_id='.$customerProfilePageId,
'top'
);
}
});
}
public function render(?array $viewData = null)
{
if (!is_user_logged_in()) {
ob_start();
$redirectUrl = (new StoreSettings())->getCustomerProfilePage();
if (defined('FLUENT_AUTH_VERSION') && (new \FluentAuth\App\Hooks\Handlers\CustomAuthHandler())->isEnabled()) {
?>
';
} else {
?>
renderCustomerAppContainer();
}
public function renderCustomerAppContainer()
{
// Enqueue global styles
Vite::enqueueStyle( 'fluent-cart-customer-profile-global',
'public/customer-profile/style/customer-profile-global.scss',
);
$customEndpointContent = $this->maybeCustomEndpointContent();
if(!$customEndpointContent) {
(new static())->enqueueStyles();
}
$colors = self::generateCssColorVariables(Arr::get($this->shortCodeAttributes, 'colors', ''));
add_action('fluent_cart/customer_menu', array($this, 'renderCustomerMenu'));
add_action('fluent_cart/customer_app', function () use ($customEndpointContent) {
if($customEndpointContent) {
echo $customEndpointContent; // @phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
} else {
AssetLoader::loadCustomerDashboardAssets();
$this->renderCustomerApp();
}
});
App::make('view')->render('frontend.customer_app', [
'wp_page_title' => get_the_title(),
'colors' => $colors,
'active_tab' => apply_filters('fluent_cart/customer_portal/active_tab', ''),
]);
}
public function maybeCustomEndpointContent() {
global $wp;
$requestedPath = $wp->request;
// remove static::$slug from the requested path
if (static::$slug && Str::startsWith($requestedPath, static::$slug)) {
$requestedPath = Str::replaceFirst(static::$slug, '', $requestedPath);
$requestedPath = trim($requestedPath, '/');
}
if($requestedPath) {
$paths = explode('/', $requestedPath);
$requestedPath = array_shift($paths);
}
$reserved = ['dashboard', 'purchase-history', 'subscriptions', 'licenses', 'downloads', 'profile'];
if(!$requestedPath || in_array($requestedPath, $reserved)) {
return ''; // No specific path requested, return early
}
// Maybe it's a custom endpoint path
$customEndpoints = apply_filters('fluent_cart/customer_portal/custom_endpoints', []);
if(empty($customEndpoints) || !isset($customEndpoints[$requestedPath])) {
return ''; // No custom endpoints defined, return early
}
ob_start();
$endpoint = $customEndpoints[$requestedPath];
add_filter('fluent_cart/customer_portal/active_tab', function ($activeTab) use ($requestedPath) {
return $requestedPath;
});
if (isset($endpoint['render_callback']) && is_callable($endpoint['render_callback'])) {
call_user_func($endpoint['render_callback']);
return ob_get_clean();
}
if(isset($endpoint['page_id'])) {
$pageId = (int) $endpoint['page_id'];
// Create a custom query to fetch the two pages
$args = array(
'post_type' => 'page',
'post__in' => [$pageId],
'posts_per_page' => 1,
'orderby' => 'post__in', // Preserve the order of the IDs
);
$page_query = new \WP_Query($args);
// Check if the query has posts
if ($page_query->have_posts()) :
while ($page_query->have_posts()) : $page_query->the_post();
?>
' . esc_html__('No content found!', 'fluent-cart') . '';
endif;
}
return ob_get_clean();
}
public function renderCustomerApp()
{
echo '
';
}
public function renderCustomerMenu()
{
$baseUrl = TemplateService::getCustomerProfileUrl('/');
$menuItems = [
'dashboard' => [
'label' => __('Dashboard', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl,
'icon_svg' => '
',
],
'purchase-history' => [
'label' => __('Purchase History', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl . 'purchase-history',
'icon_svg' => '
'
],
'subscriptions' => [
'label' => __('Subscription Plans', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl . 'subscriptions',
'icon_svg' => '
'
],
'licenses' => [
'label' => __('Licenses', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl . 'licenses',
'icon_svg' => '
'
],
'downloads' => [
'label' => __('Downloads', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl . 'downloads',
'icon_svg' => '
'
],
'profile' => [
'label' => __('Profile', 'fluent-cart'),
'css_class' => 'fct_route',
'link' => $baseUrl . 'profile',
'icon_svg' => '
'
]
];
$currentCustomer = CustomerResource::getCurrentCustomer();
if (!ModuleSettings::isActive('license') || !App::isProActive()) {
unset($menuItems['licenses']);
}
if($currentCustomer) {
$hasSubscriptions = Subscription::query()->where('customer_id', $currentCustomer->id)->exists();
if(!$hasSubscriptions) {
unset($menuItems['subscriptions']);
}
} else {
unset($menuItems['subscriptions']);
}
$menuItems = apply_filters('fluent_cart/global_customer_menu_items', $menuItems, [
'base_url' => $baseUrl
]);
$profileData = null;
if($currentCustomer) {
$profileData = [
'email' => $currentCustomer->email,
'full_name' => $currentCustomer->full_name,
'photo' => $currentCustomer->photo
];
} else if(is_user_logged_in()) {
$user = wp_get_current_user();
$profileData = [
'email' => $user->user_email,
'full_name' => $user->display_name,
'photo' => get_avatar_url($user->ID)
];
}
add_filter('fct_allowed_svg_tags', function ($tags) {
return [
'svg' => [
'xmlns' => true,
'width' => true,
'height' => true,
'viewBox' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true,
'class' => true
],
'path' => [
'd' => true,
'fill' => true,
'stroke' => true,
'stroke-width' => true
],
'g' => [
'fill' => true,
'stroke' => true
]
];
});
App::make('view')->render('frontend.customer_menu', [
'menuItems' => $menuItems,
'profileData' => $profileData,
]);
}
public static function getLocalizationData($attributes = []):array
{
$currentCustomer = CustomerResource::getCurrentCustomer();
$customerEmail = $currentCustomer ? $currentCustomer->email : '';
$pageUrl = TemplateService::getCustomerProfileUrl();
$pageSlug = trim(str_replace(home_url('/'), '', $pageUrl), '/');
$dashboardSlug = (new StoreSettings())->getCustomerDashboardPageSlug();
if($pageSlug !== $dashboardSlug) {
// we should resave the page slug from settings
$prevSettings = (new StoreSettings())->get();
(new StoreSettings())->save($prevSettings);
}
$shopLocalizationData = Helper::shopConfig();
$shopLocalizationData['shop_url'] = (new StoreSettings())->getShopPage();
// For supporting subdirectory installations
$domainParts = parse_url(home_url('/'));
// if we have path in domain url, we need to set it as base path
$basePath = trim(Arr::get($domainParts, 'path', ''), '/');
if($basePath && $basePath !== '/') {
$pageSlug = $basePath.'/'.$pageSlug;
}
return [
'fluentcart_customer_profile_vars' => [
'app_slug' => $pageSlug,
'app_url' => TemplateService::getCustomerProfileUrl(),
'shop' => $shopLocalizationData,
'trans' => TransStrings::getCustomerProfileString(),
'download_url_base' => site_url('fluent-cart/download-file/?fluent_cart_download=true'),
'placeholder_image' => Vite::getAssetUrl('images/placeholder.svg'),
'stripe_pub_key' => apply_filters('fluent_cart/payment_methods/stripe_pub_key', ''),
'paypal_client_id' => apply_filters('fluent_cart/payment_methods/paypal_client_id', '', []),
'assets_path' => Vite::getAssetUrl(),
'rest' => Helper::getRestInfo(),
'customer_email' => $customerEmail,
'wp_page_title' => get_the_title(),
'payment_methods' => PaymentMethods::getActiveMeta(),
'site_url' => site_url(),
'me' => [
'email' => $currentCustomer ? $currentCustomer->email : '',
'first_name' => $currentCustomer ? $currentCustomer->first_name : '',
'last_name' => $currentCustomer ? $currentCustomer->last_name : '',
'photo' => $currentCustomer ? $currentCustomer->photo : ''
],
'logout_url' => wp_logout_url(home_url()),
'datei18' => TransStrings::dateTimeStrings(),
'el_strings' => TransStrings::elStrings(),
'wp_locale' => get_locale()
],
'fluentCartRestVars' => [
'rest' => Helper::getRestInfo(),
],
];
}
public function localizeData(): array
{
return static::getLocalizationData($this->shortCodeAttributes);
}
private static function generateCssColorVariables($colors): string
{
$cssVariables = '';
if (!empty($colors)) {
// Split the colors string by commas to separate each key-value pair
$pairs = explode(',', $colors);
$colorVariables = [];
foreach ($pairs as $pair) {
list($key, $value) = explode('=', trim($pair));
// Only add to the array if the value is not empty or just a semicolon
if (!empty($value) && $value !== ';') {
$colorVariables[] = "$key: $value;";
}
}
$cssVariables = implode("\n", $colorVariables);
}
return $cssVariables;
}
}