Files
WooList/woolist-phplist/includes/class-woolist-shortcode.php

202 lines
6.0 KiB
PHP
Raw Normal View History

<?php
/**
* [woolist_newsletter] shortcode and AJAX handler.
*
* @package WooList
*/
defined( 'ABSPATH' ) || exit;
class WooList_Shortcode {
/** @var WooList_API */
private WooList_API $api;
public function __construct( WooList_API $api ) {
$this->api = $api;
add_shortcode( 'woolist_newsletter', [ $this, 'render_shortcode' ] );
// Register AJAX handlers for logged-in and guest visitors.
add_action( 'wp_ajax_woolist_newsletter_submit', [ $this, 'handle_ajax' ] );
add_action( 'wp_ajax_nopriv_woolist_newsletter_submit', [ $this, 'handle_ajax' ] );
// Enqueue front-end assets.
add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_assets' ] );
}
/**
* Enqueue CSS and JS for the newsletter form.
*/
public function enqueue_assets(): void {
wp_enqueue_style(
'woolist-public',
WOOLIST_URL . 'assets/css/woolist-public.css',
[],
WOOLIST_VERSION
);
wp_enqueue_script(
'woolist-public',
WOOLIST_URL . 'assets/js/woolist-public.js',
[ 'jquery' ],
WOOLIST_VERSION,
true
);
wp_localize_script(
'woolist-public',
'woolist',
[
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'woolist_newsletter_nonce' ),
'i18n' => [
'subscribing' => __( 'Subscribing…', 'woolist-phplist' ),
'subscribe' => __( 'Subscribe', 'woolist-phplist' ),
'error' => __( 'Something went wrong. Please try again.', 'woolist-phplist' ),
],
]
);
}
/**
* Render the [woolist_newsletter] shortcode.
*
* @return string HTML output.
*/
public function render_shortcode(): string {
if ( get_option( 'woolist_sync_newsletter' ) !== 'yes' ) {
if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'manage_options' ) ) {
return '<!-- WooList: newsletter shortcode is disabled in settings -->';
}
return '';
}
ob_start();
?>
<div class="woolist-newsletter-wrap">
<form id="woolist-newsletter-form" novalidate>
<div class="woolist-form-row">
<input
type="email"
name="woolist_email"
class="woolist-email-input"
placeholder="<?php esc_attr_e( 'Your email address', 'woolist-phplist' ); ?>"
required
/>
<button type="submit" class="woolist-submit-btn">
<?php esc_html_e( 'Subscribe', 'woolist-phplist' ); ?>
</button>
</div>
</form>
<div class="woolist-response" style="display:none;" aria-live="polite"></div>
</div>
<?php
return ob_get_clean();
}
/**
* Handle AJAX newsletter subscription submission.
*/
public function handle_ajax(): void {
// 1. Verify nonce.
if ( ! check_ajax_referer( 'woolist_newsletter_nonce', 'nonce', false ) ) {
wp_send_json_error( [ 'message' => __( 'Security check failed. Please refresh and try again.', 'woolist-phplist' ) ], 403 );
}
// 2. Validate email.
$email = isset( $_POST['woolist_email'] ) ? sanitize_email( wp_unslash( $_POST['woolist_email'] ) ) : '';
if ( ! is_email( $email ) ) {
wp_send_json_error( [ 'message' => __( 'Please enter a valid email address.', 'woolist-phplist' ) ], 400 );
}
// 3. Get list ID.
$list_id = (int) get_option( 'woolist_newsletter_list_id', 0 );
if ( $list_id < 1 ) {
wp_send_json_error( [ 'message' => __( 'Newsletter is not configured. Please contact the site administrator.', 'woolist-phplist' ) ], 500 );
}
// 4. Subscribe email to phpList.
$result = $this->api->subscribe_email_to_list( $email, $list_id );
if ( ! $result['success'] ) {
wp_send_json_error( [ 'message' => __( 'Could not subscribe your email. Please try again later.', 'woolist-phplist' ) ], 500 );
}
// 5. Handle coupon generation.
$coupon_code = '';
$thankyou_msg = get_option( 'woolist_newsletter_thankyou', __( 'Thank you for subscribing!', 'woolist-phplist' ) );
if ( get_option( 'woolist_newsletter_enable_coupon' ) === 'yes' ) {
$coupon_mode = get_option( 'woolist_coupon_mode', 'fixed' );
if ( $coupon_mode === 'fixed' ) {
$coupon_code = sanitize_text_field( get_option( 'woolist_coupon_fixed_code', '' ) );
} else {
$coupon_code = $this->generate_coupon( $email );
}
}
// Replace {coupon} placeholder in the thank-you message.
$thankyou_msg = str_replace( '{coupon}', esc_html( $coupon_code ), $thankyou_msg );
wp_send_json_success(
[
'message' => wp_kses_post( $thankyou_msg ),
'coupon' => $coupon_code,
]
);
}
/**
* Generate a unique WooCommerce percentage coupon for the subscriber.
*
* @param string $email Subscriber email.
* @return string Generated coupon code, or empty string on failure.
*/
private function generate_coupon( string $email ): string {
if ( ! class_exists( 'WC_Coupon' ) ) {
error_log( '[WooList] WC_Coupon class not available; cannot generate coupon.' );
return '';
}
$discount_pct = (int) get_option( 'woolist_coupon_discount_pct', 10 );
$expiry_days = (int) get_option( 'woolist_coupon_expiry_days', 30 );
$coupon_code = 'WOOLIST-' . strtoupper( substr( md5( $email . time() ), 0, 8 ) );
$expiry_date = '';
if ( $expiry_days > 0 ) {
$expiry_date = gmdate( 'Y-m-d', strtotime( '+' . $expiry_days . ' days' ) );
}
$post_id = wp_insert_post(
[
'post_title' => $coupon_code,
'post_name' => $coupon_code,
'post_status' => 'publish',
'post_type' => 'shop_coupon',
'post_excerpt' => 'WooList newsletter signup coupon for ' . $email,
],
true
);
if ( is_wp_error( $post_id ) ) {
error_log( '[WooList] Failed to create coupon post: ' . $post_id->get_error_message() );
return '';
}
// Set coupon meta via WC functions.
update_post_meta( $post_id, 'discount_type', 'percent' );
update_post_meta( $post_id, 'coupon_amount', (string) $discount_pct );
update_post_meta( $post_id, 'usage_limit', '1' );
update_post_meta( $post_id, 'usage_limit_per_user', '1' );
update_post_meta( $post_id, 'individual_use', 'yes' );
update_post_meta( $post_id, 'customer_email', [ $email ] );
if ( $expiry_date ) {
update_post_meta( $post_id, 'date_expires', strtotime( $expiry_date ) );
}
return $coupon_code;
}
}