always resume up at the last pending or unfinished step. * If the Ads account has already been created, the ID is simply returned. * * @return array The newly created (or pre-existing) Ads ID. * @throws Exception If an error occurs during any step. */ public function setup_account(): array { $state = $this->state->get(); $ads_id = $this->options->get_ads_id(); $account = [ 'id' => $ads_id ]; foreach ( $state as $name => &$step ) { if ( AdsAccountState::STEP_DONE === $step['status'] ) { continue; } try { switch ( $name ) { case 'set_id': // Just in case, don't create another Ads ID. if ( ! empty( $ads_id ) ) { break; } $account = $this->container->get( Middleware::class )->create_ads_account(); $step['data']['sub_account'] = true; $step['data']['created_timestamp'] = time(); break; case 'billing': $this->check_billing_status( $account ); break; case 'conversion_action': $this->create_conversion_action(); break; case 'link_merchant': // Continue to next step if the MC account is not connected yet. if ( ! $this->options->get_merchant_id() ) { // Save step as pending and continue the foreach loop with `continue 2`. $state[ $name ]['status'] = AdsAccountState::STEP_PENDING; $this->state->update( $state ); continue 2; } $this->link_merchant_account(); break; case 'account_access': $this->check_ads_account_has_access(); break; default: throw new Exception( /* translators: 1: is a string representing an unknown step name */ sprintf( __( 'Unknown ads account creation step %1$s', 'google-listings-and-ads' ), $name ) ); } $step['status'] = AdsAccountState::STEP_DONE; $step['message'] = ''; $this->state->update( $state ); } catch ( Exception $e ) { $step['status'] = AdsAccountState::STEP_ERROR; $step['message'] = $e->getMessage(); $this->state->update( $state ); throw $e; } } return $account; } /** * Gets the billing setup status and returns a setup URL if available. * * @return array */ public function get_billing_status(): array { $status = $this->container->get( Ads::class )->get_billing_status(); if ( BillingSetupStatus::APPROVED === $status ) { $this->state->complete_step( 'billing' ); return [ 'status' => $status ]; } $billing_url = $this->options->get( OptionsInterface::ADS_BILLING_URL ); // Check if user has provided the access and ocid is present. $connection_status = $this->container->get( Connection::class )->get_status(); $email = $connection_status['email'] ?? ''; $has_access = $this->container->get( Ads::class )->has_access( $email ); $ocid = $this->options->get( OptionsInterface::ADS_ACCOUNT_OCID, null ); // Link directly to the payment page if the customer already has access. if ( $has_access ) { $billing_url = add_query_arg( [ 'ocid' => $ocid ?: 0, ], 'https://ads.google.com/aw/signup/payment' ); } return [ 'status' => $status, 'billing_url' => $billing_url, ]; } /** * Check if the Ads account has access. * * @throws ExceptionWithResponseData If the account doesn't have access. */ private function check_ads_account_has_access() { $access_status = $this->get_ads_account_has_access(); if ( ! $access_status['has_access'] ) { throw new ExceptionWithResponseData( __( 'Account must be accepted before completing setup.', 'google-listings-and-ads' ), 428, null, $access_status ); } } /** * Gets the Ads account access status. * * @return array { * Returns the access status, last completed account setup step, * and invite link if available. * * @type bool $has_access Whether the customer has access to the account. * @type string $step The last completed setup step for the Ads account. * @type string $invite_link The URL to the invite link. * } */ public function get_ads_account_has_access() { $has_access = false; // Check if an Ads ID is present. if ( $this->options->get_ads_id() ) { $connection_status = $this->container->get( Connection::class )->get_status(); $email = $connection_status['email'] ?? ''; } // If no email, means google account is not connected. if ( ! empty( $email ) ) { $has_access = $this->container->get( Ads::class )->has_access( $email ); } // If we have access, complete the step so that it won't be called next time. if ( $has_access ) { $this->state->complete_step( 'account_access' ); } return [ 'has_access' => $has_access, 'step' => $this->state->last_incomplete_step(), 'invite_link' => $this->options->get( OptionsInterface::ADS_BILLING_URL, '' ), ]; } /** * Disconnect Ads account */ public function disconnect() { $this->options->delete( OptionsInterface::ADS_ACCOUNT_CURRENCY ); $this->options->delete( OptionsInterface::ADS_ACCOUNT_OCID ); $this->options->delete( OptionsInterface::ADS_ACCOUNT_STATE ); $this->options->delete( OptionsInterface::ADS_BILLING_URL ); $this->options->delete( OptionsInterface::ADS_CONVERSION_ACTION ); $this->options->delete( OptionsInterface::ADS_ID ); $this->options->delete( OptionsInterface::ADS_SETUP_COMPLETED_AT ); $this->options->delete( OptionsInterface::CAMPAIGN_CONVERT_STATUS ); $this->container->get( TransientsInterface::class )->delete( TransientsInterface::ADS_CAMPAIGN_COUNT ); } /** * Confirm the billing flow has been completed. * * @param array $account Account details. * * @throws ExceptionWithResponseData If this step hasn't been completed yet. */ private function check_billing_status( array $account ) { $status = BillingSetupStatus::UNKNOWN; // Only check billing status if we haven't just created the account. if ( empty( $account['billing_url'] ) ) { $status = $this->container->get( Ads::class )->get_billing_status(); } if ( BillingSetupStatus::APPROVED !== $status ) { throw new ExceptionWithResponseData( __( 'Billing setup must be completed.', 'google-listings-and-ads' ), 428, null, [ 'billing_url' => $this->options->get( OptionsInterface::ADS_BILLING_URL ), 'billing_status' => $status, ] ); } } /** * Get the callback function for linking a merchant account. * * @throws Exception When the ads account hasn't been set yet. */ private function link_merchant_account() { if ( ! $this->options->get_ads_id() ) { throw new Exception( 'An Ads account must be connected' ); } $mc_state = $this->container->get( MerchantAccountState::class ); // Create link for Merchant and accept it in Ads. $this->container->get( Merchant::class )->link_ads_id( $this->options->get_ads_id() ); $this->container->get( Ads::class )->accept_merchant_link( $this->options->get_merchant_id() ); $mc_state->complete_step( 'link_ads' ); } /** * Create the generic GLA conversion action and store the details as an option. * * @throws Exception If the conversion action can't be created. */ private function create_conversion_action(): void { $action = $this->container->get( AdsConversionAction::class )->create_conversion_action(); $this->options->update( OptionsInterface::ADS_CONVERSION_ACTION, $action ); } }
Warning: class_implements(): Class Automattic\WooCommerce\GoogleListingsAndAds\Ads\AccountService does not exist and could not be loaded in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 119

Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, bool given in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php:120 Stack trace: #0 /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php(120): array_key_exists('Automattic\\WooC...', false) #1 /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/CoreServiceProvider.php(308): Automattic\WooCommerce\GoogleListingsAndAds\Internal\DependencyManagement\AbstractServiceProvider->conditionally_share_with_tags('Automattic\\WooC...', 'Automattic\\WooC...') #2 /htdocs/wp-content/plugins/google-listings-and-ads/vendor/league/container/src/ServiceProvider/ServiceProviderAggregate.php(102): Automattic\WooCommerce\GoogleListingsAndAds\Internal\DependencyManagement\CoreServiceProvider->register() #3 /htdocs/wp-content/plugins/google-listings-and-ads/vendor/league/container/src/Container.php(172): Automattic\WooCommerce\GoogleListingsAndAds\Vendor\League\Container\ServiceProvider\ServiceProviderAggregate->register('Automattic\\WooC...') #4 /htdocs/wp-content/plugins/google-listings-and-ads/src/Container.php(90): Automattic\WooCommerce\GoogleListingsAndAds\Vendor\League\Container\Container->get('Automattic\\WooC...') #5 /htdocs/wp-content/plugins/google-listings-and-ads/src/Infrastructure/GoogleListingsAndAdsPlugin.php(130): Automattic\WooCommerce\GoogleListingsAndAds\Container->get('Automattic\\WooC...') #6 /htdocs/wp-content/plugins/google-listings-and-ads/src/Infrastructure/GoogleListingsAndAdsPlugin.php(91): Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\GoogleListingsAndAdsPlugin->maybe_register_services() #7 /htdocs/wp-includes/class-wp-hook.php(324): Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\GoogleListingsAndAdsPlugin->Automattic\WooCommerce\GoogleListingsAndAds\Infrastructure\{closure}('') #8 /htdocs/wp-includes/class-wp-hook.php(348): WP_Hook->apply_filters(NULL, Array) #9 /htdocs/wp-includes/plugin.php(517): WP_Hook->do_action(Array) #10 /htdocs/wp-settings.php(559): do_action('plugins_loaded') #11 /htdocs/wp-config.php(85): require_once('/htdocs/wp-sett...') #12 /htdocs/wp-load.php(50): require_once('/htdocs/wp-conf...') #13 /htdocs/wp-blog-header.php(13): require_once('/htdocs/wp-load...') #14 /htdocs/index.php(17): require('/htdocs/wp-blog...') #15 {main} thrown in /htdocs/wp-content/plugins/google-listings-and-ads/src/Internal/DependencyManagement/AbstractServiceProvider.php on line 120