forked from LiveCarta/LiveCartaWP
Changed source root directory
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/**
|
||||
* Asset cache busting utility.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Cmatic_Buster {
|
||||
|
||||
private string $plugin_version;
|
||||
|
||||
private bool $is_debug;
|
||||
|
||||
private static ?self $instance = null;
|
||||
|
||||
public function __construct( string $plugin_version = SPARTAN_MCE_VERSION, ?bool $is_debug = null ) {
|
||||
$this->plugin_version = $plugin_version;
|
||||
$this->is_debug = $is_debug ?? ( defined( 'WP_DEBUG' ) && WP_DEBUG );
|
||||
}
|
||||
|
||||
public function get_version( string $file_path ): string {
|
||||
$version_parts = array( $this->plugin_version );
|
||||
|
||||
if ( file_exists( $file_path ) ) {
|
||||
$version_parts[] = (string) filemtime( $file_path );
|
||||
$version_parts[] = substr( md5_file( $file_path ), 0, 8 );
|
||||
}
|
||||
|
||||
if ( $this->is_debug ) {
|
||||
$version_parts[] = (string) time();
|
||||
}
|
||||
|
||||
return implode( '-', $version_parts );
|
||||
}
|
||||
|
||||
public static function instance(): self {
|
||||
if ( null === self::$instance ) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
<?php
|
||||
/**
|
||||
* Debug file logger.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Cmatic_File_Logger implements Cmatic_Logger_Interface {
|
||||
|
||||
private $is_write_enabled = false;
|
||||
|
||||
private $log_prefix;
|
||||
|
||||
public function __construct( $context = 'ChimpMatic', $enabled = false ) {
|
||||
|
||||
$this->is_write_enabled = (bool) $enabled && ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG );
|
||||
$this->log_prefix = '[' . sanitize_key( $context ) . ']';
|
||||
}
|
||||
|
||||
public function log( string $level, string $message, $context = null ): void {
|
||||
if ( ! $this->is_write_enabled ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$level_str = strtoupper( $level );
|
||||
$log_message = "[ChimpMatic Lite] {$this->log_prefix} [{$level_str}] " . trim( $message );
|
||||
|
||||
if ( ! is_null( $context ) ) {
|
||||
$context_string = $this->format_data( $context );
|
||||
$log_message .= ' | Data: ' . $context_string;
|
||||
}
|
||||
|
||||
error_log( $log_message ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
|
||||
}
|
||||
|
||||
private function format_data( $data ) {
|
||||
if ( is_string( $data ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! is_array( $data ) ) {
|
||||
return wp_json_encode( $data, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
if ( isset( $data['email_address'] ) && isset( $data['status'] ) ) {
|
||||
$summary = array(
|
||||
'email' => $data['email_address'] ?? '',
|
||||
'status' => $data['status'] ?? '',
|
||||
'id' => $data['id'] ?? '',
|
||||
);
|
||||
return wp_json_encode( $summary, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
if ( isset( $data['url'] ) && isset( $data['payload'] ) ) {
|
||||
$merge_fields = $data['payload']['merge_fields'] ?? array();
|
||||
if ( is_object( $merge_fields ) ) {
|
||||
$merge_fields = (array) $merge_fields;
|
||||
}
|
||||
$summary = array(
|
||||
'url' => $data['url'],
|
||||
'email' => $data['payload']['email_address'] ?? '',
|
||||
'status' => $data['payload']['status'] ?? '',
|
||||
'fields' => is_array( $merge_fields ) ? array_keys( $merge_fields ) : array(),
|
||||
);
|
||||
return wp_json_encode( $summary, JSON_UNESCAPED_SLASHES );
|
||||
}
|
||||
|
||||
$json = wp_json_encode( $data, JSON_UNESCAPED_SLASHES );
|
||||
if ( strlen( $json ) <= 1000 ) {
|
||||
return $json;
|
||||
}
|
||||
|
||||
return substr( $json, 0, 1000 ) . '... [truncated]';
|
||||
}
|
||||
|
||||
private function map_numeric_level_to_string( $numeric_level ) {
|
||||
switch ( (int) $numeric_level ) {
|
||||
case 1:
|
||||
return 'INFO';
|
||||
case 2:
|
||||
return 'DEBUG';
|
||||
case 3:
|
||||
return 'WARNING';
|
||||
case 4:
|
||||
return 'ERROR';
|
||||
case 5:
|
||||
return 'CRITICAL';
|
||||
default:
|
||||
return 'UNKNOWN';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
/**
|
||||
* Lite field restrictions and limits.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Cmatic_Lite_Get_Fields {
|
||||
|
||||
public static function cmatic_lite_fields() {
|
||||
return array(
|
||||
'source',
|
||||
'ip_signup',
|
||||
'subscribed',
|
||||
'timestamp_signup',
|
||||
'member_rating',
|
||||
'location',
|
||||
'email_client',
|
||||
'vip',
|
||||
'language',
|
||||
'email_type',
|
||||
'consents_to_one_to_one_messaging',
|
||||
);
|
||||
}
|
||||
|
||||
public static function cmatic_lite_sections() {
|
||||
return array(
|
||||
'tags',
|
||||
'interests',
|
||||
'marketing_permissions',
|
||||
);
|
||||
}
|
||||
|
||||
public static function cmatic_lite_merge_fields() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
/**
|
||||
* URL tracking and link builder.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
final class Cmatic_Pursuit {
|
||||
|
||||
const PLUGIN_ID = 'chimpmatic_lite';
|
||||
const BASE_URLS = array(
|
||||
'docs' => 'https://chimpmatic.com',
|
||||
'pricing' => 'https://chimpmatic.com/pricing',
|
||||
'support' => 'https://chimpmatic.com/contact',
|
||||
'promo' => 'https://chimpmatic.com/almost-there',
|
||||
'home' => 'https://chimpmatic.com',
|
||||
'author' => 'https://renzojohnson.com',
|
||||
);
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
public static function url( string $base_url, string $medium, string $content = '', string $campaign = '' ): string {
|
||||
if ( empty( $base_url ) ) {
|
||||
return '';
|
||||
}
|
||||
$params = array(
|
||||
'utm_source' => self::PLUGIN_ID,
|
||||
'utm_medium' => self::sanitize( $medium ),
|
||||
'utm_campaign' => $campaign ? self::sanitize( $campaign ) : 'plugin_' . gmdate( 'Y' ),
|
||||
);
|
||||
if ( $content ) {
|
||||
$params['utm_content'] = self::sanitize( $content );
|
||||
}
|
||||
return add_query_arg( $params, $base_url );
|
||||
}
|
||||
|
||||
public static function docs( string $slug = '', string $content = '' ): string {
|
||||
$base = self::BASE_URLS['docs'];
|
||||
if ( $slug ) {
|
||||
$base = trailingslashit( $base ) . ltrim( $slug, '/' );
|
||||
}
|
||||
return self::url( $base, 'plugin', $content, 'docs' );
|
||||
}
|
||||
|
||||
public static function upgrade( string $content = '' ): string {
|
||||
return self::url( self::BASE_URLS['pricing'], 'plugin', $content, 'upgrade' );
|
||||
}
|
||||
|
||||
public static function support( string $content = '' ): string {
|
||||
return self::url( self::BASE_URLS['support'], 'plugin', $content, 'support' );
|
||||
}
|
||||
|
||||
public static function promo( string $content = '', int $discount = 40 ): string {
|
||||
$params = array(
|
||||
'u_source' => self::PLUGIN_ID,
|
||||
'u_medium' => 'banner',
|
||||
'u_campaign' => 'promo_' . $discount . 'off',
|
||||
);
|
||||
if ( $content ) {
|
||||
$params['u_content'] = self::sanitize( $content );
|
||||
}
|
||||
return add_query_arg( $params, self::BASE_URLS['promo'] );
|
||||
}
|
||||
|
||||
public static function home( string $content = '' ): string {
|
||||
return self::url( self::BASE_URLS['home'], 'plugin', $content, 'brand' );
|
||||
}
|
||||
|
||||
public static function author( string $content = '' ): string {
|
||||
return self::url( self::BASE_URLS['author'], 'plugin', $content, 'author' );
|
||||
}
|
||||
|
||||
public static function adminbar( string $destination, string $content = '' ): string {
|
||||
$base = self::BASE_URLS[ $destination ] ?? self::BASE_URLS['home'];
|
||||
return self::url( $base, 'adminbar', $content, $destination );
|
||||
}
|
||||
|
||||
private static function sanitize( string $value ): string {
|
||||
return preg_replace( '/[^a-z0-9_]/', '', str_replace( array( ' ', '-' ), '_', strtolower( trim( $value ) ) ) );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,251 @@
|
||||
<?php
|
||||
/**
|
||||
* Remote data fetcher with caching.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class CMatic_Remote_Fetcher {
|
||||
|
||||
private $config;
|
||||
|
||||
private $defaults = array(
|
||||
'url' => '',
|
||||
'cache_key' => 'cmatic_remote_data',
|
||||
'cache_duration' => DAY_IN_SECONDS,
|
||||
'retry_interval' => 600, // 10 minutes in seconds
|
||||
'max_retries' => 3,
|
||||
'retry_count_key' => 'cmatic_retry_count',
|
||||
'cron_hook' => 'cmatic_fetch_retry',
|
||||
'timeout' => 15,
|
||||
'fallback_data' => array(),
|
||||
'parser_callback' => null,
|
||||
);
|
||||
|
||||
public function __construct( $config = array() ) {
|
||||
$this->config = wp_parse_args( $config, $this->defaults );
|
||||
add_action( $this->config['cron_hook'], array( $this, 'cron_retry_fetch' ) );
|
||||
}
|
||||
|
||||
public function get_data() {
|
||||
$cached_data = $this->get_cache();
|
||||
|
||||
if ( false !== $cached_data ) {
|
||||
return $cached_data;
|
||||
}
|
||||
|
||||
$fresh_data = $this->fetch_fresh_data();
|
||||
|
||||
if ( false !== $fresh_data ) {
|
||||
$this->set_cache( $fresh_data );
|
||||
$this->clear_retry_schedule();
|
||||
return $fresh_data;
|
||||
}
|
||||
|
||||
$this->schedule_retry();
|
||||
return $this->get_fallback_data();
|
||||
}
|
||||
|
||||
public function get_cache() {
|
||||
return get_transient( $this->config['cache_key'] );
|
||||
}
|
||||
|
||||
public function set_cache( $data ) {
|
||||
return set_transient(
|
||||
$this->config['cache_key'],
|
||||
$data,
|
||||
$this->config['cache_duration']
|
||||
);
|
||||
}
|
||||
|
||||
public function clear_cache() {
|
||||
return delete_transient( $this->config['cache_key'] );
|
||||
}
|
||||
|
||||
private function fetch_fresh_data() {
|
||||
if ( empty( $this->config['url'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response = wp_remote_get(
|
||||
$this->config['url'],
|
||||
array(
|
||||
'timeout' => $this->config['timeout'],
|
||||
'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url(),
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$response_code = wp_remote_retrieve_response_code( $response );
|
||||
if ( 200 !== $response_code ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$body = wp_remote_retrieve_body( $response );
|
||||
if ( empty( $body ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->parse_content( $body );
|
||||
}
|
||||
|
||||
/** Parse fetched content. */
|
||||
private function parse_content( $content ) {
|
||||
if ( is_callable( $this->config['parser_callback'] ) ) {
|
||||
return call_user_func( $this->config['parser_callback'], $content );
|
||||
}
|
||||
|
||||
$json_data = $this->parse_pricing_json( $content );
|
||||
if ( false !== $json_data ) {
|
||||
return $json_data;
|
||||
}
|
||||
|
||||
return $this->parse_pricing_html( $content );
|
||||
}
|
||||
|
||||
private function parse_pricing_json( $content ) {
|
||||
$json = json_decode( $content, true );
|
||||
|
||||
if ( null === $json || ! is_array( $json ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! isset( $json['regular_price'] ) || ! isset( $json['discount_percent'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$pricing_data = array(
|
||||
'regular_price' => (int) $json['regular_price'],
|
||||
'sale_price' => isset( $json['sale_price'] ) ? (float) $json['sale_price'] : null,
|
||||
'discount_percent' => (int) $json['discount_percent'],
|
||||
'coupon_code' => isset( $json['coupon_code'] ) ? sanitize_text_field( $json['coupon_code'] ) : null,
|
||||
'last_updated' => current_time( 'mysql' ),
|
||||
);
|
||||
|
||||
if ( null === $pricing_data['sale_price'] ) {
|
||||
$discount_amount = $pricing_data['regular_price'] * ( $pricing_data['discount_percent'] / 100 );
|
||||
$pricing_data['sale_price'] = $pricing_data['regular_price'] - $discount_amount;
|
||||
}
|
||||
|
||||
if ( null === $pricing_data['coupon_code'] ) {
|
||||
$pricing_data['coupon_code'] = 'NOW' . $pricing_data['discount_percent'];
|
||||
}
|
||||
|
||||
$pricing_data['formatted'] = sprintf(
|
||||
'$%d → $%s • Save %d%%',
|
||||
$pricing_data['regular_price'],
|
||||
number_format( $pricing_data['sale_price'], 2 ),
|
||||
$pricing_data['discount_percent']
|
||||
);
|
||||
|
||||
return $pricing_data;
|
||||
}
|
||||
|
||||
private function parse_pricing_html( $html ) {
|
||||
$pricing_data = array(
|
||||
'regular_price' => null,
|
||||
'sale_price' => null,
|
||||
'discount_percent' => null,
|
||||
'coupon_code' => null,
|
||||
'formatted' => null,
|
||||
'last_updated' => current_time( 'mysql' ),
|
||||
);
|
||||
|
||||
if ( preg_match( '/Single\s+Site[^$]*\$(\d+)\/year/i', $html, $matches ) ) {
|
||||
$pricing_data['regular_price'] = (int) $matches[1];
|
||||
}
|
||||
|
||||
if ( preg_match( '/(\d+)%\s+Off/i', $html, $matches ) ) {
|
||||
$pricing_data['discount_percent'] = (int) $matches[1];
|
||||
}
|
||||
|
||||
if ( preg_match( '/coupon\s+code\s+["\']([A-Z0-9]+)["\']/i', $html, $matches ) ) {
|
||||
$pricing_data['coupon_code'] = sanitize_text_field( $matches[1] );
|
||||
}
|
||||
|
||||
if ( $pricing_data['regular_price'] && $pricing_data['discount_percent'] ) {
|
||||
$discount_amount = $pricing_data['regular_price'] * ( $pricing_data['discount_percent'] / 100 );
|
||||
$pricing_data['sale_price'] = $pricing_data['regular_price'] - $discount_amount;
|
||||
}
|
||||
|
||||
if ( $pricing_data['regular_price'] && $pricing_data['sale_price'] && $pricing_data['discount_percent'] ) {
|
||||
$pricing_data['formatted'] = sprintf(
|
||||
'$%d → $%s • Save %d%%',
|
||||
$pricing_data['regular_price'],
|
||||
number_format( $pricing_data['sale_price'], 2 ),
|
||||
$pricing_data['discount_percent']
|
||||
);
|
||||
}
|
||||
|
||||
if ( null === $pricing_data['regular_price'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $pricing_data;
|
||||
}
|
||||
|
||||
private function get_fallback_data() {
|
||||
if ( ! empty( $this->config['fallback_data'] ) ) {
|
||||
return $this->config['fallback_data'];
|
||||
}
|
||||
|
||||
return array(
|
||||
'regular_price' => 39,
|
||||
'sale_price' => 29.25,
|
||||
'discount_percent' => 25,
|
||||
'coupon_code' => 'NOW25',
|
||||
'formatted' => '$39 → $29.25 • Save 25%',
|
||||
'last_updated' => null,
|
||||
);
|
||||
}
|
||||
|
||||
private function schedule_retry() {
|
||||
$retry_count = (int) get_option( $this->config['retry_count_key'], 0 );
|
||||
|
||||
if ( $retry_count >= $this->config['max_retries'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( $this->config['retry_count_key'], $retry_count + 1 );
|
||||
|
||||
if ( ! wp_next_scheduled( $this->config['cron_hook'] ) ) {
|
||||
wp_schedule_single_event(
|
||||
time() + $this->config['retry_interval'],
|
||||
$this->config['cron_hook']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function cron_retry_fetch() {
|
||||
$fresh_data = $this->fetch_fresh_data();
|
||||
|
||||
if ( false !== $fresh_data ) {
|
||||
$this->set_cache( $fresh_data );
|
||||
$this->clear_retry_schedule();
|
||||
} else {
|
||||
$this->schedule_retry();
|
||||
}
|
||||
}
|
||||
|
||||
private function clear_retry_schedule() {
|
||||
$timestamp = wp_next_scheduled( $this->config['cron_hook'] );
|
||||
if ( $timestamp ) {
|
||||
wp_unschedule_event( $timestamp, $this->config['cron_hook'] );
|
||||
}
|
||||
|
||||
delete_option( $this->config['retry_count_key'] );
|
||||
}
|
||||
|
||||
public function clear_all() {
|
||||
$this->clear_cache();
|
||||
$this->clear_retry_schedule();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
/**
|
||||
* Utility functions for ChimpMatic.
|
||||
*
|
||||
* @package contact-form-7-mailchimp-extension
|
||||
* @author renzo.johnson@gmail.com
|
||||
* @copyright 2014-2026 https://renzojohnson.com
|
||||
* @license GPL-3.0+
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
final class Cmatic_Utils {
|
||||
|
||||
const CMATIC_FB_A = 'chimpmatic';
|
||||
|
||||
public static function validate_bool( $value ): bool {
|
||||
if ( is_bool( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ( is_int( $value ) || is_float( $value ) ) {
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
if ( is_string( $value ) ) {
|
||||
$v = strtolower( trim( $value ) );
|
||||
|
||||
if ( '' === $v ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_numeric( $v ) ) {
|
||||
return 0.0 !== (float) $v;
|
||||
}
|
||||
|
||||
static $true = array( 'true', 'on', 'yes', 'y', '1' );
|
||||
static $false = array( 'false', 'off', 'no', 'n', '0' );
|
||||
|
||||
if ( in_array( $v, $true, true ) ) {
|
||||
return true;
|
||||
}
|
||||
if ( in_array( $v, $false, true ) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static function get_first( $array, $default = '' ) {
|
||||
if ( is_array( $array ) && ! empty( $array ) ) {
|
||||
return reset( $array );
|
||||
}
|
||||
return $default;
|
||||
}
|
||||
|
||||
public static function get_newest_form_id(): ?int {
|
||||
$forms = get_posts(
|
||||
array(
|
||||
'post_type' => 'wpcf7_contact_form',
|
||||
'posts_per_page' => 1,
|
||||
'orderby' => 'ID',
|
||||
'order' => 'DESC',
|
||||
'post_status' => 'publish',
|
||||
'fields' => 'ids',
|
||||
)
|
||||
);
|
||||
|
||||
return ! empty( $forms ) ? (int) $forms[0] : null;
|
||||
}
|
||||
|
||||
public static function get_days_since( int $timestamp ): int {
|
||||
$datetime_now = new \DateTime( 'now' );
|
||||
$datetime_from = new \DateTime( '@' . $timestamp );
|
||||
|
||||
$diff = date_diff( $datetime_now, $datetime_from );
|
||||
|
||||
return (int) $diff->format( '%a' );
|
||||
}
|
||||
|
||||
private function __construct() {}
|
||||
|
||||
private function __clone() {}
|
||||
|
||||
public function __wakeup() {
|
||||
throw new \Exception( 'Cannot unserialize singleton' );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user