enable_rest_api(); $this->enable_wp_cli(); Event_Manager::register_model_events('membership', __('Membership', 'wp-ultimo'), array('created', 'updated')); add_action('wu_async_transfer_membership', array($this, 'async_transfer_membership'), 10, 2); add_action('wu_async_delete_membership', array($this, 'async_delete_membership'), 10); /* * Transitions */ add_action('wu_transition_membership_status', array($this, 'mark_cancelled_date'), 10, 3); add_action('wu_transition_membership_status', array($this, 'transition_membership_status'), 10, 3); /* * Deal with delayed/schedule swaps */ add_action('wu_async_membership_swap', array($this, 'async_membership_swap'), 10); /* * Deal with pending sites creation */ add_action('wp_ajax_wu_publish_pending_site', array($this, 'publish_pending_site')); add_action('wp_ajax_wu_check_pending_site_created', array($this, 'check_pending_site_created')); add_action('wu_async_publish_pending_site', array($this, 'async_publish_pending_site'), 10); } // end init; /** * Processes a delayed site publish action. * * @since 2.0.11 */ public function publish_pending_site() { check_ajax_referer('wu_publish_pending_site'); ignore_user_abort(true); // Don't make the request block till we finish, if possible. if ( function_exists( 'fastcgi_finish_request' ) && version_compare( phpversion(), '7.0.16', '>=' ) ) { wp_send_json(array( 'status' => 'creating-site')); fastcgi_finish_request(); } // end if; $membership_id = wu_request('membership_id'); $this->async_publish_pending_site($membership_id); exit; // Just exit the request } // end publish_pending_site; /** * Processes a delayed site publish action. * * @since 2.0.0 * * @param int $membership_id The membership id. * @return bool|\WP_Error */ public function async_publish_pending_site($membership_id) { $membership = wu_get_membership($membership_id); if (!$membership) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $status = $membership->publish_pending_site(); if (is_wp_error($status)) { wu_log_add('site-errors', $status, LogLevel::ERROR); } // end if; return $status; } // end async_publish_pending_site; /** * Processes a delayed site publish action. * * @since 2.0.11 */ public function check_pending_site_created() { $membership_id = wu_request('membership_hash'); $membership = wu_get_membership_by_hash($membership_id); if (!$membership) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $pending_site = $membership->get_pending_site(); if (!$pending_site) { /** * We do not have a pending site, so we can assume the site was created. */ wp_send_json(array('publish_status' => 'completed')); exit; } // end if; wp_send_json(array('publish_status' => $pending_site->is_publishing() ? 'running' : 'stopped')); exit; } // end check_pending_site_created; /** * Processes a membership swap. * * @since 2.0.0 * * @param int $membership_id The membership id. * @return bool|\WP_Error */ public function async_membership_swap($membership_id) { global $wpdb; $membership = wu_get_membership($membership_id); if (!$membership) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $scheduled_swap = $membership->get_scheduled_swap(); if (empty($scheduled_swap)) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $order = $scheduled_swap->order; $wpdb->query('START TRANSACTION'); try { $membership->swap($order); $status = $membership->save(); if (is_wp_error($status)) { $wpdb->query('ROLLBACK'); return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; } catch (\Throwable $exception) { $wpdb->query('ROLLBACK'); return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end try; /* * Clean up the membership swap order. */ $membership->delete_scheduled_swap(); $wpdb->query('COMMIT'); return true; } // end async_membership_swap; /** * Watches the change in payment status to take action when needed. * * @todo Publishing sites should be done in async. * * @since 2.0.0 * * @param string $old_status The old status of the membership. * @param string $new_status The new status of the membership. * @param integer $membership_id Payment ID. * @return void */ public function transition_membership_status($old_status, $new_status, $membership_id) { $allowed_previous_status = array( Membership_Status::PENDING, Membership_Status::ON_HOLD, ); if (!in_array($old_status, $allowed_previous_status, true)) { return; } // end if; $allowed_status = array( Membership_Status::ACTIVE, Membership_Status::TRIALING, ); if (!in_array($new_status, $allowed_status, true)) { return; } // end if; /* * Create pending sites. */ $membership = wu_get_membership($membership_id); $status = $membership->publish_pending_site_async(); if (is_wp_error($status)) { wu_log_add('site-errors', $status, LogLevel::ERROR); } // end if; } // end transition_membership_status; /** * Mark the membership date of cancellation. * * @since 2.0.0 * * @param string $old_value Old status value. * @param string $new_value New status value. * @param int $item_id The membership id. * @return void */ public function mark_cancelled_date($old_value, $new_value, $item_id) { if ($new_value === 'cancelled' && $new_value !== $old_value) { $membership = wu_get_membership($item_id); $membership->set_date_cancellation(wu_get_current_time('mysql', true)); $membership->save(); } // end if; } // end mark_cancelled_date; /** * Transfer a membership from a user to another. * * @since 2.0.0 * * @param int $membership_id The ID of the membership being transferred. * @param int $target_customer_id The new owner. * @return mixed */ public function async_transfer_membership($membership_id, $target_customer_id) { global $wpdb; $membership = wu_get_membership($membership_id); $target_customer = wu_get_customer($target_customer_id); if (!$membership || !$target_customer || absint($membership->get_customer_id()) === absint($target_customer->get_id())) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $wpdb->query('START TRANSACTION'); try { /* * Get Sites and move them over. */ $sites = wu_get_sites(array( 'meta_query' => array( 'membership_id' => array( 'key' => 'wu_membership_id', 'value' => $membership->get_id(), ), ), )); foreach ($sites as $site) { $site->set_customer_id($target_customer_id); $saved = $site->save(); if (is_wp_error($saved)) { $wpdb->query('ROLLBACK'); return $saved; } // end if; } // end foreach; /* * Change the membership */ $membership->set_customer_id($target_customer_id); $saved = $membership->save(); if (is_wp_error($saved)) { $wpdb->query('ROLLBACK'); return $saved; } // end if; } catch (\Throwable $e) { $wpdb->query('ROLLBACK'); return new \WP_Error('exception', $e->getMessage()); } // end try; $wpdb->query('COMMIT'); $membership->unlock(); return true; } // end async_transfer_membership; /** * Delete a membership. * * @since 2.0.0 * * @param int $membership_id The ID of the membership being deleted. * @return mixed */ public function async_delete_membership($membership_id) { global $wpdb; $membership = wu_get_membership($membership_id); if (!$membership) { return new \WP_Error('error', __('An unexpected error happened.', 'wp-ultimo')); } // end if; $wpdb->query('START TRANSACTION'); try { /* * Get Sites and delete them. */ $sites = wu_get_sites(array( 'meta_query' => array( 'membership_id' => array( 'key' => 'wu_membership_id', 'value' => $membership->get_id(), ), ), )); foreach ($sites as $site) { $saved = $site->delete(); if (is_wp_error($saved)) { $wpdb->query('ROLLBACK'); return $saved; } // end if; } // end foreach; /* * Delete the membership */ $saved = $membership->delete(); if (is_wp_error($saved)) { $wpdb->query('ROLLBACK'); return $saved; } // end if; } catch (\Throwable $e) { $wpdb->query('ROLLBACK'); return new \WP_Error('exception', $e->getMessage()); } // end try; $wpdb->query('COMMIT'); return true; } // end async_delete_membership; } // end class Membership_Manager;