<?php
namespace WCBoost\Wishlist;
defined( 'ABSPATH' ) || exit;
use WCBoost\Packages\Utilities\SingletonTrait;
use WCBoost\Wishlist\Helper;
class Frontend {
use SingletonTrait;
/**
* Class constructor
*/
protected function __construct() {
add_action( 'wp', [ $this, 'template_hooks' ] );
add_action( 'wp', [ $this, 'add_nocache_headers' ] );
add_filter( 'wp_robots', [ $this, 'add_noindex_robots' ], 20 );
add_action( 'init', [ $this, 'register_scripts' ] );
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] );
}
/**
* Template hooks
*/
public function template_hooks() {
add_filter( 'body_class', [ $this, 'body_class' ] );
// Wishlist page.
add_action( 'wcboost_wishlist_before_wishlist', [ $this, 'print_notices' ], 5 );
add_action( 'wcboost_wishlist_before_wishlist', [ $this, 'wishlist_header' ], 10 );
add_action( 'wcboost_wishlist_main_content', [ $this, 'wishlist_content' ] );
if ( wc_string_to_bool( get_option( 'wcboost_wishlist_page_show_title', 'no' ) ) ) {
add_action( 'wcboost_wishlist_header', [ $this, 'wishlist_title' ] );
}
if ( wc_string_to_bool( get_option( 'wcboost_wishlist_page_show_desc', 'no' ) ) ) {
add_action( 'wcboost_wishlist_header', [ $this, 'wishlist_description' ], 20 );
}
add_action( 'wcboost_wishlist_after_wishlist', [ $this, 'wishlist_footer' ] );
if ( wc_string_to_bool( get_option( 'wcboost_wishlist_share', 'yes' ) ) ) {
add_action( 'wcboost_wishlist_footer', [ $this, 'share_buttons' ] );
}
add_action( 'wcboost_wishlist_footer', [ $this, 'link_edit_wishlist' ], 50 );
// Display button on single product page.
if ( 'theme' != wc_get_theme_support( 'wishlist::single_button_position' ) ) {
add_action( 'woocommerce_before_single_product', [ $this, 'display_wishlist_button' ] );
}
// Display button on the loop. Default is hidden.
if ( 'theme' != wc_get_theme_support( 'wishlist::loop_button_position' ) ) {
switch ( get_option( 'wcboost_wishlist_loop_button_position' ) ) {
case 'before_add_to_cart':
add_action( 'woocommerce_after_shop_loop_item', [ $this, 'loop_add_to_wishlist_button' ], 9 );
break;
case 'after_add_to_cart':
add_action( 'woocommerce_after_shop_loop_item', [ $this, 'loop_add_to_wishlist_button' ], 11 );
break;
}
}
// Display the delete button on the wishlist edit page.
add_action( 'wcboost_wishlist_after_edit_form', [ $this, 'form_delete_wishlist' ] );
add_filter( 'wcboost_wishlist_description', 'wpautop' );
add_filter( 'wcboost_wishlist_description', 'wp_kses_post' );
// Display buttons in the wishlist widget.
add_action( 'wcboost_wishlist_widget_buttons', [ $this, 'widget_buttons' ], 10, 2 );
}
/**
* Add nocache headers.
* Prevent caching on the wishlist page
*/
public function add_nocache_headers() {
if ( ! headers_sent() && Helper::is_wishlist() ) {
wc_nocache_headers();
}
}
/**
* Tell search engines stop indexing the URL with add-to-wishlist param.
*
* @param array $robots
* @return array
*/
public function add_noindex_robots( $robots ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( ! isset( $_GET['add-to-wishlist'] ) ) {
return $robots;
}
return wp_robots_no_robots( $robots );
}
/**
* Register scripts
*
* @since 1.1.0
*
* @return void
*/
public function register_scripts() {
$plugin = Plugin::instance();
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
wp_register_style( 'wcboost-wishlist', $plugin->plugin_url( '/assets/css/wishlist.css' ), [], WCBOOST_WISHLIST_VERSION );
wp_register_script( 'wcboost-wishlist', $plugin->plugin_url( '/assets/js/wishlist' . $suffix . '.js' ), [ 'jquery' ], WCBOOST_WISHLIST_VERSION, true );
wp_register_script( 'wcboost-wishlist-fragments', $plugin->plugin_url( '/assets/js/wishlist-fragments' . $suffix . '.js' ), [ 'jquery' ], WCBOOST_WISHLIST_VERSION, true );
}
/**
* Enqueue wishlist style and scripts
*/
public function enqueue_scripts() {
if ( apply_filters( 'wcboost_wishlist_enqueue_frontend_style', true ) ) {
wp_enqueue_style( 'wcboost-wishlist' );
}
if ( 'custom' == get_option( 'wcboost_wishlist_button_type' ) ) {
wp_add_inline_style( 'wcboost-wishlist', $this->get_custom_button_css() );
}
wp_enqueue_script( 'wcboost-wishlist' );
wp_localize_script( 'wcboost-wishlist', 'wcboost_wishlist_params', [
'allow_adding_variations' => get_option( 'wcboost_wishlist_allow_adding_variations' ),
'wishlist_redirect_after_add' => get_option( 'wcboost_wishlist_redirect_after_add' ),
'wishlist_url' => apply_filters( 'wcboost_wishlist_add_to_wishlist_redirect', wc_get_page_permalink( 'wishlist' ), null ),
'exists_item_behavior' => get_option( 'wcboost_wishlist_exists_item_button_behaviour', 'view_wishlist' ),
'i18n_link_copied_notice' => esc_html__( 'The wishlist link is copied to clipboard', 'wcboost-wishlist' ),
'i18n_close_button_text' => esc_html__( 'Close', 'wcboost-wishlist' ),
'i18n_add_to_wishlist' => Helper::get_button_text(),
'i18n_view_wishlist' => Helper::get_button_text( 'view' ),
'i18n_remove_from_wishlist' => Helper::get_button_text( 'remove' ),
'icon_normal' => Helper::get_wishlist_icon(),
'icon_filled' => Helper::get_wishlist_icon( true ),
'icon_loading' => Helper::get_icon( 'spinner' ),
] );
wp_enqueue_script( 'wcboost-wishlist-fragments' );
wp_localize_script( 'wcboost-wishlist-fragments', 'wcboost_wishlist_fragments_params', [
'refresh_on_load' => get_option( 'wcboost_wishlist_ajax_bypass_cache', 'no' ),
'hash_name' => 'wcboost_wishlist_hash_' . Helper::get_wishlist_hash_key(),
'timeout' => apply_filters( 'wcboost_wishlist_ajax_timeout', 5000 ),
] );
}
/**
* Add CSS classes to the body element on wishlist page
*
* @param array $classes
* @return array
*/
public function body_class( $classes ) {
if ( Helper::is_wishlist() ) {
$classes[] = 'woocommerce-page';
$classes[] = 'woocommerce-wishlist';
$classes[] = 'wcboost-wishlist-page';
}
return $classes;
}
/**
* Display notices.
* Need the additional check to avoid errors with live editor like Elementor.
*
* @return void
*/
public function print_notices() {
if ( WC()->session ) {
wc_print_notices();
}
}
/**
* Load the wishlist header template.
*
* @return void
*/
public function wishlist_header() {
$wishlist = Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
if ( ! $wishlist ) {
return;
}
if ( ! $wishlist->is_shareable() && ! $wishlist->can_edit() ) {
return;
}
$show_title = wc_string_to_bool( get_option( 'wcboost_wishlist_page_show_title', 'no' ) );
$show_desc = wc_string_to_bool( get_option( 'wcboost_wishlist_page_show_desc', 'no' ) );
$visble = $show_title || $show_desc;
if ( ! apply_filters( 'wcboost_wishlist_display_header', $visble, $wishlist ) ) {
return;
}
$args = apply_filters( 'wcboost_wishlist_header_template_args', [
'wishlist' => $wishlist,
'display_title' => $show_title,
'display_desc' => $show_desc,
], $wishlist );
wc_get_template( 'wishlist/wishlist-header.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Load the wishlist content template.
*
* @return void
*/
public function wishlist_content() {
$wishlist = Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
if ( ! $wishlist ) {
return;
}
$wishlist_layout = apply_filters( 'wcboost_wishlist_layout', 'table' );
$wishlist_layout = in_array( $wishlist_layout, apply_filters( 'wcboost_wishlist_supported_layouts', [ 'table' ] ) ) ? $wishlist_layout : 'table';
$template = 'wishlist/wishlist-' . $wishlist_layout . '.php';
$allow_variations = wc_string_to_bool( get_option( 'wcboost_wishlist_allow_adding_variations', 'no' ) );
$args = [
'layout' => $wishlist_layout,
'wishlist' => $wishlist,
'show_variation_data' => apply_filters( 'wcboost_wishlist_show_variation_data', $allow_variations ),
];
if ( 'table' == $wishlist_layout ) {
$default_columns = [
'price' => 'yes',
'stock' => 'yes',
'quantity' => 'no',
'date' => 'no',
'purchase' => 'yes',
];
$columns = get_option( 'wcboost_wishlist_table_columns', $default_columns );
$columns = wp_parse_args( $columns, $default_columns );
$args['columns'] = array_map( 'wc_string_to_bool', $columns );
}
$args = apply_filters( 'wcboost_wishlist_content_template_args', $args, $wishlist );
wc_get_template( $template, $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Load the wishlist footer template.
*
* @return void
*/
public function wishlist_footer() {
$wishlist = Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
if ( ! $wishlist ) {
return;
}
$args = apply_filters( 'wcboost_wishlist_footer_template_args', [
'wishlist' => $wishlist,
], $wishlist );
wc_get_template( 'wishlist/wishlist-footer.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Display the wishlist title html.
*
* @param \WCBoost\Wishlist\Wishlist $wishlist
* @return void
*/
public function wishlist_title( $wishlist ) {
$title = apply_filters( 'wcboost_wishlist_title', $wishlist->get_wishlist_title(), $wishlist );
if ( empty( $title ) ) {
return;
}
echo wp_kses_post( apply_filters( 'wcboost_wishlist_title_html', '<h2 class="wcboost-wishlist-title">' . $title . '</h2>', $title, $wishlist ) );
}
/**
* Display the wishlist description
*
* @param \WCBoost\Wishlist\Wishlis $wishlist
* @return void
*/
public function wishlist_description( $wishlist ) {
$desc = apply_filters( 'wcboost_wishlist_description', $wishlist->get_description() );
if ( empty( $desc ) ) {
return;
}
echo wp_kses_post( apply_filters( 'wcboost_wishlist_description_html', '<div class="wcboost-wishlist-description">' . $desc . '</div>', $desc, $wishlist ) );
}
/**
* Display social sharing buttons on wishlist page
*/
public function share_buttons( $wishlist ) {
$wishlist = $wishlist ? $wishlist : Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
if ( ! $wishlist->is_shareable() || ! $wishlist->count_items() ) {
return;
}
$socials = ['facebook', 'twitter', 'linkedin', 'tumblr', 'reddit', 'stumbleupon', 'telegram', 'whatsapp', 'pocket', 'digg', 'vk', 'email', 'link'];
$default = array_combine( $socials, array_fill( 0, count( $socials ), 'yes' ) );
$enabled = get_option( 'wcboost_wishlist_share_socials', [] );
$enabled = wp_parse_args( $enabled, $default );
$enabled = array_map( 'wc_string_to_bool', $enabled );
$enabled = array_filter( $enabled );
if ( empty( $enabled ) ) {
return;
}
// Don't display the share buttons if the wishlist is not viewed by the owner.
if ( 'shared' == $wishlist->get_status() && ! $wishlist->can_edit() ) {
return;
}
$args = apply_filters( 'wcboost_wishlist_share_template_args', [
'title' => __( 'Share', 'wcboost-wishlist' ),
'socials' => array_keys( $enabled ),
'wishlist' => $wishlist,
] );
wc_get_template( 'wishlist/share.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Display the link to edit the wishlist.
*
* @param \WCBoost\Wishlist\Wishlist $wishlist
* @return void
*/
public function link_edit_wishlist( $wishlist ) {
if ( ! $wishlist->can_edit() ) {
return;
}
$link = sprintf(
'<a href="%s" class="wcboost-wishlist-edit-link" rel="nofollow">%s</a>',
esc_url( $wishlist->get_edit_url() ),
esc_html__( 'Edit wishlist', 'wcboost-wishlist' )
);
$link = apply_filters( 'wcboost_wishlist_edit_link', $link, $wishlist );
if ( $link ) {
echo '<div class="wcboost-wishlist-edit-link-wrapper">' . wp_kses_post( $link ) . '</div>';
}
}
/**
* Load the form for deleting a wishlist.
* Don't display the form if the wishlist is not viewed by the owner, or this is the default wishlist.
*
* @param \WCBoost\Wishlist\Wishlist $wishlist
* @return void
*/
public function form_delete_wishlist( $wishlist ) {
if ( is_user_logged_in() ) {
return;
}
$wishlist = $wishlist ? $wishlist : Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
if ( ! $wishlist || ! $wishlist->can_edit() ) {
return;
}
// Don't display the delete form if this user has only one wishlist.
$wishlist_ids = \WC_Data_Store::load( 'wcboost_wishlist' )->get_wishlist_ids();
if ( count( $wishlist_ids ) <= 1 ) {
return;
}
if ( $wishlist->is_default() ) {
$message = __( 'You cannot delete your default wishlist. You have to set another list as default to delete this one.', 'wcboost-wishlist' );
} else {
$message = __( 'This action moves the wishlist to Trash. It will be kept in Trash for 30 days.', 'wcboost-wishlist' );
}
$args = apply_filters( 'wcboost_wishlist_form_delete_template_args', [
'title' => __( 'Delete this wishlist', 'wcboost-wishlist' ),
'message' => $message,
'wishlist' => $wishlist,
] );
wc_get_template( 'wishlist/form-delete-wishlist.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Template hooks to display the wishlist on the single product page.
*
* @return void
*/
public function display_wishlist_button() {
global $product;
switch ( get_option( 'wcboost_wishlist_single_button_position', wc_get_theme_support( 'wishlist::single_button_position', 'after_add_to_cart' ) ) ) {
case 'after_title':
add_action( 'woocommerce_single_product_summary', [ $this, 'single_add_to_wishlist_button' ], 6 );
break;
case 'after_excerpt':
add_action( 'woocommerce_single_product_summary', [ $this, 'single_add_to_wishlist_button' ], 25 );
break;
case 'before_add_to_cart':
if ( ! $product->is_type( 'simple' ) || ( $product->is_purchasable() && $product->is_in_stock() ) ) {
add_action( 'woocommerce_before_add_to_cart_button', [ $this, 'single_add_to_wishlist_button' ] );
} else {
add_action( 'woocommerce_single_product_summary', [ $this, 'single_add_to_wishlist_button' ], 35 );
}
break;
case 'after_add_to_cart':
if ( ! $product->is_type( 'simple' ) || ( $product->is_purchasable() && $product->is_in_stock() ) ) {
add_action( 'woocommerce_after_add_to_cart_button', [ $this, 'single_add_to_wishlist_button' ] );
} else {
add_action( 'woocommerce_single_product_summary', [ $this, 'single_add_to_wishlist_button' ], 35 );
}
break;
}
}
/**
* Display the add to wishlist button on catalog pages.
*/
public function loop_add_to_wishlist_button() {
global $product;
if ( ! $product ) {
return;
}
$wishlist = Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
$item = new Wishlist_Item( $product );
if ( $wishlist->has_item( $item ) && 'hide' == get_option( 'wcboost_wishlist_exists_item_button_behaviour' ) ) {
return;
}
$args = $this->get_button_template_args( $wishlist, $item );
wc_get_template( 'loop/add-to-wishlist.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Display the add to wishlist button on the single product page.
*/
public function single_add_to_wishlist_button() {
global $product;
if ( ! $product ) {
return;
}
$wishlist = Helper::get_wishlist( get_query_var( 'wishlist_token' ) );
$item = new Wishlist_Item( $product );
if ( $wishlist->has_item( $item ) && 'hide' == get_option( 'wcboost_wishlist_exists_item_button_behaviour' ) ) {
return;
}
$args = $this->get_button_template_args( $wishlist, $item );
$args['class'] .= ' wcboost-wishlist-single-button';
wc_get_template( 'single-product/add-to-wishlist.php', $args, '', Plugin::instance()->plugin_path() . '/templates/' );
}
/**
* Get the button template args.
* Add a new parameter "attributes" since version 1.1.0
*
* @since 1.0.0
*
* @param Wishlist $wishlist
* @param Wishlist_Item $item
* @return array
*/
public function get_button_template_args( $wishlist, $item ) {
$product = $item->get_product();
$args = [
'product_id' => $product->get_id(),
'class' => [ 'wcboost-wishlist-button' ],
'url' => $item->get_add_url(),
/* translators: %s product name */
'aria-label' => sprintf( __( 'Add %s to the wishlist', 'wcboost-wishlist' ), '“' . $product->get_title() . '”' ),
'label' => Helper::get_button_text(),
'quantity' => 1,
'icon' => Helper::get_wishlist_icon(),
];
// Button classes.
$button_type = wc_get_theme_support( 'wishlist::button_type' );
$button_type = $button_type ? $button_type : get_option( 'wcboost_wishlist_button_type', 'button' );
$args['class'][] = 'wcboost-wishlist-button--' . $button_type;
if ( 'text' != $button_type ) {
$args['class'][] = 'button';
if ( function_exists( 'wp_theme_get_element_class_name' ) ) {
$args['class'][] = \wp_theme_get_element_class_name( 'button' );
}
}
if ( wc_string_to_bool( get_option( 'wcboost_wishlist_enable_ajax_add_to_wishlist', 'yes' ) ) ) {
$args['class'][] = 'wcboost-wishlist-button--ajax';
}
if ( $wishlist->has_item( $item ) ) {
$args['class'][] = 'added';
$args['icon'] = Helper::get_wishlist_icon( true );
switch ( get_option( 'wcboost_wishlist_exists_item_button_behaviour', 'view_wishlist' ) ) {
case 'hide':
$args['class'][] = 'hidden';
break;
case 'remove':
$args['url'] = $item->get_remove_url();
/* translators: %s product name */
$args['aria-label'] = sprintf( __( 'Remove %s from the wishlist', 'wcboost-wishlist' ), '“' . $product->get_title() . '”' );
$args['label'] = Helper::get_button_text( 'remove' );
break;
case 'view_wishlist':
$args['url'] = wc_get_page_permalink( 'wishlist' );
$args['aria-label'] = __( 'Open the wishlist', 'wcboost-wishlist' );
$args['label'] = Helper::get_button_text( 'view' );
break;
}
} elseif ( ! $wishlist->is_default() ) {
$args['url'] = add_query_arg( [ 'wishlist' => $wishlist->get_id() ], $args['url'] );
}
if ( wc_string_to_bool( get_option( 'wcboost_wishlist_allow_adding_variations' ) ) && $product->is_type( 'variable' ) ) {
/** @var \WC_Product_Variable $product */
$variations = $product->get_available_variations( 'objects' );
$data = [];
// Add the parent product to the top of variation data.
$data[] = [
'variation_id' => $product->get_id(),
'add_url' => $item->get_add_url(),
'remove_url' => $item->get_remove_url(),
'added' => $wishlist->has_item( $item ) ? 'yes' : 'no',
'is_parent' => 'yes',
];
foreach ( $variations as $variation ) {
$item = new Wishlist_Item( $variation );
$data[] = [
'variation_id' => $variation->get_id(),
'add_url' => $item->get_add_url(),
'remove_url' => $item->get_remove_url(),
'added' => $wishlist->has_item( $item ) ? 'yes' : 'no',
];
}
$args['variations_data'] = $data;
}
$args = apply_filters( 'wcboost_wishlist_button_template_args', $args, $wishlist, $product );
$args['class'] = implode( ' ', (array) $args['class'] );
// Add a new key "attributes",
// but must keep orginal keys to ensure backwards compatibility.
$args['attributes'] = [
'data-quantity' => $args['quantity'],
'data-product_id' => $args['product_id'],
'aria-label' => $args['aria-label'],
'rel' => 'nofollow',
];
if ( isset( $args['variations_data'] ) ) {
$args['attributes']['data-variations'] = wp_json_encode( $args['variations_data'] );
}
return $args;
}
/**
* Get CSS for custom button style.
*
* @return string
*/
public function get_custom_button_css() {
$default_style = wp_parse_args( get_option( 'wcboost_wishlist_button_style' ), [
'background_color' => '#333333',
'border_color' => '#333333',
'text_color' => '#ffffff',
] );
$hover_style = wp_parse_args( get_option( 'wcboost_wishlist_button_hover_style' ), [
'background_color' => '#111111',
'border_color' => '#111111',
'text_color' => '#ffffff',
] );
$css = ':root {
--wcboost-wishlist-button-color--background:' . $default_style['background_color'] . ';
--wcboost-wishlist-button-color--border:' . $default_style['border_color'] . ';
--wcboost-wishlist-button-color--text:' . $default_style['text_color'] . ';
--wcboost-wishlist-button-hover-color--background:' . $hover_style['background_color'] . ';
--wcboost-wishlist-button-hover-color--border:' . $hover_style['border_color'] . ';
--wcboost-wishlist-button-hover-color--text:' . $hover_style['text_color'] . ';
}';
return $css;
}
/**
* Display wishlist buttons in the widget.
*
* @param \WCBoost\Wishlist\Wishlist $wishlist
* @param array $args
* @return void
*/
public function widget_buttons( $wishlist, $args ) {
if ( ! $args['show_buttons'] ) {
return;
}
printf(
'<a href="%s" class="button">%s</a>',
esc_url( $wishlist->get_public_url() ),
esc_html__( 'View wishlist', 'wcboost-wishlist' )
);
}
/**
* Will set cookies if needed and when possible.
*
* @since 1.1.1
* @deprecated 1.1.2 Moved to the Session class.
*
* @return void
*/
public function maybe_set_cookies() {
_deprecated_function( __METHOD__, '1.1.2', '\WCBoost\Wishlist\Session\maybe_set_cookies' );
Session::instance()->maybe_set_cookies();
}
}
|