File "class-mailchimp-woocommerce-tower.php"

Full Path: /home/vantageo/public_html/cache/.wp-cli/wp-content/plugins/mailchimp-for-woocommerce_bk/includes/api/class-mailchimp-woocommerce-tower.php
File size: 22.88 KB
MIME-type: text/x-php
Charset: utf-8

<?php

class MailChimp_WooCommerce_Tower extends Mailchimp_Woocommerce_Job {

	protected $store_id;
	protected $with_shop_sales = true;
	protected $with_log_file   = null;
	protected $with_log_search = null;

	/**
	 * OrderCreatedHook constructor.
	 *
	 * @param $store_id
	 */
	public function __construct( $store_id ) {
		$this->store_id = $store_id;
	}

	public function withoutShopSales() {
		$this->with_shop_sales = false;
		return $this;
	}

	public function withShopSales() {
		$this->with_shop_sales = true;
		return $this;
	}

	public function withLogFile( $file ) {
		$this->with_log_file = $file;
		return $this;
	}

	public function withLogSearch( $search ) {
		$this->with_log_search = $search;
		return $this;
	}

	/**
	 * @return array
	 * @throws MailChimp_WooCommerce_Error
	 * @throws MailChimp_WooCommerce_ServerError
	 */
	public function handle() {
		return $this->getData();
	}

	/**
	 * @return array
	 * @throws MailChimp_WooCommerce_Error
	 * @throws MailChimp_WooCommerce_RateLimitError
	 * @throws MailChimp_WooCommerce_ServerError
	 */
	public function getData() {
		$product_count = $customer_count = $order_count = $mc_product_count = $mc_customer_count = $mc_order_count = 0;

		$api           = mailchimp_get_api();
		$store_id      = mailchimp_get_store_id();
		$authenticated = mailchimp_is_configured();
		$list_id       = mailchimp_get_list_id();
		$url           = get_option( 'siteurl' );
		$options       = (array) get_option( 'mailchimp-woocommerce' );
		$last_sync_at  = mailchimp_get_data('sync.last_loop_at');

		try {
			$product_count  = mailchimp_get_product_count();
			$customer_count = 0;
			$order_count    = mailchimp_get_order_count();
			$plan           = $plan_name = 'Woo';
			$store_active   = true;
		} catch ( Throwable $e ) {
			$store_active = false;
			$plan         = null;
		}

		$has_mailchimp_script    = false;
		$has_old_integration     = false;
		$duplicate_store_problem = false;
		$store_attached          = false;
		$syncing_mc              = false;
		$list_is_valid           = false;
		$account_info            = array();
		$shop                    = null;
		$akamai_block            = false;

		if ( $authenticated ) {
			try {
				$account_info = $api->getProfile();
			} catch ( Exception $e ) {
				$account_info = array();
				if ( $e->getCode() === 503 ) {
					$akamai_block = true;
				}
			}
			if ( is_array( $account_info ) ) {
				// don't need these
				unset( $account_info['_links'] );
			}
			$stores      = $api->stores();
			$compare_url = $this->baseDomain( $url );
			$list_name   = $list_id ? $api->getList( $list_id )['name'] : null;

			if ( is_array( $stores ) && ! empty( $stores ) ) {
				foreach ( $stores as $mc_store ) {
					/** @var MailChimp_WooCommerce_Store $mc_store */
					$store_url          = $this->baseDomain( $mc_store->getDomain() );
					$public_key_matched = $mc_store->getId() === $store_id;
					// make sure the current store in context is inside the Mailchimp array of stores.
					if ( $public_key_matched ) {
						$shop                 = $mc_store;
						$syncing_mc           = (bool) mailchimp_get_data('sync.syncing' );
						$store_attached       = true;
						$list_is_valid        = $mc_store->getListId() === $list_id;
						$has_mailchimp_script = (bool) $mc_store->getConnectedSiteScriptFragment();

						// if the store is not syncing locally, but is still marked as syncing on Mailchimp,
						// clean it up by toggling to false.
						if ( !$syncing_mc && $mc_store->isSyncing() ) {
							if ( $api->flagStoreSync($store_id, false) ) {
								mailchimp_log('tower', 'Toggled Mailchimp store to not syncing historical data');
							}
						}
					}
					if ( $store_url === $compare_url ) {
						if ( ! $public_key_matched && $mc_store->getPlatform() === 'Woocommerce' ) {
							$duplicate_store_problem = true;
						}
					}
				}
			}

			try {
				if ( $store_attached ) {
					$mc_product_count  = $api->getProductCount( $store_id );
					$mc_customer_count = $api->getCustomerCount( $store_id );
					$mc_order_count    = $api->getOrderCount( $store_id );
				}
			} catch ( Throwable $e ) {
				if ( $e->getCode() === 503 ) {
					$akamai_block = true;
				}
			}

			$automations  = array();
			$merge_fields = array();
			$journeys     = array();
			try {
				foreach ( $api->getAutomations( $list_id ) as $automation ) {
					$created       = new DateTime( $automation['create_time'] );
					$started       = new DateTime( $automation['start_time'] );
					$automations[] = array(
						'created_at' => $created->format( 'Y-m-d H:i:s' ),
						'start_at'   => $started->format( 'Y-m-d H:i:s' ),
						'status'     => $automation['status'],
						'name'       => $automation['settings']['title'],
						'type'       => $automation['trigger_settings']['workflow_title'],
						'stats'      => $automation['report_summary'],
					);
				}
				$merge_fields   = $api->mergeFields( $list_id );
				$merge_fields   = $merge_fields['merge_fields'];
				$journeys       = $api->getJourneys();
			} catch ( Throwable $e ) {
				if ( $e->getCode() === 503 ) {
					$akamai_block = true;
				}
			}
		}

		$time = new DateTime( 'now' );

		return array(
			'store'         => (object) array(
				'public_key'            => $store_id,
				'domain'                => $url,
				'secure_url'            => $url,
				'user'                  => (object) array(
					'email' => isset( $options['admin_email'] ) ? $options['admin_email'] : null,
				),
				'average_monthly_sales' => $this->getShopSales(),
				'address'               => (object) array(
					'street'  => isset( $options['store_street'] ) && $options['store_street'] ? $options['store_street'] : '',
					'city'    => isset( $options['store_street'] ) && $options['store_street'] ? $options['store_street'] : '',
					'state'   => isset( $options['store_state'] ) && $options['store_state'] ? $options['store_state'] : '',
					'country' => isset( $options['store_country'] ) && $options['store_country'] ? $options['store_country'] : '',
					'zip'     => isset( $options['store_postal_code'] ) && $options['store_postal_code'] ? $options['store_postal_code'] : '',
					'phone'   => isset( $options['store_phone'] ) && $options['store_phone'] ? $options['store_phone'] : '',
				),
				'metrics'               => array_values(
					array(
						'shopify_hooks'             => (object) array(
							'key'   => 'shopify_hooks',
							'value' => $this->hasWebhookInstalled(),
						),
						'shop.products'             => (object) array(
							'key'   => 'shop.products',
							'value' => $product_count,
						),
						'shop.customers'            => (object) array(
							'key'   => 'shop.customers',
							'value' => $customer_count,
						),
						'shop.orders'               => (object) array(
							'key'   => 'shop.orders',
							'value' => $order_count,
						),
						'mc.products'               => (object) array(
							'key'   => 'mc.products',
							'value' => $mc_product_count,
						),
						'mc.orders'                 => (object) array(
							'key'   => 'mc.orders',
							'value' => $mc_order_count,
						),
						'mc.has_chimpstatic'        => (object) array(
							'key'   => 'mc.has_chimpstatic',
							'value' => true,
						),
						'mc.has_duplicate_store'    => (object) array(
							'key'   => 'mc.has_duplicate_store',
							'value' => $duplicate_store_problem,
						),
						'mc.store_attached'         => (object) array(
							'key'   => 'mc.store_attached',
							'value' => $store_attached,
						),
						'mc.is_syncing'             => (object) array(
							'key'   => 'mc.is_syncing',
							'value' => $syncing_mc,
						),
						'mailchimp_api_connected'   => (object) array(
							'key'   => 'mailchimp_api_connected',
							'value' => (bool) $account_info,
						),
						'mc_list_id'                => (object) array(
							'key'   => 'mc_list_id',
							'value' => (bool) $list_id && $list_is_valid,
						),
						'mc_list_valid'             => (object) array(
							'key'   => 'mc_list_valid',
							'value' => $list_is_valid,
						),
						'mc.has_legacy_integration' => (object) array(
							'key'   => 'mc.has_legacy_integration',
							'value' => $has_old_integration,
						),
						'admin.updated_at'          => (object) array(
							'key'   => 'admin.updated_at',
							'value' => $time->format( 'Y-m-d H:i:s' ),
						),
						'product_sync_started'      => (object) array(
							'key'   => 'product_sync_started',
							'value' => get_option( 'mailchimp-woocommerce-sync.products.started_at' ),
						),
						'product_sync_completed'    => (object) array(
							'key'   => 'product_sync_completed',
							'value' => get_option( 'mailchimp-woocommerce-sync.products.completed_at' ),
						),
						'customer_sync_started'     => (object) array(
							'key'   => 'customer_sync_started',
							'value' => get_option( 'mailchimp-woocommerce-sync.customers.started_at' ),
						),
						'customer_sync_completed'   => (object) array(
							'key'   => 'customer_sync_completed',
							'value' => get_option( 'mailchimp-woocommerce-sync.customers.completed_at' ),
						),
						'order_sync_started'        => (object) array(
							'key'   => 'order_sync_started',
							'value' => get_option( 'mailchimp-woocommerce-sync.orders.started_at' ),
						),
						'order_sync_completed'      => (object) array(
							'key'   => 'order_sync_completed',
							'value' => get_option( 'mailchimp-woocommerce-sync.orders.completed_at' ),
						),
						'last_loop_at'              => (object) array(
							'key'   => 'last_loop_at',
							'value' => $last_sync_at,
						),
					)
				),
				'meta'                  => $this->getMeta(),
			),
			'meta'          => array(
				'timestamp'  => $time->format( 'Y-m-d H:i:s' ),
				'platform'   => array(
					'active'              => $store_active,
					'plan'                => $plan,
					'store_name'          => get_option( 'blogname' ),
					'domain'              => $url,
					'secure_url'          => $url,
					'user_email'          => isset( $options['admin_email'] ) ? $options['admin_email'] : null,
					'is_syncing'          => $syncing_mc,
					'sync_started_at'     => get_option( 'mailchimp-woocommerce-sync.started_at' ),
					'sync_completed_at'   => get_option( 'mailchimp-woocommerce-sync.completed_at' ),
					'subscribed_to_hooks' => true,
					'uses_custom_rules'   => false,
					'wp_cron_enabled'     => $this->hasWPCronEnabled(),
					'ecomm_stats'         => array(
						'products'  => $product_count,
						'customers' => $customer_count,
						'orders'    => $order_count,
					),
					'shop'                => array(
						'phone' => isset( $options['store_phone'] ) && $options['store_phone'] ? $options['store_phone'] : '',
					),
				),
				'mailchimp'  => array(
					'shop'                    => $shop ? $shop->toArray() : false,
					'chimpstatic_installed'   => $has_mailchimp_script,
					'force_disconnect'        => false,
					'duplicate_store_problem' => $duplicate_store_problem,
					'has_old_integration'     => $has_old_integration,
					'store_attached'          => $store_attached,
					'akamai_block'            => $akamai_block,
					'ecomm_stats'             => array(
						'products'  => $mc_product_count,
						'customers' => $mc_customer_count,
						'orders'    => $mc_order_count,
					),
					'list'                    => array(
						'id'            => $list_id,
						'name'          => isset( $list_name ) ? $list_name : null,
						'double_opt_in' => $this->hasDoubleOptInEnabled(),
						'valid'         => $list_is_valid,
					),
					'account_info'            => $account_info,
					'automations'             => isset( $automations ) ? $automations : null,
					'journeys'                => isset( $journeys ) ? $journeys : null,
					'merge_fields'            => isset( $merge_fields ) ? (object) $merge_fields : null,
				),
				'merge_tags' => array(),
			),
			'logs'          => static::logs( $this->with_log_file, $this->with_log_search ),
			'system_report' => $this->getSystemReport(),
		);
	}

	/**
	 * @return bool
	 */
	public function hasDoubleOptInEnabled() {
		try {
			return mailchimp_list_has_double_optin();
		} catch ( Exception $e ) {
			return false;
		}
	}

	/**
	 * @return bool
	 */
	protected function hasWebhookInstalled() {
		if ( ! mailchimp_is_configured() || ! mailchimp_get_data( 'webhook.token' ) ) {
			return false;
		}
		try {
			return (bool) mailchimp_get_api()->hasWebhook( mailchimp_get_list_id(), mailchimp_get_webhook_url() );
		} catch ( Throwable $e ) {
			mailchimp_log( 'tower', 'could not get webhook URL', array( 'message' => $e->getMessage() ) );
			return false;
		}
	}
	/**
	 * @param $domain
	 * @return string|string[]
	 */
	protected function baseDomain( $domain ) {
		return str_replace(
			array( 'http://', 'https://', 'www.' ),
			'',
			rtrim( strtolower( trim( $domain ) ), '/' )
		);
	}

	/**
	 * @param null $file
	 * @param null $search
	 *
	 * @return array
	 */
	public function logs( $file = null, $search = null ) {
		try {
			$logs = new MailChimp_WooCommerce_Logs();
			$logs->limit( 200 );
			$logs->withView( ! is_null( $file ) ? $file : $this->with_log_file );
			$logs->searching( ! is_null( $search ) ? $search : $this->with_log_search );
			return $logs->handle();
		} catch ( Exception $e ) {
			mailchimp_error( 'tower', $e->getMessage() );
			return array();
		}
	}

	public function getShopSales() {
		try {
			global $woocommerce, $wpdb;
			include_once $woocommerce->plugin_path() . '/includes/admin/reports/class-wc-admin-report.php';

			// WooCommerce Admin Report
			$wc_report = new WC_Admin_Report();

			// Set date parameters for the current month
			$start_date            = strtotime( date( 'Y-m', current_time( 'timestamp' ) ) . '-01 midnight' );
			$end_date              = strtotime( '+1month', $start_date ) - 86400;
			$wc_report->start_date = $start_date;
			$wc_report->end_date   = $end_date;

			// Avoid max join size error
			$wpdb->query( 'SET SQL_BIG_SELECTS=1' );

			// Get data for current month sold products
			$sold_products = $wc_report->get_order_report_data(
				array(
					'data'         => array(
						'_product_id'    => array(
							'type'            => 'order_item_meta',
							'order_item_type' => 'line_item',
							'function'        => '',
							'name'            => 'product_id',
						),
						'_qty'           => array(
							'type'            => 'order_item_meta',
							'order_item_type' => 'line_item',
							'function'        => 'SUM',
							'name'            => 'quantity',
						),
						'_line_subtotal' => array(
							'type'            => 'order_item_meta',
							'order_item_type' => 'line_item',
							'function'        => 'SUM',
							'name'            => 'gross',
						),
						'_line_total'    => array(
							'type'            => 'order_item_meta',
							'order_item_type' => 'line_item',
							'function'        => 'SUM',
							'name'            => 'gross_after_discount',
						),
					),
					'query_type'   => 'get_results',
					'group_by'     => 'product_id',
					'where_meta'   => '',
					'order_by'     => 'quantity DESC',
					'order_types'  => wc_get_order_types( 'order_count' ),
					'filter_range' => true,
					'order_status' => array( 'completed', 'complete' ),
				)
			);
			$total         = 0;
			foreach ( $sold_products as $product ) {
				$total += $product->gross;
			}
			return $total;
		} catch ( Throwable $e ) {
			mailchimp_log( 'tower', $e->getMessage() );
			return 0;
		}
	}

	public function getSystemReport() {
		global $wp_version;

		$actions = $this->getLastActions();
		$theme   = wp_get_theme();

		return array(
			array(
				'key'   => 'PhpVersion',
				'value' => phpversion(),
			),
			array(
				'key'   => 'Memory Limit',
				'value' => ini_get( 'memory_limit' ),
			),
			array(
				'key'   => 'WP CRON Enabled',
				'value' => $this->hasWPCronEnabled(),
			),
			array(
				'key'   => 'WP CLI Enabled',
				'value' => defined('WP_CLI') && WP_CLI,
			),
			array(
				'key'   => 'Curl Enabled',
				'value' => function_exists( 'curl_init' ),
			),
			array(
				'key'   => 'Curl Version',
				'value' => $this->getCurlVersion(),
			),
			array(
				'key'   => 'Wordpress Version',
				'value' => $wp_version,
			),
			array(
				'key'   => 'WooCommerce Version',
				'value' => defined( 'WC_VERSION' ) ? WC_VERSION : null,
			),
			array(
				'key'   => 'Action Scheduler Version',
				'value' => $this->getActionSchedulerVersion(),
			),
			array(
				'key'   => 'Theme Name',
				'value' => esc_html( $theme->get( 'Name' ) ),
			),
			array(
				'key'   => 'Theme URL',
				'value' => esc_html( $theme->get( 'ThemeURI' ) ),
			),
			array(
				'key'   => 'Outbound IP Address',
				'value' => mailchimp_get_outbound_ip(),
			),
			array(
				'key'   => 'Active Plugins',
				'value' => $this->getActivePlugins(),
			),
			array(
				'key'   => 'Actions',
				'value' => $actions,
			),
		);
	}

	/**
	 * @return bool
	 */
	public function hasWPCronEnabled() {
		return ! defined( 'DISABLE_WP_CRON' ) ||
			( defined( 'DISABLE_WP_CRON' ) && ! DISABLE_WP_CRON );
	}

	/**
	 * @return mixed|null
	 */
	public function getCurlVersion() {
		$version = function_exists( 'curl_version' ) ? curl_version() : null;
		return is_array( $version ) ? $version['version'] : null;
	}

	/**
	 * @return string
	 */
	public function getActionSchedulerVersion() {

		// do a query to make sure this exists.
		if ( !class_exists('ActionScheduler_Versions') ) {
			return 'none';
		}
		if ( ! ActionScheduler::is_initialized( __FUNCTION__ ) ) {
			return 'Not Initialized In REST API';
		}
		return (string) ActionScheduler_Versions::instance()->latest_version();
	}

	public function getActivePlugins() {
		$active_plugins = '<ul>';
		$plugins        = wp_get_active_and_valid_plugins();
		foreach ( $plugins as $plugin ) {
			$plugin_data     = get_plugin_data( $plugin );
			$active_plugins .= '<li><span class="font-bold">' . $plugin_data['Name'] . '</span>: ' . $plugin_data['Version'] . '</li>';
		}
		$active_plugins .= '</ul>';
		return print_r( $active_plugins, true );
	}

	public function getLastActions() {
		global $wpdb;
		if ( ! class_exists( 'ActionScheduler' ) || ! ActionScheduler::is_initialized( 'store' ) ) {
			return array();
		}
		if ( ! ActionScheduler::store() ) {
			return array();
		}
		$oldest_and_newest = '<ul>';

		foreach ( array_keys( ActionScheduler::store()->get_status_labels() ) as $status ) {
			if ( 'in-progress' === $status ) {
				continue;
			}
			$newest             = $this->get_action_status_date( $status, 'newest' );
			$status             = ucfirst( $status );
			$oldest_and_newest .= "<li><span class='font-bold'>{$status}</span>: {$newest}</li>";
		}

		$oldest_and_newest .= '</ul>';

		return $oldest_and_newest;
	}

	/**
	 * @return array|object|null
	 */
	public function getMeta() {
		global $wpdb;
		$results  = $wpdb->get_results( "SELECT * FROM $wpdb->options WHERE option_name LIKE 'mailchimp-woocommerce-%'" );
		$response = array();
		$date     = new DateTime( 'now' );
		foreach ( $results as $result ) {
			$response[] = array(
				'key'        => str_replace( 'mailchimp-woocommerce-', '', $result->option_name ),
				'value'      => $result->option_value,
				'updated_at' => $date->format( 'Y-m-d H:i:s' ),
			);
		}
		return $response;
	}

	/**
	 * This is where we need to hook into tower from the store owner's support request.
	 * We can enable and disable this feature which will generate an API token specific to
	 * tower which will be used for authentication coming from our server to this specific store.
	 *
	 * @param bool $enable
	 *
	 * @return array|mixed|object|null
	 */
	public function toggle( $enable = true ) {
		$command        = (bool) $enable ? 'enable' : 'disable';
		$store_id       = mailchimp_get_store_id();
		$key            = mailchimp_get_api_key();
		$list_id        = mailchimp_get_list_id();
		$is_connected   = mailchimp_is_configured();
		$post_url       = "https://tower.vextras.com/admin-api/woocommerce/{$command}/{$store_id}";
		$plugin_options = (array) get_option( 'mailchimp-woocommerce' );
		$akamai_block   = false;

		if ( (bool) $enable ) {
			mailchimp_set_data( 'tower.token', $support_token = wp_generate_password() );
		} else {
			$support_token = mailchimp_get_data( 'tower.token' );
			delete_option( 'mailchimp-woocommerce-tower.support_token' );
		}

		if ( $enable ) {
			$data = array(
				'list_id'       => $list_id,
				'php_version'   => phpversion(),
				'curl_enabled'  => function_exists( 'curl_init' ),
				'is_connected'  => $is_connected,
				'sync_complete' => mailchimp_is_done_syncing(),
				'rest_url'      => MailChimp_WooCommerce_Rest_Api::url( '' ),
			);
			if ( $is_connected ) {
				try {
					$api          = mailchimp_get_api();
					$account_info = $api->getProfile();
					$list_info    = ! empty( $list_id ) ? $api->getList( $list_id ) : null;
					$mc_store     = $api->getStore( $store_id );
					$syncing_mc   = $mc_store ? $mc_store->isSyncing() : false;
					if ( is_array( $list_info ) ) {
						unset( $list_info['_links'] );
					}
					if ( is_array( $account_info ) ) {
						unset( $account_info['_links'] );
					}
					$job = new MailChimp_WooCommerce_Fix_Duplicate_Store( $store_id, false, false );
					$job->handle();
					$dup_store = (bool) $job->hasDuplicateStoreProblem();
				} catch ( Throwable $e ) {
					$list_info    = false;
					$syncing_mc   = false;
					$account_info = false;
					if ( $e->getCode() === 503 ) {
						$akamai_block = true;
					}
					if ( ! isset( $dup_store ) ) {
						$dup_store = false;
					}
				}
				$data['list_info']                 = $list_info;
				$data['is_syncing']                = $syncing_mc;
				$data['account_info']              = $account_info;
				$data['duplicate_mailchimp_store'] = $dup_store;
				$data['akamai_block']              = $akamai_block;
			}
		} else {
			$data = array();
		}

		try {
			$payload  = array(
				'headers' => array(
					'Content-type'     => 'application/json',
					'Accept'           => 'application/json',
					'X-Store-Platform' => 'woocommerce',
					'X-List-Id'        => $list_id,
					'X-Store-Key'      => base64_encode( "{$store_id}:{$key}" ),
				),
				'body'    => json_encode(
					array(
						'name'          => ! empty( $plugin_options ) && isset( $plugin_options['store_name'] ) ? $plugin_options['store_name'] : get_option( 'blogname' ),
						'support_token' => $support_token,
						'domain'        => get_option( 'siteurl' ),
						'data'          => $data,
					)
				),
				'timeout' => 30,
			);
			$response = wp_remote_post( $post_url, $payload );
			return json_decode( $response['body'] );
		} catch ( Throwable $e ) {
			return null;
		}
	}

	/**
	 * @param $status
	 * @param string $date_type
	 *
	 * @return string
	 */
	protected function get_action_status_date( $status, $date_type = 'oldest' ) {
		$order  = 'oldest' === $date_type ? 'ASC' : 'DESC';
		$store  = ActionScheduler::store();
		$action = $store->query_actions(
			array(
				'claimed'  => false,
				'status'   => $status,
				'per_page' => 1,
				'order'    => $order,
			)
		);
		if ( ! empty( $action ) ) {
			$date_object = $store->get_date( $action[0] );
			$action_date = $date_object->format( 'Y-m-d H:i:s O' );
		} else {
			$action_date = '&ndash;';
		}
		return $action_date;
	}
}