<?php
/**
* Handle Admin init.
*
* @package Pinterest/Admin
* @version 1.0.0
*/
use Automattic\WooCommerce\Admin\Features\Features;
use Automattic\WooCommerce\Admin\Features\Navigation\Menu;
use Automattic\WooCommerce\Admin\Features\Navigation\Screen;
use Automattic\WooCommerce\Admin\PageController;
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry;
use Automattic\WooCommerce\Pinterest\Compat;
use Automattic\WooCommerce\Pinterest\Tracking;
use Automattic\WooCommerce\Pinterest\PinterestSyncSettings;
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'Pinterest_For_Woocommerce_Admin' ) ) :
/**
* Class handling the settings page and onboarding Wizard registration and rendering.
*/
class Pinterest_For_Woocommerce_Admin {
/**
* Initialize class
*/
public function __construct() {
add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_assets' ) );
add_action( 'admin_init', array( $this, 'maybe_redirect_to_middleware' ) );
add_filter( 'woocommerce_get_registered_extended_tasks', array( $this, 'register_task_list_item' ), 10, 1 );
add_filter( 'admin_footer', array( $this, 'load_settings' ) );
add_filter( 'woocommerce_marketing_menu_items', array( $this, 'add_menu_items' ) );
add_action( 'admin_menu', array( $this, 'fix_menu_paths' ) );
add_action( 'admin_menu', array( $this, 'register_wc_admin_pages' ) );
add_filter( 'plugin_action_links_' . PINTEREST_FOR_WOOCOMMERCE_PLUGIN_BASENAME, array( $this, 'plugin_action_links' ) );
}
/**
* Handle registration of all needed pages, depending on setup_complete status,
* and wether we have the new WC nav enabled or not.
*
* @return void
*/
public function register_wc_admin_pages() {
$new_nav = $this->is_new_nav_enabled();
$setup_complete = Pinterest_For_Woocommerce()::is_setup_complete();
if ( $new_nav && $setup_complete ) {
// If setup is complete, add the base menu item as a category, and the settings as the main item.
// Connection & catalog are added later on, for both new and old nav.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-category',
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'parent' => 'woocommerce',
'path' => '/pinterest/settings',
'nav_args' => array(
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'is_category' => true,
'menuId' => 'plugins',
'is_top_level' => true,
),
)
);
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-catalog',
'title' => esc_html__( 'Catalog', 'pinterest-for-woocommerce' ),
'parent' => 'pinterest-for-woocommerce-category',
'path' => '/pinterest/catalog',
'nav_args' => array(
'order' => 10,
'parent' => 'pinterest-for-woocommerce-category',
),
)
);
} elseif ( $new_nav ) {
// Setup not complete. Add the Landing page as the main menu item.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-landing-page',
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'parent' => 'woocommerce',
'path' => '/pinterest/landing',
'nav_args' => array(
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'menuId' => 'plugins',
'is_top_level' => true,
),
)
);
// Allow rendering of the onboarding guide on a page refresh.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-setup-guide',
'title' => esc_html__( 'Setup Pinterest', 'pinterest-for-woocommerce' ),
'parent' => '',
'path' => '/pinterest/onboarding',
)
);
}
$menu_items_parent = $new_nav ? 'pinterest-for-woocommerce-category' : 'toplevel_page_woocommerce-marketing';
if ( $setup_complete ) {
// The connection & settings pages are registered for both old & new nav, if setup is complete.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-connection',
'title' => esc_html__( 'Connection', 'pinterest-for-woocommerce' ),
'parent' => $menu_items_parent,
'path' => '/pinterest/connection',
'nav_args' => array(
'order' => 50,
'parent' => $menu_items_parent,
),
)
);
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-settings',
'title' => esc_html__( 'Settings', 'pinterest-for-woocommerce' ),
'parent' => $menu_items_parent,
'path' => '/pinterest/settings',
'nav_args' => array(
'order' => 40,
'parent' => $menu_items_parent,
),
)
);
}
if ( ! $new_nav ) {
// Allow rendering of the onboarding guide on a page refresh.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-setup-guide',
'title' => esc_html__( 'Setup Pinterest', 'pinterest-for-woocommerce' ),
'parent' => 'toplevel_page_woocommerce-marketing',
'path' => '/pinterest/onboarding',
)
);
}
if ( $setup_complete ) {
// Allow rendering of the landing page on a page refresh for both old & new nav, when setup is complete.
wc_admin_register_page(
array(
'id' => 'pinterest-for-woocommerce-landing-page',
'title' => esc_html__( 'Landing page', 'pinterest-for-woocommerce' ),
'parent' => '',
'path' => '/pinterest/landing',
)
);
}
}
/**
* Fix sub-menu paths. wc_admin_register_page() gets it wrong.
*
* @return void
*/
public function fix_menu_paths() {
global $submenu;
if ( ! isset( $submenu['woocommerce-marketing'] ) || $this->is_new_nav_enabled() ) {
return;
}
foreach ( $submenu['woocommerce-marketing'] as &$item ) {
// The "slug" (aka the path) is the third item in the array.
if ( 0 === strpos( $item[2], 'wc-admin' ) ) {
$item[2] = 'admin.php?page=' . $item[2];
}
}
}
/**
* Add the base menu item using the woocommerce_marketing_menu_items filter,
* Depending on status of setup_complete.
*
* @param array $items The array of items to be filtered.
*
* @return array
*/
public function add_menu_items( $items ) {
if ( $this->is_new_nav_enabled() ) {
return $items;
}
if ( Pinterest_For_Woocommerce()::is_setup_complete() ) {
$items[] = array(
'id' => 'pinterest-for-woocommerce-catalog',
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'path' => '/pinterest/catalog',
'capability' => 'manage_woocommerce',
);
} else {
$items[] = array(
'id' => 'pinterest-for-woocommerce-landing-page',
'title' => esc_html__( 'Pinterest', 'pinterest-for-woocommerce' ),
'path' => '/pinterest/landing',
'capability' => 'manage_woocommerce',
);
}
return $items;
}
/**
* Add a Settings link to the plugin's action links in the Plugins list table.
*
* @param array $links Existing plugin action links.
* @return array
*/
public function plugin_action_links( $links ) {
$url = admin_url( 'admin.php?page=wc-admin&path=/pinterest/landing' );
$settings_link = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Settings', 'pinterest-for-woocommerce' ) . '</a>';
array_unshift( $links, $settings_link );
return $links;
}
/**
* Checks if the new WC navigation is enabled.
*
* @return boolean
*/
public function is_new_nav_enabled() {
return method_exists( Screen::class, 'register_post_type' ) &&
method_exists( Menu::class, 'add_plugin_item' ) &&
method_exists( Menu::class, 'add_plugin_category' ) &&
method_exists( Features::class, 'is_enabled' ) &&
Features::is_enabled( 'navigation' );
}
/**
* Load the scripts needed for the setup guide / settings page.
*/
public function load_setup_guide_scripts() {
if ( ! PageController::is_admin_page() ) {
return;
}
$build_path = '/assets/build';
$handle = PINTEREST_FOR_WOOCOMMERCE_PREFIX . '-setup-guide';
$script_asset_path = Pinterest_For_Woocommerce()->plugin_path() . $build_path . '/setup-guide.asset.php';
$script_info = file_exists( $script_asset_path )
? include $script_asset_path
: array(
'dependencies' => array(),
'version' => PINTEREST_FOR_WOOCOMMERCE_VERSION,
);
// This is a quick fix for a breaking change in WP 6.6.
// We may not need this in the future when we update `@wordpress/*` packages to newer versions.
$script_info['dependencies'][] = 'regenerator-runtime';
$script_info['dependencies'][] = 'wc-settings';
wp_register_script(
$handle,
Pinterest_For_Woocommerce()->plugin_url() . $build_path . '/setup-guide.js',
$script_info['dependencies'],
$script_info['version'],
true
);
wp_enqueue_script( $handle );
wp_register_style(
$handle,
Pinterest_For_Woocommerce()->plugin_url() . $build_path . '/style-setup-guide.css',
array( 'wc-admin-app' ),
PINTEREST_FOR_WOOCOMMERCE_VERSION
);
wp_enqueue_style( $handle );
}
/**
* Enqueues admin related scripts & styles
*
* @return void
*/
public function load_admin_assets() {
$assets_path_url = str_replace( array( 'http:', 'https:' ), '', Pinterest_For_Woocommerce()->plugin_url() ) . '/assets/';
$ext = ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ) ? '' : '.min';
wp_enqueue_script( 'pinterest-for-woocommerce-admin', $assets_path_url . 'js/admin/pinterest-for-woocommerce-admin' . $ext . '.js', array( 'jquery' ), PINTEREST_FOR_WOOCOMMERCE_VERSION, true );
$this->load_setup_guide_scripts();
}
/**
* Register the Task List item for WC-Admin.
*
* @param array $registered_tasks_list_items the list of tasks to be filtered.
*/
public function register_task_list_item( $registered_tasks_list_items ) {
if (
! PageController::is_admin_page() ||
! Compat::should_show_tasks()
) {
return $registered_tasks_list_items;
}
$new_task_name = 'woocommerce_admin_add_task_pinterest_setup';
if ( ! in_array( $new_task_name, $registered_tasks_list_items, true ) ) {
array_push( $registered_tasks_list_items, $new_task_name );
}
return $registered_tasks_list_items;
}
/**
* Load all plugin frontend data using the AssetDataRegistry class.
* Hooked to admin_footer as AssetDataRegistry prints at wp_print_footer_scripts.
*
* @return void
*/
public function load_settings() {
if ( ! PageController::is_admin_page() || ! class_exists( AssetDataRegistry::class ) ) {
return;
}
Package::container()->get( AssetDataRegistry::class )->add( 'pinterest_for_woocommerce', $this->get_component_settings() );
}
/**
* Initialize asset data and registering it with
* the internal WC data registry.
*
* @return array
*/
private function get_component_settings() {
$store_country = Pinterest_For_Woocommerce()::get_base_country();
return array(
'pluginVersion' => PINTEREST_FOR_WOOCOMMERCE_VERSION,
'pluginUrl' => Pinterest_For_Woocommerce()->plugin_url(),
'serviceLoginUrl' => $this->get_service_login_url(),
'createBusinessAccountUrl' => $this->get_create_business_account_url(),
'switchBusinessAccountUrl' => $this->get_switch_business_account_url(),
'billingSettingsUrl' => $this->get_advertiser_billing_settings_url(),
'homeUrlToVerify' => get_home_url(),
'storeCountry' => $store_country,
'isAdsSupportedCountry' => Pinterest_For_Woocommerce_Ads_Supported_Countries::is_ads_supported_country(),
'isConnected' => ! empty( Pinterest_For_Woocommerce()::is_connected() ),
'isBusinessConnected' => ! empty( Pinterest_For_Woocommerce()::is_business_connected() ),
'businessAccounts' => Pinterest_For_Woocommerce()::get_linked_businesses(),
'apiRoute' => PINTEREST_FOR_WOOCOMMERCE_API_NAMESPACE . '/v' . PINTEREST_FOR_WOOCOMMERCE_API_VERSION,
'optionsName' => PINTEREST_FOR_WOOCOMMERCE_OPTION_NAME,
'syncedSettings' => PinterestSyncSettings::get_synced_settings(),
'error' => isset( $_GET['error'] ) ? sanitize_text_field( wp_unslash( $_GET['error'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended --- not needed
'pinterestLinks' => array(
'newAccount' => 'https://business.pinterest.com/',
'claimWebsite' => 'https://help.pinterest.com/en/business/article/claim-your-website',
'richPins' => 'https://help.pinterest.com/en/business/article/rich-pins',
'enhancedMatch' => 'https://help.pinterest.com/en/business/article/enhanced-match',
'createAdvertiser' => 'https://help.pinterest.com/en/business/article/create-an-advertiser-account',
'adGuidelines' => 'https://policy.pinterest.com/en/advertising-guidelines',
'adDataTerms' => 'https://policy.pinterest.com/en/ad-data-terms',
'merchantGuidelines' => 'https://policy.pinterest.com/en/merchant-guidelines',
'convertToBusinessAcct' => 'https://help.pinterest.com/en/business/article/get-a-business-account#section-15096',
'appealDeclinedMerchant' => 'https://www.pinterest.com/product-catalogs/data-source/?showModal=true',
'installTag' => 'https://help.pinterest.com/en/business/article/install-the-pinterest-tag',
'adsManager' => 'https://ads.pinterest.com/',
'preLaunchNotice' => 'https://help.pinterest.com/en-gb/business/article/get-a-business-profile/',
'adsAvailability' => 'https://help.pinterest.com/en/business/availability/ads-availability',
'automaticEnhancedMatch' => 'https://www.pinterest.com/_/_/help/business/article/automatic-enhanced-match',
'tagManager' => $this->get_tag_manager_link(),
),
'isSetupComplete' => Pinterest_For_Woocommerce()::is_setup_complete(),
'countryTos' => Pinterest_For_Woocommerce()::get_applicable_tos(),
'claimWebsiteErrorStatus' => array(
401 => 'token',
403 => 'connection',
406 => 'domain verification',
409 => 'meta-tag',
),
'conflictingTagsWarning' => Tracking\Tag::get_third_party_tags_warning_message(),
);
}
/**
* Return the serviceLoginUrl
*
* @return string
*/
private function get_service_login_url() {
return add_query_arg(
array(
'page' => 'wc-admin',
'view' => 'wizard',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_service_login' => '1',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_nonce' => $this->get_middleware_url_nonce(),
),
admin_url( 'admin.php' )
);
}
/**
* Return the createBusinessAccountUrl
*
* @return string
*/
private function get_create_business_account_url() {
return add_query_arg(
array(
'page' => 'wc-admin',
'view' => 'wizard',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_create_account' => '1',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_nonce' => $this->get_middleware_url_nonce(),
),
admin_url( 'admin.php' )
);
}
/**
* Return the switchBusinessAccountUrl
*
* @return string
*/
private function get_switch_business_account_url() {
return add_query_arg(
array(
'page' => 'wc-admin',
'view' => 'wizard',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_switch_account' => '1',
PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_nonce' => $this->get_middleware_url_nonce(),
),
admin_url( 'admin.php' )
);
}
/**
* Return the advertiser billing settings URL.
*
* @since 1.4.5
* @return string
*/
private function get_advertiser_billing_settings_url() {
$advertiser_id = Pinterest_For_Woocommerce()->get_setting( 'tracking_advertiser' );
return "https://ads.pinterest.com/advertiser/{$advertiser_id}/billing";
}
/**
* Create & return a nonce for the service URL.
* This nonce is runtime cached.
*
* @return string
*/
private function get_middleware_url_nonce() {
static $nonce;
return null === $nonce ? wp_create_nonce( 'go_to_middleware_url' ) : $nonce;
}
/**
* Handles redirection to the Middleware App (Woo Connect Bridge).
*/
public function maybe_redirect_to_middleware() {
if ( ! isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_service_login' ] ) && ! isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_create_account' ] ) && ! isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_switch_account' ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended --- not needed
return;
}
if ( ! isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_nonce' ] ) || ! wp_verify_nonce( sanitize_key( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_nonce' ] ), 'go_to_middleware_url' ) || ! current_user_can( 'manage_woocommerce' ) ) {
wp_die( esc_html__( "Cheatin' huh?", 'pinterest-for-woocommerce' ) );
}
$context = 'login';
$args = array( 'view' => ! empty( $_REQUEST['view'] ) ? sanitize_key( $_REQUEST['view'] ) : null );
if ( isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_create_account' ] ) ) {
$context = 'create_business';
} elseif ( isset( $_GET[ PINTEREST_FOR_WOOCOMMERCE_PREFIX . '_go_to_switch_account' ] ) && ! empty( $_GET['business_id'] ) ) {
$context = 'switch_business';
$args['business_id'] = sanitize_key( $_GET['business_id'] );
}
add_filter( 'allowed_redirect_hosts', array( $this, 'allow_service_login' ) );
wp_safe_redirect( Pinterest_For_Woocommerce()::get_middleware_url( $context, $args ) );
exit;
}
/**
* Add the domain of API/Bridge service to the list of allowed redirect hosts.
*
* @param array $allowed_hosts the array of allowed hosts.
*
* @return array
*/
public function allow_service_login( $allowed_hosts ) {
$service_domain = Pinterest_For_Woocommerce()::get_connection_proxy_url();
$allowed_hosts[] = wp_parse_url( $service_domain, PHP_URL_HOST );
return $allowed_hosts;
}
/**
* Get tags manager link if there is a connected advertiser or the ads manager link if not.
*
* @since 1.2.18
*
* @return string
*/
protected function get_tag_manager_link() {
$tag_manager_link = 'https://ads.pinterest.com/advertiser/';
$advertiser_id = Pinterest_For_Woocommerce()->get_setting( 'tracking_advertiser' );
if ( ! $advertiser_id ) {
return $tag_manager_link;
}
return "{$tag_manager_link}{$advertiser_id}/conversions/tag";
}
}
endif;
return new Pinterest_For_Woocommerce_Admin();