Multichannel Marketing - Core Library (#35099)
* Create channel interface and campaign value class * Create MarketingChannels class * Register MarketingChannels class in DI container * Use the new MarketingChannels class to get the installed marketing extensions' data * Use DI container to access InstalledExtensions class * Add InstalledExtensions to the $provides array * Hint that campaign cost should also indicate the currency * Initialize the channels array * Add unit tests for MarketingCampaign * Add unit tests for MarketingChannels * Add Price class to represent a price with currency * Use Price class for marketing campaign's cost * Define a constant to indicate the MCM classes exist This constant will be checked by third-party extensions before utilizing any of the classes/interfaces defined for this feature. * Create MarketingSpecs class to include WC.com API calls * Remove WC.com API calls from Marketing class And replace them with calls from MarketingSpecs class. * Use the const from MarketingSpecs * Fix MarketingChannels unit tests * Add missing settings URL to the channel data Co-authored-by: Nima <nima.karimi@automattic.com>
This commit is contained in:
parent
c55c91d7e0
commit
6acd69e404
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
|
||||||
use Automattic\WooCommerce\Internal\Admin\Marketing;
|
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||||
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
|
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
|
||||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
|
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
|
||||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
|
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
|
||||||
|
@ -2469,5 +2469,5 @@ function wc_update_700_remove_download_log_fk() {
|
||||||
* Remove the transient data for recommended marketing extensions.
|
* Remove the transient data for recommended marketing extensions.
|
||||||
*/
|
*/
|
||||||
function wc_update_700_remove_recommended_marketing_plugins_transient() {
|
function wc_update_700_remove_recommended_marketing_plugins_transient() {
|
||||||
delete_transient( Marketing::RECOMMENDED_PLUGINS_TRANSIENT );
|
delete_transient( MarketingSpecs::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
|
|
||||||
namespace Automattic\WooCommerce\Admin\API;
|
namespace Automattic\WooCommerce\Admin\API;
|
||||||
|
|
||||||
use Automattic\WooCommerce\Internal\Admin\Marketing as MarketingFeature;
|
|
||||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
use Automattic\WooCommerce\Admin\PluginsHelper;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
|
||||||
|
@ -103,9 +103,16 @@ class Marketing extends \WC_REST_Data_Controller {
|
||||||
* @return \WP_Error|\WP_REST_Response
|
* @return \WP_Error|\WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public function get_recommended_plugins( $request ) {
|
public function get_recommended_plugins( $request ) {
|
||||||
|
/**
|
||||||
|
* MarketingSpecs class.
|
||||||
|
*
|
||||||
|
* @var MarketingSpecs $marketing_specs
|
||||||
|
*/
|
||||||
|
$marketing_specs = wc_get_container()->get( MarketingSpecs::class );
|
||||||
|
|
||||||
// Default to marketing category (if no category set).
|
// Default to marketing category (if no category set).
|
||||||
$category = ( ! empty( $request->get_param( 'category' ) ) ) ? $request->get_param( 'category' ) : 'marketing';
|
$category = ( ! empty( $request->get_param( 'category' ) ) ) ? $request->get_param( 'category' ) : 'marketing';
|
||||||
$all_plugins = MarketingFeature::get_instance()->get_recommended_plugins();
|
$all_plugins = $marketing_specs->get_recommended_plugins();
|
||||||
$valid_plugins = [];
|
$valid_plugins = [];
|
||||||
$per_page = $request->get_param( 'per_page' );
|
$per_page = $request->get_param( 'per_page' );
|
||||||
|
|
||||||
|
@ -130,7 +137,14 @@ class Marketing extends \WC_REST_Data_Controller {
|
||||||
* @return \WP_Error|\WP_REST_Response
|
* @return \WP_Error|\WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public function get_knowledge_base_posts( $request ) {
|
public function get_knowledge_base_posts( $request ) {
|
||||||
|
/**
|
||||||
|
* MarketingSpecs class.
|
||||||
|
*
|
||||||
|
* @var MarketingSpecs $marketing_specs
|
||||||
|
*/
|
||||||
|
$marketing_specs = wc_get_container()->get( MarketingSpecs::class );
|
||||||
|
|
||||||
$category = $request->get_param( 'category' );
|
$category = $request->get_param( 'category' );
|
||||||
return rest_ensure_response( MarketingFeature::get_instance()->get_knowledge_base_posts( $category ) );
|
return rest_ensure_response( $marketing_specs->get_knowledge_base_posts( $category ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -125,7 +125,14 @@ class MarketingOverview extends \WC_REST_Data_Controller {
|
||||||
* @return \WP_Error|\WP_REST_Response
|
* @return \WP_Error|\WP_REST_Response
|
||||||
*/
|
*/
|
||||||
public function get_installed_plugins( $request ) {
|
public function get_installed_plugins( $request ) {
|
||||||
return rest_ensure_response( InstalledExtensions::get_data() );
|
/**
|
||||||
|
* InstalledExtensions
|
||||||
|
*
|
||||||
|
* @var InstalledExtensions $installed_extensions
|
||||||
|
*/
|
||||||
|
$installed_extensions = wc_get_container()->get( InstalledExtensions::class );
|
||||||
|
|
||||||
|
return rest_ensure_response( $installed_extensions->get_data() );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,598 +5,46 @@
|
||||||
|
|
||||||
namespace Automattic\WooCommerce\Admin\Marketing;
|
namespace Automattic\WooCommerce\Admin\Marketing;
|
||||||
|
|
||||||
use Automattic\WooCommerce\Admin\PluginsHelper;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installed Marketing Extensions class.
|
* Installed Marketing Extensions class.
|
||||||
*/
|
*/
|
||||||
class InstalledExtensions {
|
class InstalledExtensions {
|
||||||
|
/**
|
||||||
|
* MarketingChannels repository
|
||||||
|
*
|
||||||
|
* @var MarketingChannels
|
||||||
|
*/
|
||||||
|
protected $marketing_channels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class initialization, invoked by the DI container.
|
||||||
|
*
|
||||||
|
* @param MarketingChannels $marketing_channels The MarketingChannels repository.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final public function init( MarketingChannels $marketing_channels ) {
|
||||||
|
$this->marketing_channels = $marketing_channels;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets an array of plugin data for the "Installed marketing extensions" card.
|
* Gets an array of plugin data for the "Installed marketing extensions" card.
|
||||||
*
|
|
||||||
* Valid extensions statuses are: installed, activated, configured
|
|
||||||
*/
|
*/
|
||||||
public static function get_data() {
|
public function get_data(): array {
|
||||||
$data = [];
|
return array_map(
|
||||||
|
function ( MarketingChannelInterface $channel ) {
|
||||||
$automatewoo = self::get_automatewoo_extension_data();
|
return [
|
||||||
$aw_referral = self::get_aw_referral_extension_data();
|
'slug' => $channel->get_slug(),
|
||||||
$aw_birthdays = self::get_aw_birthdays_extension_data();
|
'status' => $channel->is_setup_completed() ? 'configured' : 'activated',
|
||||||
$mailchimp = self::get_mailchimp_extension_data();
|
'settingsUrl' => $channel->get_setup_url(),
|
||||||
$facebook = self::get_facebook_extension_data();
|
'name' => $channel->get_name(),
|
||||||
$pinterest = self::get_pinterest_extension_data();
|
'description' => $channel->get_description(),
|
||||||
$google = self::get_google_extension_data();
|
'product_listings_status' => $channel->get_product_listings_status(),
|
||||||
$amazon_ebay = self::get_amazon_ebay_extension_data();
|
'errors_no' => $channel->get_errors_no(),
|
||||||
$mailpoet = self::get_mailpoet_extension_data();
|
'icon' => $channel->get_icon_url(),
|
||||||
$creative_mail = self::get_creative_mail_extension_data();
|
];
|
||||||
$tiktok = self::get_tiktok_extension_data();
|
},
|
||||||
$jetpack_crm = self::get_jetpack_crm_extension_data();
|
$this->marketing_channels->get_registered_channels()
|
||||||
$zapier = self::get_zapier_extension_data();
|
);
|
||||||
$salesforce = self::get_salesforce_extension_data();
|
|
||||||
$vimeo = self::get_vimeo_extension_data();
|
|
||||||
$trustpilot = self::get_trustpilot_extension_data();
|
|
||||||
|
|
||||||
if ( $automatewoo ) {
|
|
||||||
$data[] = $automatewoo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $aw_referral ) {
|
|
||||||
$data[] = $aw_referral;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $aw_birthdays ) {
|
|
||||||
$data[] = $aw_birthdays;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $mailchimp ) {
|
|
||||||
$data[] = $mailchimp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $facebook ) {
|
|
||||||
$data[] = $facebook;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $pinterest ) {
|
|
||||||
$data[] = $pinterest;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $google ) {
|
|
||||||
$data[] = $google;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $amazon_ebay ) {
|
|
||||||
$data[] = $amazon_ebay;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $mailpoet ) {
|
|
||||||
$data[] = $mailpoet;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $creative_mail ) {
|
|
||||||
$data[] = $creative_mail;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $tiktok ) {
|
|
||||||
$data[] = $tiktok;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $jetpack_crm ) {
|
|
||||||
$data[] = $jetpack_crm;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $zapier ) {
|
|
||||||
$data[] = $zapier;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $salesforce ) {
|
|
||||||
$data[] = $salesforce;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $vimeo ) {
|
|
||||||
$data[] = $vimeo;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( $trustpilot ) {
|
|
||||||
$data[] = $trustpilot;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Get allowed plugins.
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public static function get_allowed_plugins() {
|
|
||||||
return [
|
|
||||||
'automatewoo',
|
|
||||||
'mailchimp-for-woocommerce',
|
|
||||||
'creative-mail-by-constant-contact',
|
|
||||||
'facebook-for-woocommerce',
|
|
||||||
'pinterest-for-woocommerce',
|
|
||||||
'google-listings-and-ads',
|
|
||||||
'hubspot-for-woocommerce',
|
|
||||||
'woocommerce-amazon-ebay-integration',
|
|
||||||
'mailpoet',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get AutomateWoo extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_automatewoo_extension_data() {
|
|
||||||
$slug = 'automatewoo';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/automatewoo.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && function_exists( 'AW' ) ) {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=automatewoo-settings' );
|
|
||||||
$data['docsUrl'] = 'https://automatewoo.com/docs/';
|
|
||||||
$data['status'] = 'configured'; // Currently no configuration step.
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get AutomateWoo Refer a Friend extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_aw_referral_extension_data() {
|
|
||||||
$slug = 'automatewoo-referrals';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/automatewoo.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
$data['docsUrl'] = 'https://automatewoo.com/docs/refer-a-friend/';
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
if ( function_exists( 'AW_Referrals' ) ) {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=automatewoo-settings&tab=referrals' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get AutomateWoo Birthdays extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_aw_birthdays_extension_data() {
|
|
||||||
$slug = 'automatewoo-birthdays';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/automatewoo.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
$data['docsUrl'] = 'https://automatewoo.com/docs/getting-started-with-birthdays/';
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
if ( function_exists( 'AW_Birthdays' ) ) {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=automatewoo-settings&tab=birthdays' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get MailChimp extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_mailchimp_extension_data() {
|
|
||||||
$slug = 'mailchimp-for-woocommerce';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/mailchimp.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && function_exists( 'mailchimp_is_configured' ) ) {
|
|
||||||
$data['docsUrl'] = 'https://mailchimp.com/help/connect-or-disconnect-mailchimp-for-woocommerce/';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=mailchimp-woocommerce' );
|
|
||||||
|
|
||||||
if ( mailchimp_is_configured() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Facebook extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_facebook_extension_data() {
|
|
||||||
$slug = 'facebook-for-woocommerce';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/facebook-icon.svg';
|
|
||||||
|
|
||||||
if ( $data['status'] === 'activated' && function_exists( 'facebook_for_woocommerce' ) ) {
|
|
||||||
$integration = facebook_for_woocommerce()->get_integration();
|
|
||||||
|
|
||||||
if ( $integration->is_configured() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['settingsUrl'] = facebook_for_woocommerce()->get_settings_url();
|
|
||||||
$data['docsUrl'] = facebook_for_woocommerce()->get_documentation_url();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Pinterest extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_pinterest_extension_data() {
|
|
||||||
$slug = 'pinterest-for-woocommerce';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/pinterest.svg';
|
|
||||||
|
|
||||||
// TODO: Finalise docs url.
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/pinterest-for-woocommerce/?utm_medium=product';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( 'Pinterest_For_Woocommerce' ) ) {
|
|
||||||
$pinterest_onboarding_completed = Pinterest_For_Woocommerce()::is_setup_complete();
|
|
||||||
if ( $pinterest_onboarding_completed ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=wc-admin&path=/pinterest/settings' );
|
|
||||||
} else {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=wc-admin&path=/pinterest/landing' );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Google extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_google_extension_data() {
|
|
||||||
$slug = 'google-listings-and-ads';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/google.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && function_exists( 'woogle_get_container' ) && class_exists( '\Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService' ) ) {
|
|
||||||
|
|
||||||
$merchant_center = woogle_get_container()->get( \Automattic\WooCommerce\GoogleListingsAndAds\MerchantCenter\MerchantCenterService::class );
|
|
||||||
|
|
||||||
if ( $merchant_center->is_setup_complete() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=wc-admin&path=/google/settings' );
|
|
||||||
} else {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=wc-admin&path=/google/start' );
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/google-listings-and-ads/?utm_medium=product';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Amazon / Ebay extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_amazon_ebay_extension_data() {
|
|
||||||
$slug = 'woocommerce-amazon-ebay-integration';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/amazon-ebay.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( '\CodistoConnect' ) ) {
|
|
||||||
|
|
||||||
$codisto_merchantid = get_option( 'codisto_merchantid' );
|
|
||||||
|
|
||||||
// Use same check as codisto admin tabs.
|
|
||||||
if ( is_numeric( $codisto_merchantid ) ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=codisto-settings' );
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/multichannel-for-woocommerce-google-amazon-ebay-walmart-integration/?utm_medium=product';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get MailPoet extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_mailpoet_extension_data() {
|
|
||||||
$slug = 'mailpoet';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/mailpoet.svg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( '\MailPoet\API\API' ) ) {
|
|
||||||
$mailpoet_api = \MailPoet\API\API::MP( 'v1' );
|
|
||||||
|
|
||||||
if ( ! method_exists( $mailpoet_api, 'isSetupComplete' ) || $mailpoet_api->isSetupComplete() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=mailpoet-settings' );
|
|
||||||
} else {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=mailpoet-newsletters' );
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['docsUrl'] = 'https://kb.mailpoet.com/';
|
|
||||||
$data['supportUrl'] = 'https://www.mailpoet.com/support/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Creative Mail for WooCommerce extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_creative_mail_extension_data() {
|
|
||||||
$slug = 'creative-mail-by-constant-contact';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/creative-mail-by-constant-contact.png';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( '\CreativeMail\Helpers\OptionsHelper' ) ) {
|
|
||||||
if ( ! method_exists( '\CreativeMail\Helpers\OptionsHelper', 'get_instance_id' ) || \CreativeMail\Helpers\OptionsHelper::get_instance_id() !== null ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=creativemail_settings' );
|
|
||||||
} else {
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=creativemail' );
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['docsUrl'] = 'https://app.creativemail.com/kb/help/WooCommerce';
|
|
||||||
$data['supportUrl'] = 'https://app.creativemail.com/kb/help/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get TikTok for WooCommerce extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_tiktok_extension_data() {
|
|
||||||
$slug = 'tiktok-for-business';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/tiktok.jpg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
if ( false !== get_option( 'tt4b_access_token' ) ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=tiktok' );
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/tiktok-for-woocommerce/';
|
|
||||||
$data['supportUrl'] = 'https://ads.tiktok.com/athena/user-feedback/?identify_key=6a1e079024806640c5e1e695d13db80949525168a052299b4970f9c99cb5ac78';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Jetpack CRM for WooCommerce extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_jetpack_crm_extension_data() {
|
|
||||||
$slug = 'zero-bs-crm';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/jetpack-crm.png';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=zerobscrm-plugin-settings' );
|
|
||||||
$data['docsUrl'] = 'https://kb.jetpackcrm.com/';
|
|
||||||
$data['supportUrl'] = 'https://kb.jetpackcrm.com/crm-support/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get WooCommerce Zapier extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_zapier_extension_data() {
|
|
||||||
$slug = 'woocommerce-zapier';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/zapier.png';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=wc-settings&tab=wc_zapier' );
|
|
||||||
$data['docsUrl'] = 'https://docs.om4.io/woocommerce-zapier/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Salesforce extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_salesforce_extension_data() {
|
|
||||||
$slug = 'integration-with-salesforce';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/salesforce.jpg';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( '\Integration_With_Salesforce_Admin' ) ) {
|
|
||||||
if ( ! method_exists( '\Integration_With_Salesforce_Admin', 'get_connection_status' ) || \Integration_With_Salesforce_Admin::get_connection_status() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=integration-with-salesforce' );
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/salesforce-integration/';
|
|
||||||
$data['supportUrl'] = 'https://wpswings.com/submit-query/';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Vimeo extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_vimeo_extension_data() {
|
|
||||||
$slug = 'vimeo';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/vimeo.png';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] && class_exists( '\Tribe\Vimeo_WP\Vimeo\Vimeo_Auth' ) ) {
|
|
||||||
if ( method_exists( '\Tribe\Vimeo_WP\Vimeo\Vimeo_Auth', 'has_access_token' ) ) {
|
|
||||||
$vimeo_auth = new \Tribe\Vimeo_WP\Vimeo\Vimeo_Auth();
|
|
||||||
if ( $vimeo_auth->has_access_token() ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
}
|
|
||||||
|
|
||||||
$data['settingsUrl'] = admin_url( 'options-general.php?page=vimeo_settings' );
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/vimeo/';
|
|
||||||
$data['supportUrl'] = 'https://vimeo.com/help/contact';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get Trustpilot extension data.
|
|
||||||
*
|
|
||||||
* @return array|bool
|
|
||||||
*/
|
|
||||||
protected static function get_trustpilot_extension_data() {
|
|
||||||
$slug = 'trustpilot-reviews';
|
|
||||||
|
|
||||||
if ( ! PluginsHelper::is_plugin_installed( $slug ) ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$data = self::get_extension_base_data( $slug );
|
|
||||||
$data['icon'] = WC_ADMIN_IMAGES_FOLDER_URL . '/marketing/trustpilot.png';
|
|
||||||
|
|
||||||
if ( 'activated' === $data['status'] ) {
|
|
||||||
$data['status'] = 'configured';
|
|
||||||
$data['settingsUrl'] = admin_url( 'admin.php?page=woocommerce-trustpilot-settings-page' );
|
|
||||||
$data['docsUrl'] = 'https://woocommerce.com/document/trustpilot-reviews/';
|
|
||||||
$data['supportUrl'] = 'https://support.trustpilot.com/hc/en-us/requests/new';
|
|
||||||
}
|
|
||||||
|
|
||||||
return $data;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get an array of basic data for a given extension.
|
|
||||||
*
|
|
||||||
* @param string $slug Plugin slug.
|
|
||||||
*
|
|
||||||
* @return array|false
|
|
||||||
*/
|
|
||||||
protected static function get_extension_base_data( $slug ) {
|
|
||||||
$status = PluginsHelper::is_plugin_active( $slug ) ? 'activated' : 'installed';
|
|
||||||
$plugin_data = PluginsHelper::get_plugin_data( $slug );
|
|
||||||
|
|
||||||
if ( ! $plugin_data ) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
|
||||||
'slug' => $slug,
|
|
||||||
'status' => $status,
|
|
||||||
'name' => $plugin_data['Name'],
|
|
||||||
'description' => html_entity_decode( wp_trim_words( $plugin_data['Description'], 20 ) ),
|
|
||||||
'supportUrl' => 'https://woocommerce.com/my-account/create-a-ticket/?utm_medium=product',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,110 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Represents a marketing/ads campaign for marketing channels.
|
||||||
|
*
|
||||||
|
* Marketing channels (implementing MarketingChannelInterface) can use this class to map their campaign data and present it to WooCommerce core.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\Marketing;
|
||||||
|
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MarketingCampaign class
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
class MarketingCampaign implements JsonSerializable {
|
||||||
|
/**
|
||||||
|
* The unique identifier.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Title of the marketing campaign.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $title;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The URL to the channel's campaign management page.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $manage_url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cost of the marketing campaign with the currency.
|
||||||
|
*
|
||||||
|
* @var Price
|
||||||
|
*/
|
||||||
|
protected $cost;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MarketingCampaign constructor.
|
||||||
|
*
|
||||||
|
* @param string $id The marketing campaign's unique identifier.
|
||||||
|
* @param string $title The title of the marketing campaign.
|
||||||
|
* @param string $manage_url The URL to the channel's campaign management page.
|
||||||
|
* @param Price|null $cost The cost of the marketing campaign with the currency.
|
||||||
|
*/
|
||||||
|
public function __construct( string $id, string $title, string $manage_url, Price $cost = null ) {
|
||||||
|
$this->id = $id;
|
||||||
|
$this->title = $title;
|
||||||
|
$this->manage_url = $manage_url;
|
||||||
|
$this->cost = $cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the marketing campaign's unique identifier.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_id(): string {
|
||||||
|
return $this->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the title of the marketing campaign.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_title(): string {
|
||||||
|
return $this->title;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to manage the marketing campaign.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_manage_url(): string {
|
||||||
|
return $this->manage_url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the cost of the marketing campaign with the currency.
|
||||||
|
*
|
||||||
|
* @return Price|null
|
||||||
|
*/
|
||||||
|
public function get_cost(): ?Price {
|
||||||
|
return $this->cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the marketing campaign data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() {
|
||||||
|
return [
|
||||||
|
'id' => $this->get_id(),
|
||||||
|
'title' => $this->get_title(),
|
||||||
|
'manage_url' => $this->get_manage_url(),
|
||||||
|
'cost' => $this->get_cost(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,82 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Represents a marketing channel for the multichannel-marketing feature.
|
||||||
|
*
|
||||||
|
* This interface will be implemented by third-party extensions to register themselves as marketing channels.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\Marketing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MarketingChannelInterface interface
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
interface MarketingChannelInterface {
|
||||||
|
public const PRODUCT_LISTINGS_NOT_APPLICABLE = 'not-applicable';
|
||||||
|
public const PRODUCT_LISTINGS_SYNC_IN_PROGRESS = 'sync-in-progress';
|
||||||
|
public const PRODUCT_LISTINGS_SYNCED = 'synced';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the unique identifier string for the marketing channel extension, also known as the plugin slug.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_slug(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the marketing channel.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_name(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the description of the marketing channel.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_description(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the path to the channel icon.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_icon_url(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the setup status of the marketing channel.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function is_setup_completed(): bool;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the URL to the settings page, or the link to complete the setup/onboarding if the channel has not been set up yet.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_setup_url(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the status of the marketing channel's product listings.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_product_listings_status(): string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the number of channel issues/errors (e.g. account-related errors, product synchronization issues, etc.).
|
||||||
|
*
|
||||||
|
* @return int The number of issues to resolve, or 0 if there are no issues with the channel.
|
||||||
|
*/
|
||||||
|
public function get_errors_no(): int;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of the channel's marketing campaigns.
|
||||||
|
*
|
||||||
|
* @return MarketingCampaign[]
|
||||||
|
*/
|
||||||
|
public function get_campaigns(): array;
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Handles the registration of marketing channels and acts as their repository.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\Marketing;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MarketingChannels repository class
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
class MarketingChannels {
|
||||||
|
/**
|
||||||
|
* The registered marketing channels.
|
||||||
|
*
|
||||||
|
* @var MarketingChannelInterface[]
|
||||||
|
*/
|
||||||
|
private $registered_channels = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of plugin slugs for allowed marketing channels.
|
||||||
|
*
|
||||||
|
* @var string[]
|
||||||
|
*/
|
||||||
|
private $allowed_channels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MarketingSpecs repository
|
||||||
|
*
|
||||||
|
* @var MarketingSpecs
|
||||||
|
*/
|
||||||
|
protected $marketing_specs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class initialization, invoked by the DI container.
|
||||||
|
*
|
||||||
|
* @param MarketingSpecs $marketing_specs The MarketingSpecs class.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
final public function init( MarketingSpecs $marketing_specs ) {
|
||||||
|
$this->marketing_specs = $marketing_specs;
|
||||||
|
$this->allowed_channels = $this->get_allowed_channels();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a marketing channel.
|
||||||
|
*
|
||||||
|
* Note that only a predetermined list of third party extensions can be registered as a marketing channel.
|
||||||
|
*
|
||||||
|
* @param MarketingChannelInterface $channel The marketing channel to register.
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @see MarketingChannels::is_channel_allowed() Checks if the marketing channel is allowed to be registered or not.
|
||||||
|
*/
|
||||||
|
public function register( MarketingChannelInterface $channel ): void {
|
||||||
|
if ( ! $this->is_channel_allowed( $channel ) ) {
|
||||||
|
// Silently log an error and bail.
|
||||||
|
wc_get_logger()->error( sprintf( 'Marketing channel %s (%s) cannot be registered!', $channel->get_name(), $channel->get_slug() ) );
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->registered_channels[ $channel->get_slug() ] = $channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of all registered marketing channels.
|
||||||
|
*
|
||||||
|
* @return MarketingChannelInterface[]
|
||||||
|
*/
|
||||||
|
public function get_registered_channels(): array {
|
||||||
|
/**
|
||||||
|
* Filter the list of registered marketing channels.
|
||||||
|
*
|
||||||
|
* Note that only a predetermined list of third party extensions can be registered as a marketing channel.
|
||||||
|
* Any new plugins added to this array will be cross-checked with that list, which is obtained from WooCommerce.com API.
|
||||||
|
*
|
||||||
|
* @param MarketingChannelInterface[] $channels Array of registered marketing channels.
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
$channels = apply_filters( 'woocommerce_marketing_channels', $this->registered_channels );
|
||||||
|
|
||||||
|
// Only return allowed channels.
|
||||||
|
$allowed_channels = array_filter(
|
||||||
|
$channels,
|
||||||
|
function ( MarketingChannelInterface $channel ) {
|
||||||
|
if ( ! $this->is_channel_allowed( $channel ) ) {
|
||||||
|
// Silently log an error and bail.
|
||||||
|
wc_get_logger()->error( sprintf( 'Marketing channel %s (%s) cannot be registered!', $channel->get_name(), $channel->get_slug() ) );
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return array_values( $allowed_channels );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an array of plugin slugs for the marketing channels that are allowed to be registered.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function get_allowed_channels(): array {
|
||||||
|
$recommended_channels = $this->marketing_specs->get_recommended_plugins();
|
||||||
|
if ( empty( $recommended_channels ) ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_column( $recommended_channels, 'product', 'product' );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines whether the given marketing channel is allowed to be registered.
|
||||||
|
*
|
||||||
|
* @param MarketingChannelInterface $channel The marketing channel object.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function is_channel_allowed( MarketingChannelInterface $channel ): bool {
|
||||||
|
return isset( $this->allowed_channels[ $channel->get_slug() ] );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Represents a price with a currency.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Admin\Marketing;
|
||||||
|
|
||||||
|
use JsonSerializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Price class
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
class Price implements JsonSerializable {
|
||||||
|
/**
|
||||||
|
* The price.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $value;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The currency of the price.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
protected $currency;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Price constructor.
|
||||||
|
*
|
||||||
|
* @param string $value The value of the price.
|
||||||
|
* @param string $currency The currency of the price.
|
||||||
|
*/
|
||||||
|
public function __construct( string $value, string $currency ) {
|
||||||
|
$this->value = $value;
|
||||||
|
$this->currency = $currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get value of the price.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_value(): string {
|
||||||
|
return $this->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the currency of the price.
|
||||||
|
*
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_currency(): string {
|
||||||
|
return $this->currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Serialize the price data.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function jsonSerialize() {
|
||||||
|
return [
|
||||||
|
'value' => $this->get_value(),
|
||||||
|
'currency' => $this->get_currency(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\COTMig
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\DownloadPermissionsAdjusterServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\DownloadPermissionsAdjusterServiceProvider;
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\AssignDefaultCategoryServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\AssignDefaultCategoryServiceProvider;
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\FeaturesServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\FeaturesServiceProvider;
|
||||||
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\MarketingServiceProvider;
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrdersControllersServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrdersControllersServiceProvider;
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrderAdminServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrderAdminServiceProvider;
|
||||||
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrderMetaBoxServiceProvider;
|
use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\OrderMetaBoxServiceProvider;
|
||||||
|
@ -65,6 +66,7 @@ final class Container {
|
||||||
OrderMetaBoxServiceProvider::class,
|
OrderMetaBoxServiceProvider::class,
|
||||||
OrderAdminServiceProvider::class,
|
OrderAdminServiceProvider::class,
|
||||||
FeaturesServiceProvider::class,
|
FeaturesServiceProvider::class,
|
||||||
|
MarketingServiceProvider::class,
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -7,7 +7,6 @@ namespace Automattic\WooCommerce\Internal\Admin;
|
||||||
|
|
||||||
use Automattic\WooCommerce\Admin\Features\Features;
|
use Automattic\WooCommerce\Admin\Features\Features;
|
||||||
use Automattic\WooCommerce\Admin\Marketing\InstalledExtensions;
|
use Automattic\WooCommerce\Admin\Marketing\InstalledExtensions;
|
||||||
use Automattic\WooCommerce\Internal\Admin\Loader;
|
|
||||||
use Automattic\WooCommerce\Admin\PageController;
|
use Automattic\WooCommerce\Admin\PageController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -17,20 +16,6 @@ class Marketing {
|
||||||
|
|
||||||
use CouponsMovedTrait;
|
use CouponsMovedTrait;
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of recommended plugins transient.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const RECOMMENDED_PLUGINS_TRANSIENT = 'wc_marketing_recommended_plugins';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of knowledge base post transient.
|
|
||||||
*
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
const KNOWLEDGE_BASE_TRANSIENT = 'wc_marketing_knowledge_base';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class instance.
|
* Class instance.
|
||||||
*
|
*
|
||||||
|
@ -180,124 +165,15 @@ class Marketing {
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
$settings['marketing']['installedExtensions'] = InstalledExtensions::get_data();
|
/**
|
||||||
|
* InstalledExtensions helper class.
|
||||||
|
*
|
||||||
|
* @var InstalledExtensions $installed_extensions
|
||||||
|
*/
|
||||||
|
$installed_extensions = wc_get_container()->get( InstalledExtensions::class );
|
||||||
|
|
||||||
|
$settings['marketing']['installedExtensions'] = $installed_extensions->get_data();
|
||||||
|
|
||||||
return $settings;
|
return $settings;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Load recommended plugins from WooCommerce.com
|
|
||||||
*
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_recommended_plugins() {
|
|
||||||
$plugins = get_transient( self::RECOMMENDED_PLUGINS_TRANSIENT );
|
|
||||||
|
|
||||||
if ( false === $plugins ) {
|
|
||||||
$request = wp_remote_get(
|
|
||||||
'https://woocommerce.com/wp-json/wccom/marketing-tab/1.2/recommendations.json',
|
|
||||||
array(
|
|
||||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$plugins = [];
|
|
||||||
|
|
||||||
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
|
||||||
$plugins = json_decode( $request['body'], true );
|
|
||||||
}
|
|
||||||
|
|
||||||
set_transient(
|
|
||||||
self::RECOMMENDED_PLUGINS_TRANSIENT,
|
|
||||||
$plugins,
|
|
||||||
// Expire transient in 15 minutes if remote get failed.
|
|
||||||
// Cache an empty result to avoid repeated failed requests.
|
|
||||||
empty( $plugins ) ? 900 : 3 * DAY_IN_SECONDS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return array_values( $plugins );
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Load knowledge base posts from WooCommerce.com
|
|
||||||
*
|
|
||||||
* @param string $category Category of posts to retrieve.
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
public function get_knowledge_base_posts( $category ) {
|
|
||||||
|
|
||||||
$kb_transient = self::KNOWLEDGE_BASE_TRANSIENT;
|
|
||||||
|
|
||||||
$categories = array(
|
|
||||||
'marketing' => 1744,
|
|
||||||
'coupons' => 25202,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Default to marketing category (if no category set on the kb component).
|
|
||||||
if ( ! empty( $category ) && array_key_exists( $category, $categories ) ) {
|
|
||||||
$category_id = $categories[ $category ];
|
|
||||||
$kb_transient = $kb_transient . '_' . strtolower( $category );
|
|
||||||
} else {
|
|
||||||
$category_id = $categories['marketing'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$posts = get_transient( $kb_transient );
|
|
||||||
|
|
||||||
if ( false === $posts ) {
|
|
||||||
$request_url = add_query_arg(
|
|
||||||
array(
|
|
||||||
'categories' => $category_id,
|
|
||||||
'page' => 1,
|
|
||||||
'per_page' => 8,
|
|
||||||
'_embed' => 1,
|
|
||||||
),
|
|
||||||
'https://woocommerce.com/wp-json/wp/v2/posts?utm_medium=product'
|
|
||||||
);
|
|
||||||
|
|
||||||
$request = wp_remote_get(
|
|
||||||
$request_url,
|
|
||||||
array(
|
|
||||||
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$posts = [];
|
|
||||||
|
|
||||||
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
|
||||||
$raw_posts = json_decode( $request['body'], true );
|
|
||||||
|
|
||||||
foreach ( $raw_posts as $raw_post ) {
|
|
||||||
$post = [
|
|
||||||
'title' => html_entity_decode( $raw_post['title']['rendered'] ),
|
|
||||||
'date' => $raw_post['date_gmt'],
|
|
||||||
'link' => $raw_post['link'],
|
|
||||||
'author_name' => isset( $raw_post['author_name'] ) ? html_entity_decode( $raw_post['author_name'] ) : '',
|
|
||||||
'author_avatar' => isset( $raw_post['author_avatar_url'] ) ? $raw_post['author_avatar_url'] : '',
|
|
||||||
];
|
|
||||||
|
|
||||||
$featured_media = $raw_post['_embedded']['wp:featuredmedia'] ?? [];
|
|
||||||
if ( count( $featured_media ) > 0 ) {
|
|
||||||
$image = current( $featured_media );
|
|
||||||
$post['image'] = add_query_arg(
|
|
||||||
array(
|
|
||||||
'resize' => '650,340',
|
|
||||||
'crop' => 1,
|
|
||||||
),
|
|
||||||
$image['source_url']
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$posts[] = $post;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
set_transient(
|
|
||||||
$kb_transient,
|
|
||||||
$posts,
|
|
||||||
// Expire transient in 15 minutes if remote get failed.
|
|
||||||
empty( $posts ) ? 900 : DAY_IN_SECONDS
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $posts;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Marketing Specs Handler
|
||||||
|
*
|
||||||
|
* Fetches the specifications for the marketing feature from WC.com API.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\Admin\Marketing;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Marketing Specifications Class.
|
||||||
|
*
|
||||||
|
* @internal
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
class MarketingSpecs {
|
||||||
|
/**
|
||||||
|
* Name of recommended plugins transient.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const RECOMMENDED_PLUGINS_TRANSIENT = 'wc_marketing_recommended_plugins';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of knowledge base post transient.
|
||||||
|
*
|
||||||
|
* @var string
|
||||||
|
*/
|
||||||
|
const KNOWLEDGE_BASE_TRANSIENT = 'wc_marketing_knowledge_base';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load recommended plugins from WooCommerce.com
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_recommended_plugins(): array {
|
||||||
|
$plugins = get_transient( self::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||||
|
|
||||||
|
if ( false === $plugins ) {
|
||||||
|
$request = wp_remote_get(
|
||||||
|
'https://woocommerce.com/wp-json/wccom/marketing-tab/1.2/recommendations.json',
|
||||||
|
array(
|
||||||
|
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$plugins = [];
|
||||||
|
|
||||||
|
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
||||||
|
$plugins = json_decode( $request['body'], true );
|
||||||
|
}
|
||||||
|
|
||||||
|
set_transient(
|
||||||
|
self::RECOMMENDED_PLUGINS_TRANSIENT,
|
||||||
|
$plugins,
|
||||||
|
// Expire transient in 15 minutes if remote get failed.
|
||||||
|
// Cache an empty result to avoid repeated failed requests.
|
||||||
|
empty( $plugins ) ? 900 : 3 * DAY_IN_SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_values( $plugins );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load knowledge base posts from WooCommerce.com
|
||||||
|
*
|
||||||
|
* @param string|null $category Category of posts to retrieve.
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_knowledge_base_posts( ?string $category ): array {
|
||||||
|
$kb_transient = self::KNOWLEDGE_BASE_TRANSIENT;
|
||||||
|
|
||||||
|
$categories = array(
|
||||||
|
'marketing' => 1744,
|
||||||
|
'coupons' => 25202,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Default to marketing category (if no category set on the kb component).
|
||||||
|
if ( ! empty( $category ) && array_key_exists( $category, $categories ) ) {
|
||||||
|
$category_id = $categories[ $category ];
|
||||||
|
$kb_transient = $kb_transient . '_' . strtolower( $category );
|
||||||
|
} else {
|
||||||
|
$category_id = $categories['marketing'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$posts = get_transient( $kb_transient );
|
||||||
|
|
||||||
|
if ( false === $posts ) {
|
||||||
|
$request_url = add_query_arg(
|
||||||
|
array(
|
||||||
|
'categories' => $category_id,
|
||||||
|
'page' => 1,
|
||||||
|
'per_page' => 8,
|
||||||
|
'_embed' => 1,
|
||||||
|
),
|
||||||
|
'https://woocommerce.com/wp-json/wp/v2/posts?utm_medium=product'
|
||||||
|
);
|
||||||
|
|
||||||
|
$request = wp_remote_get(
|
||||||
|
$request_url,
|
||||||
|
array(
|
||||||
|
'user-agent' => 'WooCommerce/' . WC()->version . '; ' . get_bloginfo( 'url' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$posts = [];
|
||||||
|
|
||||||
|
if ( ! is_wp_error( $request ) && 200 === $request['response']['code'] ) {
|
||||||
|
$raw_posts = json_decode( $request['body'], true );
|
||||||
|
|
||||||
|
foreach ( $raw_posts as $raw_post ) {
|
||||||
|
$post = [
|
||||||
|
'title' => html_entity_decode( $raw_post['title']['rendered'] ),
|
||||||
|
'date' => $raw_post['date_gmt'],
|
||||||
|
'link' => $raw_post['link'],
|
||||||
|
'author_name' => isset( $raw_post['author_name'] ) ? html_entity_decode( $raw_post['author_name'] ) : '',
|
||||||
|
'author_avatar' => isset( $raw_post['author_avatar_url'] ) ? $raw_post['author_avatar_url'] : '',
|
||||||
|
];
|
||||||
|
|
||||||
|
$featured_media = $raw_post['_embedded']['wp:featuredmedia'] ?? [];
|
||||||
|
if ( count( $featured_media ) > 0 ) {
|
||||||
|
$image = current( $featured_media );
|
||||||
|
$post['image'] = add_query_arg(
|
||||||
|
array(
|
||||||
|
'resize' => '650,340',
|
||||||
|
'crop' => 1,
|
||||||
|
),
|
||||||
|
$image['source_url']
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$posts[] = $post;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
set_transient(
|
||||||
|
$kb_transient,
|
||||||
|
$posts,
|
||||||
|
// Expire transient in 15 minutes if remote get failed.
|
||||||
|
empty( $posts ) ? 900 : DAY_IN_SECONDS
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $posts;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* MarketingServiceProvider class file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\InstalledExtensions;
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\MarketingChannels;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||||
|
use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider;
|
||||||
|
|
||||||
|
// Indicates that the multichannel marketing classes exist.
|
||||||
|
// This constant will be checked by third-party extensions before utilizing any of the classes defined for this feature.
|
||||||
|
if ( ! defined( 'WC_MCM_EXISTS' ) ) {
|
||||||
|
define( 'WC_MCM_EXISTS', true );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Service provider for the non-static utils classes in the Automattic\WooCommerce\src namespace.
|
||||||
|
*
|
||||||
|
* @since x.x.x
|
||||||
|
*/
|
||||||
|
class MarketingServiceProvider extends AbstractServiceProvider {
|
||||||
|
/**
|
||||||
|
* The classes/interfaces that are serviced by this service provider.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
protected $provides = array(
|
||||||
|
MarketingSpecs::class,
|
||||||
|
MarketingChannels::class,
|
||||||
|
InstalledExtensions::class,
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register the classes.
|
||||||
|
*/
|
||||||
|
public function register() {
|
||||||
|
$this->share( MarketingSpecs::class );
|
||||||
|
$this->share( MarketingChannels::class )->addArgument( MarketingSpecs::class );
|
||||||
|
$this->share( InstalledExtensions::class )->addArgument( MarketingChannels::class );
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Admin\Marketing;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\MarketingCampaign;
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\Price;
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the MarketingCampaign class.
|
||||||
|
*/
|
||||||
|
class MarketingCampaignTest extends WC_Unit_Test_Case {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox `get_id`, `get_title`, `get_manage_url`, and `get_cost` return the class properties set by the constructor.
|
||||||
|
*/
|
||||||
|
public function test_get_methods_return_properties() {
|
||||||
|
$marketing_campaign = new MarketingCampaign( '1234', 'Ad #1234', 'https://example.com/manage-campaigns', new Price( '1000', 'USD' ) );
|
||||||
|
|
||||||
|
$this->assertEquals( '1234', $marketing_campaign->get_id() );
|
||||||
|
$this->assertEquals( 'Ad #1234', $marketing_campaign->get_title() );
|
||||||
|
$this->assertEquals( 'https://example.com/manage-campaigns', $marketing_campaign->get_manage_url() );
|
||||||
|
$this->assertNotNull( $marketing_campaign->get_cost() );
|
||||||
|
$this->assertEquals( 'USD', $marketing_campaign->get_cost()->get_currency() );
|
||||||
|
$this->assertEquals( '1000', $marketing_campaign->get_cost()->get_value() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox `cost` property can be null.
|
||||||
|
*/
|
||||||
|
public function test_cost_can_be_null() {
|
||||||
|
$marketing_campaign = new MarketingCampaign( '1234', 'Ad #1234', 'https://example.com/manage-campaigns' );
|
||||||
|
|
||||||
|
$this->assertNull( $marketing_campaign->get_cost() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox It can be serialized to JSON including all its properties.
|
||||||
|
*/
|
||||||
|
public function test_can_be_serialized_to_json() {
|
||||||
|
$marketing_campaign = new MarketingCampaign( '1234', 'Ad #1234', 'https://example.com/manage-campaigns', new Price( '1000', 'USD' ) );
|
||||||
|
|
||||||
|
$json = wp_json_encode( $marketing_campaign );
|
||||||
|
$this->assertNotEmpty( $json );
|
||||||
|
$this->assertEqualSets(
|
||||||
|
[
|
||||||
|
'id' => $marketing_campaign->get_id(),
|
||||||
|
'title' => $marketing_campaign->get_title(),
|
||||||
|
'manage_url' => $marketing_campaign->get_manage_url(),
|
||||||
|
'cost' => [
|
||||||
|
'value' => $marketing_campaign->get_cost()->get_value(),
|
||||||
|
'currency' => $marketing_campaign->get_cost()->get_currency(),
|
||||||
|
],
|
||||||
|
],
|
||||||
|
json_decode( $json, true )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,120 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Automattic\WooCommerce\Tests\Admin\Marketing;
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\MarketingChannelInterface;
|
||||||
|
use Automattic\WooCommerce\Admin\Marketing\MarketingChannels;
|
||||||
|
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||||
|
use WC_Unit_Test_Case;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests for the MarketingChannels class.
|
||||||
|
*/
|
||||||
|
class MarketingChannelsTest extends WC_Unit_Test_Case {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs before each test.
|
||||||
|
*/
|
||||||
|
public function setUp(): void {
|
||||||
|
delete_transient( MarketingSpecs::RECOMMENDED_PLUGINS_TRANSIENT );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox A marketing channel can be registered using the `register` method if it is in the allowed list.
|
||||||
|
*/
|
||||||
|
public function test_registers_allowed_channels() {
|
||||||
|
$test_channel = $this->createMock( MarketingChannelInterface::class );
|
||||||
|
$test_channel->expects( $this->any() )->method( 'get_slug' )->willReturn( 'test-channel-1' );
|
||||||
|
|
||||||
|
$marketing_specs = $this->createMock( MarketingSpecs::class );
|
||||||
|
$marketing_specs->expects( $this->once() )
|
||||||
|
->method( 'get_recommended_plugins' )
|
||||||
|
->willReturn(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'product' => 'test-channel-1',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$marketing_channels = new MarketingChannels();
|
||||||
|
$marketing_channels->init( $marketing_specs );
|
||||||
|
$marketing_channels->register( $test_channel );
|
||||||
|
|
||||||
|
$this->assertNotEmpty( $marketing_channels->get_registered_channels() );
|
||||||
|
$this->assertEquals( $test_channel, $marketing_channels->get_registered_channels()[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox A marketing channel can NOT be registered using the `register` method if it is NOT in the allowed list.
|
||||||
|
*/
|
||||||
|
public function test_does_not_register_disallowed_channels() {
|
||||||
|
$test_channel = $this->createMock( MarketingChannelInterface::class );
|
||||||
|
$test_channel->expects( $this->any() )->method( 'get_slug' )->willReturn( 'test-channel-1' );
|
||||||
|
|
||||||
|
$marketing_specs = $this->createMock( MarketingSpecs::class );
|
||||||
|
$marketing_specs->expects( $this->once() )->method( 'get_recommended_plugins' )->willReturn( [] );
|
||||||
|
|
||||||
|
$marketing_channels = new MarketingChannels();
|
||||||
|
$marketing_channels->init( $marketing_specs );
|
||||||
|
$marketing_channels->register( $test_channel );
|
||||||
|
|
||||||
|
$this->assertEmpty( $marketing_channels->get_registered_channels() );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox A marketing channel can be registered using the `woocommerce_marketing_channels` WordPress filter if it is in the allowed list.
|
||||||
|
*/
|
||||||
|
public function test_registers_allowed_channels_using_wp_filter() {
|
||||||
|
$test_channel = $this->createMock( MarketingChannelInterface::class );
|
||||||
|
$test_channel->expects( $this->any() )->method( 'get_slug' )->willReturn( 'test-channel-1' );
|
||||||
|
|
||||||
|
$marketing_specs = $this->createMock( MarketingSpecs::class );
|
||||||
|
$marketing_specs->expects( $this->once() )
|
||||||
|
->method( 'get_recommended_plugins' )
|
||||||
|
->willReturn(
|
||||||
|
[
|
||||||
|
[
|
||||||
|
'product' => 'test-channel-1',
|
||||||
|
],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
$marketing_channels = new MarketingChannels();
|
||||||
|
$marketing_channels->init( $marketing_specs );
|
||||||
|
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_marketing_channels',
|
||||||
|
function ( array $channels ) use ( $test_channel ) {
|
||||||
|
$channels[ $test_channel->get_slug() ] = $test_channel;
|
||||||
|
|
||||||
|
return $channels;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertNotEmpty( $marketing_channels->get_registered_channels() );
|
||||||
|
$this->assertEquals( $test_channel, $marketing_channels->get_registered_channels()[0] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox A marketing channel can NOT be registered using the `woocommerce_marketing_channels` WordPress filter if it NOT is in the allowed list.
|
||||||
|
*/
|
||||||
|
public function test_does_not_register_disallowed_channels_using_wp_filter() {
|
||||||
|
$test_channel = $this->createMock( MarketingChannelInterface::class );
|
||||||
|
$test_channel->expects( $this->any() )->method( 'get_slug' )->willReturn( 'test-channel-1' );
|
||||||
|
|
||||||
|
set_transient( MarketingSpecs::RECOMMENDED_PLUGINS_TRANSIENT, [] );
|
||||||
|
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_marketing_channels',
|
||||||
|
function ( array $channels ) use ( $test_channel ) {
|
||||||
|
$channels[ $test_channel->get_slug() ] = $test_channel;
|
||||||
|
|
||||||
|
return $channels;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$marketing_channels = new MarketingChannels();
|
||||||
|
$this->assertEmpty( $marketing_channels->get_registered_channels() );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue