- phpList REST API wrapper with subscriber get-or-create + list assignment - WooCommerce Settings tab (5 sections: connection, orders, signup, newsletter) - Test Connection button via admin-post action - Hooks for order completed/cancelled and user_register events - [woolist_newsletter] shortcode with jQuery AJAX, fixed & auto-generated coupons - Responsive front-end form styles and JS with loading/success/error states Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
196 lines
5.5 KiB
PHP
196 lines
5.5 KiB
PHP
<?php
|
|
/**
|
|
* phpList REST API wrapper.
|
|
*
|
|
* @package WooList
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
class WooList_API {
|
|
|
|
/**
|
|
* Retrieve a saved plugin option.
|
|
*
|
|
* @param string $key Option key (without prefix).
|
|
* @param mixed $default Default value.
|
|
* @return mixed
|
|
*/
|
|
public function get_option( string $key, $default = '' ) {
|
|
return get_option( 'woolist_' . $key, $default );
|
|
}
|
|
|
|
/**
|
|
* Build the full phpList REST API URL.
|
|
*
|
|
* All parameters are passed as query-string arguments because the phpList
|
|
* REST API reads them from $_GET regardless of the HTTP method used.
|
|
*
|
|
* @param string $cmd phpList API command.
|
|
* @param array $extra Additional query parameters.
|
|
* @return string|WP_Error Full URL or WP_Error when base URL is missing.
|
|
*/
|
|
public function build_url( string $cmd, array $extra = [] ) {
|
|
$base = $this->get_option( 'phplist_url' );
|
|
$base = rtrim( $base, '/' );
|
|
|
|
if ( empty( $base ) ) {
|
|
return new WP_Error( 'woolist_no_url', __( 'phpList base URL is not configured.', 'woolist-phplist' ) );
|
|
}
|
|
|
|
$params = array_merge(
|
|
[
|
|
'page' => 'call',
|
|
'pi' => 'restapi',
|
|
'login' => $this->get_option( 'phplist_login' ),
|
|
'password' => $this->get_option( 'phplist_password' ),
|
|
'cmd' => $cmd,
|
|
],
|
|
$extra
|
|
);
|
|
|
|
return $base . '/admin/?' . http_build_query( $params );
|
|
}
|
|
|
|
/**
|
|
* Execute an API call and return decoded JSON data.
|
|
*
|
|
* @param string $cmd phpList API command.
|
|
* @param array $extra Additional query parameters.
|
|
* @return array|WP_Error Decoded response data or WP_Error.
|
|
*/
|
|
public function call( string $cmd, array $extra = [] ) {
|
|
$url = $this->build_url( $cmd, $extra );
|
|
|
|
if ( is_wp_error( $url ) ) {
|
|
return $url;
|
|
}
|
|
|
|
$response = wp_remote_post( $url, [ 'timeout' => 15 ] );
|
|
|
|
if ( is_wp_error( $response ) ) {
|
|
error_log( '[WooList] API request failed for cmd=' . $cmd . ': ' . $response->get_error_message() );
|
|
return $response;
|
|
}
|
|
|
|
$code = wp_remote_retrieve_response_code( $response );
|
|
$body = wp_remote_retrieve_body( $response );
|
|
|
|
if ( $code < 200 || $code >= 300 ) {
|
|
error_log( '[WooList] API returned HTTP ' . $code . ' for cmd=' . $cmd );
|
|
return new WP_Error( 'woolist_http_error', 'HTTP error ' . $code );
|
|
}
|
|
|
|
$data = json_decode( $body, true );
|
|
|
|
if ( json_last_error() !== JSON_ERROR_NONE ) {
|
|
error_log( '[WooList] API returned invalid JSON for cmd=' . $cmd . ': ' . $body );
|
|
return new WP_Error( 'woolist_json_error', 'Invalid JSON response from phpList.' );
|
|
}
|
|
|
|
// phpList REST API signals errors via a "status" field.
|
|
if ( isset( $data['status'] ) && strtolower( $data['status'] ) === 'error' ) {
|
|
$message = $data['errormessage'] ?? $data['message'] ?? 'Unknown API error';
|
|
error_log( '[WooList] API error for cmd=' . $cmd . ': ' . $message );
|
|
return new WP_Error( 'woolist_api_error', $message );
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Retrieve a subscriber by email address.
|
|
*
|
|
* @param string $email Subscriber email.
|
|
* @return array|WP_Error
|
|
*/
|
|
public function subscriber_get_by_email( string $email ) {
|
|
return $this->call( 'subscriberGetByEmail', [ 'email' => rawurlencode( $email ) ] );
|
|
}
|
|
|
|
/**
|
|
* Add a new confirmed subscriber.
|
|
*
|
|
* @param string $email Subscriber email.
|
|
* @return array|WP_Error
|
|
*/
|
|
public function subscriber_add( string $email ) {
|
|
return $this->call(
|
|
'subscriberAdd',
|
|
[
|
|
'email' => rawurlencode( $email ),
|
|
'confirmed' => 1,
|
|
'htmlemail' => 1,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Add a subscriber (by ID) to a phpList list.
|
|
*
|
|
* @param int $list_id phpList list ID.
|
|
* @param int $subscriber_id phpList subscriber ID.
|
|
* @return array|WP_Error
|
|
*/
|
|
public function list_subscriber_add( int $list_id, int $subscriber_id ) {
|
|
return $this->call(
|
|
'listSubscriberAdd',
|
|
[
|
|
'listid' => $list_id,
|
|
'subscriberid' => $subscriber_id,
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* High-level helper: subscribe an email to a list.
|
|
*
|
|
* Gets or creates the subscriber, then adds them to the list.
|
|
*
|
|
* @param string $email Subscriber email address.
|
|
* @param int $list_id phpList list ID.
|
|
* @return array{success: bool, subscriber_id: int|null}
|
|
*/
|
|
public function subscribe_email_to_list( string $email, int $list_id ): array {
|
|
// Try to find existing subscriber.
|
|
$subscriber_id = null;
|
|
$existing = $this->subscriber_get_by_email( $email );
|
|
|
|
if ( ! is_wp_error( $existing ) && ! empty( $existing['id'] ) ) {
|
|
$subscriber_id = (int) $existing['id'];
|
|
} else {
|
|
// Create new subscriber.
|
|
$added = $this->subscriber_add( $email );
|
|
if ( is_wp_error( $added ) ) {
|
|
error_log( '[WooList] Could not add subscriber ' . $email . ': ' . $added->get_error_message() );
|
|
return [ 'success' => false, 'subscriber_id' => null ];
|
|
}
|
|
$subscriber_id = isset( $added['id'] ) ? (int) $added['id'] : null;
|
|
}
|
|
|
|
if ( ! $subscriber_id ) {
|
|
error_log( '[WooList] Could not determine subscriber ID for ' . $email );
|
|
return [ 'success' => false, 'subscriber_id' => null ];
|
|
}
|
|
|
|
// Add subscriber to the list.
|
|
$result = $this->list_subscriber_add( $list_id, $subscriber_id );
|
|
|
|
if ( is_wp_error( $result ) ) {
|
|
error_log( '[WooList] Could not add subscriber ' . $subscriber_id . ' to list ' . $list_id . ': ' . $result->get_error_message() );
|
|
return [ 'success' => false, 'subscriber_id' => $subscriber_id ];
|
|
}
|
|
|
|
return [ 'success' => true, 'subscriber_id' => $subscriber_id ];
|
|
}
|
|
|
|
/**
|
|
* Retrieve all lists (used for connection testing).
|
|
*
|
|
* @return array|WP_Error
|
|
*/
|
|
public function lists_get() {
|
|
return $this->call( 'listsGet' );
|
|
}
|
|
}
|