From d51ceead1ad337956072c5c8b3db7df5580f9b15 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 7 Jan 2022 13:46:48 -0500 Subject: [PATCH 01/15] feature: scaffold addition of legacy subscription files --- give.php | 45 +- src/DonationSummary/SummaryView.php | 2 +- .../Adapters/LegacyPaymentGatewayAdapter.php | 2 +- src/LegacySubscriptions/ServiceProvider.php | 91 + .../includes/give-recurring-ajax.php | 151 + .../includes/give-recurring-cache.php | 245 ++ .../includes/give-recurring-cron.php | 84 + .../give-recurring-db-subscription-meta.php | 75 + .../includes/give-recurring-emails.php | 463 +++ .../includes/give-recurring-expirations.php | 359 +++ .../includes/give-recurring-functions.php | 444 +++ .../give-recurring-gateway-factory.php | 84 + .../includes/give-recurring-helpers.php | 2627 +++++++++++++++++ .../includes/give-recurring-renewals.php | 311 ++ .../includes/give-recurring-shortcodes.php | 295 ++ .../includes/give-recurring-subscriber.php | 461 +++ .../includes/give-recurring-template.php | 347 +++ .../includes/give-subscription.php | 1225 ++++++++ .../includes/give-subscriptions-api.php | 272 ++ .../includes/give-subscriptions-db.php | 713 +++++ src/Subscriptions/ServiceProvider.php | 27 + 21 files changed, 8300 insertions(+), 23 deletions(-) create mode 100644 src/LegacySubscriptions/ServiceProvider.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-ajax.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-cache.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-cron.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-emails.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-expirations.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-functions.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-gateway-factory.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-helpers.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-renewals.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-shortcodes.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-subscriber.php create mode 100644 src/LegacySubscriptions/includes/give-recurring-template.php create mode 100644 src/LegacySubscriptions/includes/give-subscription.php create mode 100644 src/LegacySubscriptions/includes/give-subscriptions-api.php create mode 100644 src/LegacySubscriptions/includes/give-subscriptions-db.php create mode 100644 src/Subscriptions/ServiceProvider.php diff --git a/give.php b/give.php index c2eed23f8c..60dcb49065 100644 --- a/give.php +++ b/give.php @@ -49,6 +49,7 @@ use Give\Framework\Exceptions\UncaughtExceptionLogger; use Give\Framework\Migrations\MigrationsServiceProvider; use Give\InPluginUpsells\ServiceProvider as InPluginUpsellsServiceProvider; +use Give\LegacySubscriptions\ServiceProvider as LegacySubscriptionsServiceProvider; use Give\License\LicenseServiceProvider; use Give\Log\LogServiceProvider; use Give\MigrationLog\MigrationLogServiceProvider; @@ -77,28 +78,29 @@ * @since 2.8.0 build in a service container * @since 1.0 * - * @property-read Give_API $api - * @property-read Give_Async_Process $async_process - * @property-read Give_Comment $comment - * @property-read Give_DB_Donors $donors - * @property-read Give_DB_Donor_Meta $donor_meta - * @property-read Give_Emails $emails - * @property-read Give_Email_Template_Tags $email_tags - * @property-read Give_DB_Form_Meta $form_meta - * @property-read Give_Admin_Settings $give_settings - * @property-read Give_HTML_Elements $html - * @property-read Give_Logging $logs - * @property-read Give_Notices $notices - * @property-read Give_DB_Payment_Meta $payment_meta - * @property-read Give_Roles $roles - * @property-read FormRoute $routeForm - * @property-read Templates $templates - * @property-read Give_Scripts $scripts - * @property-read Give_DB_Sequential_Ordering $sequential_donation_db + * @property-read Give_API $api + * @property-read Give_Async_Process $async_process + * @property-read Give_Comment $comment + * @property-read Give_DB_Donors $donors + * @property-read Give_DB_Donor_Meta $donor_meta + * @property-read Give_Emails $emails + * @property-read Give_Email_Template_Tags $email_tags + * @property-read Give_DB_Form_Meta $form_meta + * @property-read Give_Admin_Settings $give_settings + * @property-read Give_HTML_Elements $html + * @property-read Give_Logging $logs + * @property-read Give_Notices $notices + * @property-read Give_DB_Payment_Meta $payment_meta + * @property-read Give_Roles $roles + * @property-read FormRoute $routeForm + * @property-read Templates $templates + * @property-read Give_Scripts $scripts + * @property-read Give_DB_Sequential_Ordering $sequential_donation_db * @property-read Give_Sequential_Donation_Number $seq_donation_number - * @property-read Give_Session $session - * @property-read Give_DB_Sessions $session_db - * @property-read Give_Tooltips $tooltips + * @property-read Give_Session $session + * @property-read Give_DB_Sessions $session_db + * @property-read Give_Tooltips $tooltips + * @property-read Give_Recurring_DB_Subscription_Meta $subscription_meta * * @mixin Container */ @@ -167,6 +169,7 @@ final class Give Give\Email\ServiceProvider::class, DonationSummaryServiceProvider::class, PaymentGatewaysServiceProvider::class, + LegacySubscriptionsServiceProvider::class ]; /** diff --git a/src/DonationSummary/SummaryView.php b/src/DonationSummary/SummaryView.php index 703ffe7463..31ee991d9a 100644 --- a/src/DonationSummary/SummaryView.php +++ b/src/DonationSummary/SummaryView.php @@ -119,7 +119,7 @@ protected function isFeeRecoveryEnabled() protected function isRecurringEnabled() { if (class_exists('\Give_Recurring')) { - return Give_Recurring()->is_recurring($this->formID); + return give_recurring_is_recurring($this->formID); } return false; diff --git a/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php b/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php index 3c7691b8f5..492b85ee70 100644 --- a/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php +++ b/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php @@ -53,7 +53,7 @@ public function handleBeforeGateway($legacyDonationData, $registeredGateway) if ( function_exists('Give_Recurring') && - Give_Recurring()->is_donation_recurring($formData->legacyDonationData) + give_recurring_is_donation_recurring($formData->legacyDonationData) ) { $subscriptionData = SubscriptionData::fromRequest($legacyDonationData); $subscriptionId = $this->createSubscription($donationId, $formData, $subscriptionData); diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php new file mode 100644 index 0000000000..cee3be4d0b --- /dev/null +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -0,0 +1,91 @@ +includeLegacyFiles(); + $this->bindClasses(); + } + + /** + * @inheritDoc + */ + public function boot() + { + } + + /** + * Load all the legacy class files since they don't have autoloading + * + * @unreleased + */ + private function includeLegacyFiles() + { + require_once __DIR__ . '/includes/give-subscriptions-db.php'; + require_once __DIR__ . '/includes/give-recurring-db-subscription-meta.php'; + require_once __DIR__ . '/includes/give-recurring-cache.php'; + require_once __DIR__ . '/includes/give-subscription.php'; + require_once __DIR__ . '/includes/give-subscriptions-api.php'; + require_once __DIR__ . '/includes/give-recurring-shortcodes.php'; + require_once __DIR__ . '/includes/give-recurring-subscriber.php'; + require_once __DIR__ . '/includes/give-recurring-template.php'; + require_once __DIR__ . '/includes/give-recurring-helpers.php'; + require_once __DIR__ . '/includes/give-recurring-functions.php'; + require_once __DIR__ . '/includes/give-recurring-emails.php'; + require_once __DIR__ . '/includes/give-recurring-renewals.php'; + require_once __DIR__ . '/includes/give-recurring-expirations.php'; + require_once __DIR__ . '/includes/give-recurring-cron.php'; + require_once __DIR__ . '/includes/give-recurring-gateway-factory.php'; + require_once __DIR__ . '/includes/give-recurring-ajax.php'; + } + + /** + * Binds the legacy classes to the service provider + * + * @unreleased + */ + private function bindClasses() + { + $this->bindInstance('subscription_meta', 'Give_Recurring_DB_Subscription_Meta', 'give-recurring-db-subscription-meta.php'); + } + + /** + * A helper for loading legacy classes that do not use autoloading, then binding their instance + * to the container. + * + * @unreleased + * + * @param string $alias + * @param string|Closure $class + * @param string $includesPath + * @param bool $singleton + */ + private function bindInstance($alias, $class, $includesPath, $singleton = false) + { + require_once __DIR__ . "/includes/$includesPath"; + + if ($class instanceof Closure) { + give()->instance($alias, $class()); + } elseif ($singleton) { + give()->instance($alias, $class::get_instance()); + } else { + give()->instance($alias, new $class()); + } + } +} diff --git a/src/LegacySubscriptions/includes/give-recurring-ajax.php b/src/LegacySubscriptions/includes/give-recurring-ajax.php new file mode 100644 index 0000000000..404a563ce0 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-ajax.php @@ -0,0 +1,151 @@ +hide_errors(); + } + } + + /** + * Send headers for Give Recurring Ajax Requests + */ + private static function give_recurring_ajax_headers() { + send_origin_headers(); + @header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); + @header( 'X-Robots-Tag: noindex' ); + send_nosniff_header(); + nocache_headers(); + status_header( 200 ); + } + + /** + * Check for Give Recurring Ajax request and fire action. + */ + public static function do_give_recurring_ajax() { + global $wp_query; + + if ( ! empty( $_GET['give-recurring-ajax'] ) ) { + $wp_query->set( 'give-recurring-ajax', sanitize_text_field( $_GET['give-recurring-ajax'] ) ); + } + + if ( $action = $wp_query->get( 'give-recurring-ajax' ) ) { + self::give_recurring_ajax_headers(); + do_action( 'give_recurring_ajax_' . sanitize_text_field( $action ) ); + die(); + } + } + + /** + * Hook in methods - uses WordPress ajax handlers (admin-ajax). + */ + public static function add_ajax_events() { + $ajax_events = array( + 'sync_subscription_details' => false, + 'sync_subscription_transactions' => false, + ); + + foreach ( $ajax_events as $ajax_event => $nopriv ) { + add_action( 'wp_ajax_give_recurring_' . $ajax_event, array( __CLASS__, $ajax_event ) ); + + if ( $nopriv ) { + add_action( 'wp_ajax_nopriv_give_recurring_' . $ajax_event, array( __CLASS__, $ajax_event ) ); + + // Give Recurring AJAX can be used for frontend ajax requests. + add_action( 'give_recurring_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) ); + } + } + } + + /** + * Sync subscription details. + */ + public static function sync_subscription_details() { + + check_ajax_referer( 'sync-subscription-details', 'security' ); + + $user_can_sync = current_user_can( 'update_plugins' ); + if ( !apply_filters('give_recurring_user_can_sync_transactions', $user_can_sync) ) { + die( -1 ); + } + + $subscription_id = absint( $_POST['subscription_id'] ); + $log_id = isset( $_POST['log_id'] ) ? absint( $_POST['log_id'] ) : 0; + + if ( $log_id ) { + Give_Recurring()->synchronizer->log_id = $log_id; + } + + $output = Give_Recurring()->synchronizer->sync_subscription_details( $subscription_id ); + + wp_send_json( $output ); + } + + /** + * Sync subscription transactions. + */ + public static function sync_subscription_transactions() { + + check_ajax_referer( 'sync-subscription-transactions', 'security' ); + + $user_can_sync = current_user_can( 'update_plugins' ); + if ( !apply_filters('give_recurring_user_can_sync_transactions', $user_can_sync) ) { + die( -1 ); + } + + $subscription_id = absint( $_POST['subscription_id'] ); + $log_id = isset( $_POST['log_id'] ) ? absint( $_POST['log_id'] ) : 0; + + if ( $log_id ) { + Give_Recurring()->synchronizer->log_id = $log_id; + } + + $output = Give_Recurring()->synchronizer->sync_subscription_transactions( $subscription_id ); + wp_send_json( $output ); + } +} + +Give_Recurring_AJAX::init(); diff --git a/src/LegacySubscriptions/includes/give-recurring-cache.php b/src/LegacySubscriptions/includes/give-recurring-cache.php new file mode 100644 index 0000000000..a1be30ba10 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-cache.php @@ -0,0 +1,245 @@ +sub_db = new Give_Subscriptions_DB(); + + add_action( 'give_subscription_inserted', array( $this, 'flush_on_subscription_insert' ) ); + add_action( 'give_subscription_deleted', array( $this, 'flush_on_subscription_delete' ), 10, 2 ); + add_action( 'give_subscription_updated', array( $this, 'flush_on_subscription_update' ), 10, 4 ); + add_action( 'give_cache_filter_group_name', array( $this, 'filter_group_name' ), 999, 2 ); + add_action( 'give_deleted_give-donations_cache', array( $this, 'flush_on_donation_edit' ), 10 ); + add_action( 'before_delete_post', array( $this, 'flush_on_donation_delete' ), 10 ); + } + + /** + * Filter the group name + * + * @param $filtered_group_name + * @param $group + * + * + * @return string + */ + public function filter_group_name( $filtered_group_name, $group ) { + if ( in_array( $group, $this->groups ) ) { + $incrementer = Give_Cache::get_instance()->get_incrementer( false, "{$group}-incrementer" ); + + $currenct_blog_id = get_current_blog_id(); + $filtered_group_name = "{$group}_{$currenct_blog_id}_{$incrementer}"; + } + + return $filtered_group_name; + } + + + /** + * Get instance. + * + * @since 1.6 + * @access public + * @return Give_Recurring_Cache + */ + public static function get_instance() { + if ( null === static::$instance ) { + self::$instance = new static(); + + self::$instance->setup(); + } + + return self::$instance; + } + + /** + * Set subscriptions cache + * + * @since 1.6 + * + * @param $cache_key + * @param $data + * + * @return bool + */ + public static function set_subscription( $cache_key, $data ) { + return Give_Cache::set_group( $cache_key, $data, 'give-subscriptions' ); + } + + /** + * Get subscriptions cache + * + * @since 1.6 + * + * @param $cache_key + * + * @return mixed + */ + public static function get_subscription( $cache_key ) { + return Give_Cache::get_group( $cache_key, 'give-subscriptions' ); + } + + /** + * Set subscriptions db query cache + * + * @since 1.6 + * + * @param $cache_key + * @param $data + * + * @return bool + */ + public static function set_db_query( $cache_key, $data ) { + return Give_Cache::set_group( $cache_key, $data, 'give-subscriptions-db-query' ); + } + + /** + * Get subscriptions query cache + * + * @since 1.6 + * + * @param $cache_key + * + * @return bool + */ + public static function get_db_query( $cache_key ) { + return Give_Cache::get_group( $cache_key, 'give-subscriptions-db-query' ); + } + + /** + * Delete subscription db query cache when new subscription creates + * + * @since 1.6 + */ + public function flush_on_subscription_insert() { + Give_Cache::get_instance()->get_incrementer( true, 'give-subscriptions-db-query-incrementer' ); + } + + /** + * Delete subscription cache when subscription deletes + * + * @since 1.6 + * + * @param $deleted + * @param $subscription_id + */ + public function flush_on_subscription_delete( $deleted, $subscription_id ) { + // Bailout. + if ( ! $deleted ) { + return; + } + + Give_Cache::delete_group( $subscription_id, 'give-subscriptions' ); + Give_Cache::get_instance()->get_incrementer( true, 'give-subscriptions-db-query-incrementer' ); + } + + /** + * Delete subscription cache when subscription updates + * + * @since 1.6 + * + * @param $updated + * @param $subscription_id + * @param $data + * @param $where + */ + public function flush_on_subscription_update( $updated, $subscription_id, $data, $where ) { + // Bailout. + if ( ! $updated ) { + return; + } + + if ( empty( $where ) ) { + Give_Cache::delete_group( $subscription_id, 'give-subscriptions' ); + } else { + Give_Cache::get_instance()->get_incrementer( true, 'give-subscriptions-incrementer' ); + } + + Give_Cache::get_instance()->get_incrementer( true, 'give-subscriptions-db-query-incrementer' ); + } + + + /** + * Delete subscription cache when donation update/insert + * + * @since 1.6 + * + * @param int $donation_id + */ + public function flush_on_donation_edit( $donation_id ) { + $donation = get_post( $donation_id ); + + // Bailout. + if ( ! $donation instanceof WP_Post ) { + return; + } + + $subscription_id = $donation->post_parent + ? $this->sub_db->get_column_by( 'id', 'parent_payment_id', $donation->post_parent ) + : give_get_meta( $donation_id, 'subscription_id', true ); + + if ( $subscription_id ) { + Give_Cache::delete_group( $subscription_id, 'give-subscriptions' ); + Give_Cache::get_instance()->get_incrementer( true, 'give-subscriptions-db-query-incrementer' ); + } + } + + /** + * Delete subscription cache when donation delete + * + * @since 1.6 + * + * @param int $donation_id + */ + public function flush_on_donation_delete( $donation_id ) { + $this->flush_on_donation_edit( $donation_id ); + } +} + +Give_Recurring_Cache::get_instance(); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-cron.php b/src/LegacySubscriptions/includes/give-recurring-cron.php new file mode 100644 index 0000000000..2b93ae5f17 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-cron.php @@ -0,0 +1,84 @@ +init(); + } + + /** + * Set up our actions and properties + * + * @since 1.0 + */ + public function init() { + + $this->db = new Give_Subscriptions_DB; + + add_action( 'give_daily_scheduled_events', array( $this, 'check_for_expired_subscriptions' ) ); + add_action( 'give_weekly_scheduled_events', array( $this, 'delete_old_sync_logs' ) ); + } + + /** + * Check for expired subscriptions once per day and mark them as expired + * + * @since 1.0 + */ + public function check_for_expired_subscriptions() { + + $args = array( + 'status' => 'active', + 'number' => 999999, + 'expiration' => array( + 'start' => date( 'Y-n-d 00:00:00', strtotime( '-1 day', current_time( 'timestamp' ) ) ), + 'end' => date( 'Y-n-d 23:59:59', strtotime( '-1 day', current_time( 'timestamp' ) ) ) + ) + + ); + + $subs = $this->db->get_subscriptions( $args ); + + if ( ! empty( $subs ) ) { + + foreach ( $subs as $sub ) { + + // TODO: Run sync here. + + } + + } + + } + + /** + * Deletes old Sync log data. + * + * @since 1.3 + */ + public function delete_old_sync_logs() { + + } +} diff --git a/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php b/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php new file mode 100644 index 0000000000..64c71f309e --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php @@ -0,0 +1,75 @@ +subscriptionmeta = $this->table_name = $wpdb->prefix . 'give_subscriptionmeta'; + $this->primary_key = 'meta_id'; + $this->version = '1.0'; + + parent::__construct(); + } + + /** + * Get table columns and data types. + * + * @access public + * @since 1.8 + * + * @return array Columns and formats. + */ + public function get_columns() { + return array( + 'meta_id' => '%d', + 'subscription_id' => '%d', + 'meta_key' => '%s', + 'meta_value' => '%s', + ); + } +} diff --git a/src/LegacySubscriptions/includes/give-recurring-emails.php b/src/LegacySubscriptions/includes/give-recurring-emails.php new file mode 100644 index 0000000000..8a3e45aa53 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-emails.php @@ -0,0 +1,463 @@ +init(); + } + + /** + * Initialize Give_Recurring_Emails + */ + public function init() { + + add_action( 'give_email_tags', array( $this, 'setup_email_tags' ) ); + } + + /** + * Send Reminder. + * + * Responsible for sending both `renewal` and `expiration` notices. + * + * @param string $reminder_type required - values of `expiration` or `renewal`. + * @param int $subscription_id required + * @param int $notice_id + */ + public function send_reminder( $reminder_type, $subscription_id = 0, $notice_id = 0 ) { + + $stored_notices = get_option( 'give_recurring_reminder_notices', array() ); + $content_type = $stored_notices[ $notice_id ]['content_type']; + + // Sanity check: Do we have the required subscription ID? + if ( empty( $subscription_id ) || empty( $reminder_type ) ) { + return; + } + + // Get subscription. + $this->subscription = new Give_Subscription( $subscription_id ); + + // Sanity check: Check for it + if ( empty( $this->subscription ) ) { + return; + } + + // What type of reminder email is this? (renewal or expiration) + $reminder = $reminder_type == 'renewal' + ? Give_Recurring_Renewal_Reminders::get_instance() + : Give_Recurring_Expiration_Reminders::get_instance(); + + // Sanity check: Are these reminder emails activated? + if ( ! $reminder->reminders_allowed() ) { + return; + } + + $user = get_user_by( 'id', $this->subscription->donor->user_id ); + $send = (bool) apply_filters( 'give_recurring_send_' . $reminder_type . '_reminder', true, $subscription_id, $notice_id, $user ); + + // Do not send email if revoked. + if( ! $send ) { + return; + } + + $email_to = $this->subscription->donor->email; + + // Form appropriate email depending on reminder type. + if ( $reminder_type == 'renewal' ) { + // Renewing. + $notice = $reminder->get_renewal_notice( $notice_id ); + $message = ! empty( $notice['message'] ) ? $notice['message'] : __( "Hello {name},\n\nYour subscription for {subscription_name} will renew on {expiration}.", 'give-recurring' ); + $subject = ! empty( $notice['subject'] ) ? $notice['subject'] : __( 'Your Subscription is About to Renew', 'give-recurring' ); + + } else { + // Expiring. + $notice = $reminder->get_expiration_notice( $notice_id ); + $message = ! empty( $notice['message'] ) ? $notice['message'] : __( "Hello {name},\n\nYour subscription for {subscription_name} will expire on {expiration}.", 'give-recurring' ); + $subject = ! empty( $notice['subject'] ) ? $notice['subject'] : __( 'Your Subscription is About to Expire', 'give-recurring' ); + } + + // Filter template tags. + Give()->emails->__set( 'heading', give_do_email_tags( $notice['header'], $this->subscription->parent_payment_id ) ); + $subject = $this->filter_template_tags( $subject, $this->subscription ); + $message = $this->filter_template_tags( $message, $this->subscription ); + $message = ( 'text/plain' === $content_type ) ? wp_strip_all_tags( $message ) : $message; + + $sent = Give()->emails->send( $email_to, $subject, $message ); + + // Log the email if it indeed sent. + if ( $sent ) { + $this->log_recurring_email( $reminder_type, $this->subscription, $subject, $notice ); + } + + } + + /** + * Log recurring email. + * + * When an email is sent by the plugin, log it with Give. + * + * @since 1.12.2 switch to new Log facade + * + * @param string $email_type + * @param Give_Subscription $subscription + * @param $subject string + * @param int $notice_id + * @param $notice array of the email including subj, send period, etc. Used for reminder emails + */ + public static function log_recurring_email( $email_type, $subscription, $subject, $notice_id = 0, $notice = array() ) { + // Dynamic log title based on $email_type + $log_title = __( 'LOG - Subscription ' . ucfirst( $email_type ) . ' Email Sent', 'give-recurring' ); + + Log::notice($log_title, [ + 'category' => 'Recurring Donations', + 'source' => 'Email Logs', + 'Customer ID' => $subscription->donor_id, + 'Subscription ID' => $subscription->id , + 'Email Subject' => $subject + ]); + + // Is there a notice ID for this email? + if ( $notice_id > 0 && ! empty( $notice ) ) { + // Prevent reminder notices from being sent more than once + add_user_meta( $subscription->donor->user_id, sanitize_key( '_give_recurring_' . $email_type . '_' . $subscription->id . '_sent_' . $notice['send_period'] ), time() ); + } + } + + /** + * Email reminder template tag. + * + * @deprecated Use $this->filter_email_tags() + * + * @param string $content + * @param Give_Subscription $subscription + * + * @return mixed|string + */ + public function filter_template_tags( $content = '', $subscription ) { + + $payment_id = $subscription->parent_payment_id; + $payment_meta = give_get_payment_meta( $payment_id ); + $expiration_timestamp = strtotime( $subscription->expiration ); + $interval = ! empty( $subscription->frequency ) ? $subscription->frequency : 1; + + if ( isset( $this->tags ) && ! is_null( $this->tags ) && ! empty( $this->tags ) ) { + + foreach ( $this->tags as $email_tag ) { + + switch ( $email_tag ) : + case 'renewal_link': + $content = str_replace( '{renewal_link}', ' ' . $payment_meta['form_title'] . '', $content ); + break; + case 'completion_date': + $content = str_replace( '{completion_date}', date_i18n( give_date_format(), $expiration_timestamp ), $content ); + break; + case 'subscription_frequency': + $times = (int) $subscription->bill_times; + $content = str_replace( '{subscription_frequency}', give_recurring_pretty_subscription_frequency( $subscription->period, $times, false, $interval + ), $content ); + break; + case 'subscriptions_completed': + $content = str_replace( '{subscriptions_completed}', $subscription->get_subscription_progress(), $content ); + break; + case 'cancellation_date': + $content = str_replace( '{cancellation_date}', date_i18n( give_date_format(), current_time( 'timestamp' ) ), $content ); + break; + endswitch; + + } + } + + // Filter email content through Give core as well. + $content = give_do_email_tags( $content, $payment_id ); + + return apply_filters( 'give_recurring_filter_template_tags', $content ); + + } + + /** + * filter the email tag content. + * + * @access public + * + * @param array $tag_args + * @param string $email_tag + * + * @return string + */ + public static function filter_email_tags( $tag_args, $email_tag ) { + + $subscription_id = 0; + if ( ! empty( $tag_args['subscription_id'] ) ) { + $subscription_id = $tag_args['subscription_id']; + } elseif ( ! empty( $tag_args['payment_id'] ) ) { + $subscription_id = give_recurring_get_subscription_by( 'payment', $tag_args['payment_id'] ); + } + + // Return "n/a" for one-time (non-recurring) donations for all email tags besides frequency which will return "One Time" text. + if ( empty( $subscription_id ) && 'subscription_frequency' !== $email_tag ) { + return apply_filters( 'give_recurring_one_time_filter_template_tags', __( 'n/a', 'give-recurring' ) ); + } + + /* @var Give_Subscription $subscription */ + $subscription = new Give_Subscription( $subscription_id ); + $payment_meta = give_get_payment_meta( $subscription->parent_payment_id ); + $expiration_timestamp = strtotime( $subscription->expiration ); + $interval = ! empty( $subscription->frequency ) ? $subscription->frequency : 1; + $content = ''; + + // Replace template tags with actual content. + switch ( $email_tag ) : + case 'renewal_link': + $content = str_replace( + '%2$s', + get_permalink( $payment_meta['form_id'] ), + $payment_meta['form_title'] + ); + break; + + case 'completion_date': + $content = date_i18n( give_date_format(), $expiration_timestamp ); + break; + + case 'subscription_frequency': + $times = (int) $subscription->bill_times; + $content = give_recurring_pretty_subscription_frequency( $subscription->period, $times, false, $interval ); + break; + + case 'subscriptions_completed': + $content = $subscription->get_subscription_progress(); + break; + + case 'cancellation_date': + $content = date_i18n( give_date_format(), current_time( 'timestamp' ) ); + break; + + case 'renewal_date': + case 'expiration_date': + $content = date( give_date_format(), strtotime( $subscription->expiration ) ); + break; + endswitch; + + return apply_filters( 'give_recurring_filter_template_tags', $content, $tag_args, $email_tag ); + } + + /** + * This function is used to setup new email tags for recurring add-on. + * + * @param array $email_tags List of email tags. + * + * @since 1.8.5 + * @access public + * + * @return array + */ + public function setup_email_tags( $email_tags ) { + + $email_tags[] = array( + 'tag' => 'subscriptions_link', + 'desc' => esc_html__( 'The donor\'s email access link for subscription history.', 'give-recurring' ), + 'func' => array( $this, 'email_tag_subscription_history_link' ), + 'context' => 'donor', + ); + + $email_tags[] = array( + 'tag' => 'next_payment_attempt', + 'desc' => esc_html__( 'The date and time when the next payment attempt will be made.', 'give-recurring' ), + 'func' => array( $this, 'email_tag_next_payment_attempt_date' ), + 'context' => 'donor', + ); + + $email_tags[] = array( + 'tag' => 'update_payment_method_link', + 'desc' => esc_html__( 'The link to update the payment method of the subscription.', 'give-recurring' ), + 'func' => array( $this, 'email_tag_update_payment_method_link' ), + 'context' => 'donor', + ); + + return $email_tags; + } + + /** + * Email template tag: {subscriptions_link} + * + * @since 1.8.5 + * @access public + * + * @param array $tag_args Email Tag Arguments. + * + * @return string + */ + public function email_tag_subscription_history_link( $tag_args ) { + + $donor_id = 0; + $donor = array(); + $link = ''; + + // Backward compatibility. + $tag_args = __give_20_bc_str_type_email_tag_param( $tag_args ); + + switch ( true ) { + + case ! empty( $tag_args['payment_id'] ): + $donor_id = Give()->payment_meta->get_meta( $tag_args['payment_id'], '_give_payment_donor_id', true ); + $donor = Give()->donors->get_by( 'id', $donor_id ); + break; + + case ! empty( $tag_args['donor_id'] ): + $donor_id = $tag_args['donor_id']; + $donor = Give()->donors->get_by( 'id', $tag_args['donor_id'] ); + break; + + case ! empty( $tag_args['user_id'] ): + $donor = Give()->donors->get_by( 'user_id', $tag_args['user_id'] ); + $donor_id = $donor->id; + break; + } + + // Set email access link if donor exist. + if ( $donor_id ) { + $verify_key = wp_generate_password( 20, false ); + + // Generate a new verify key. + Give()->email_access->set_verify_key( $donor_id, $donor->email, $verify_key ); + + // update verify key in email tags. + $tag_args['verify_key'] = $verify_key; + + // update donor id in email tags. + $tag_args['donor_id'] = $donor_id; + + $access_url = add_query_arg( + array( + 'give_nl' => $verify_key, + ), + give_get_subscriptions_page_uri() + ); + + // Add donation id to email access url, if it exists. + $donation_id = give_clean( filter_input( INPUT_GET, 'donation_id' ) ); + if ( ! empty( $donation_id ) ) { + $access_url = add_query_arg( + array( + 'donation_id' => $donation_id, + ), + $access_url + ); + } + + if ( empty( $tag_args['email_content_type'] ) || 'text/html' === $tag_args['email_content_type'] ) { + $link = sprintf( + '%2$s', + esc_url( $access_url ), + __( 'View your subscription history »', 'give-recurring' ) + ); + + } else { + + $link = sprintf( + '%1$s: %2$s', + __( 'View your subscription history', 'give-recurring' ), + esc_url( $access_url ) + ); + } + } // End if(). + + /** + * Filter the {subscriptions_link} email template tag output. + * + * @since 1.8.5 + * + * @param string $receipt_link_url + * @param array $tag_args + */ + return apply_filters( + 'give_recurring_email_tag_subscription_history_link', + $link, + $tag_args + ); + } + + /** + * Email tag for next payment attempt. + * + * @param array $tag_args List of Email Tag arguments. + * + * @since 1.9.0 + * @access public + * + * @return string + */ + public function email_tag_next_payment_attempt_date( $tag_args ) { + + $date_format = get_option( 'date_format' ); + $time_format = get_option( 'time_format' ); + $date_time_format = "{$date_format} {$time_format}"; + $next_payment_attempt = ! empty( $tag_args['next_payment_attempt'] ) ? date_i18n( $date_time_format, $tag_args['next_payment_attempt'] ) : false; + + /** + * Filter for next payment attempt date. + * + * @param string $next_payment_attempt Next Payment Attempt Date. + * + * @since 1.9.0 + */ + return apply_filters( 'give_recurring_email_tag_next_payment_attempt_date', $next_payment_attempt ); + } + + /** + * Email tag containing the link to update the payment method of an active subscription. + * + * @param array $tag_args List of email tag arguments. + * + * @since 1.9.0 + * @access public + * + * @return mixed + */ + public function email_tag_update_payment_method_link( $tag_args ) { + + $subscription_id = ! empty( $tag_args['subscription_id'] ) ? $tag_args['subscription_id'] : 0; + + return sprintf( + '%2$s', + add_query_arg( + array( + 'action' => 'update', + 'subscription_id' => $subscription_id, + ), + give_get_subscriptions_page_uri() + ), + __( 'Update Payment Method', 'give-recurring' ) + ); + } +} diff --git a/src/LegacySubscriptions/includes/give-recurring-expirations.php b/src/LegacySubscriptions/includes/give-recurring-expirations.php new file mode 100644 index 0000000000..c8c93f2930 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-expirations.php @@ -0,0 +1,359 @@ +setup(); + } + + return self::$instance; + } + + + /** + * Setup + * + * @since 1.7 + * @access private + */ + private function setup(){ + add_action( 'give_daily_scheduled_events', array( $this, 'scheduled_expiration_reminders' ) ); + } + + /** + * Returns if expirations are enabled + * + * @return bool True if enabled, false if not + */ + public function reminders_allowed() { + + $expiration_reminder = give_get_option('recurring_send_expiration_reminders'); + + return ( 'enabled' === $expiration_reminder ) ? true : false; + } + + /** + * Retrieve expiration notices + * + * @return array Renewal notice periods + */ + public function get_expiration_notice_periods() { + $periods = array( + '+1day' => __( 'One day before expiration', 'give-recurring' ), + '+2days' => __( 'Two days before expiration', 'give-recurring' ), + '+3days' => __( 'Three days before expiration', 'give-recurring' ), + '+1week' => __( 'One week before expiration', 'give-recurring' ), + '+2weeks' => __( 'Two weeks before expiration', 'give-recurring' ), + '+1month' => __( 'One month before expiration', 'give-recurring' ), + '+2months' => __( 'Two months before expiration', 'give-recurring' ), + '+3months' => __( 'Three months before expiration', 'give-recurring' ), + 'expired' => __( 'At the time of expiration', 'give-recurring' ), + '-1day' => __( 'One day after expiration', 'give-recurring' ), + '-2days' => __( 'Two days after expiration', 'give-recurring' ), + '-3days' => __( 'Three days after expiration', 'give-recurring' ), + '-1week' => __( 'One week after expiration', 'give-recurring' ), + '-2weeks' => __( 'Two weeks after expiration', 'give-recurring' ), + '-1month' => __( 'One month after expiration', 'give-recurring' ), + '-2months' => __( 'Two months after expiration', 'give-recurring' ), + '-3months' => __( 'Three months after expiration', 'give-recurring' ), + ); + + return apply_filters( 'get_expiration_notice_periods', $periods ); + } + + /** + * Retrieve the expiration label for a notice + * + * @param int $notice_id + * + * @return string + */ + public function get_expiration_notice_period_label( $notice_id = 0 ) { + + $notice = $this->get_expiration_notice( $notice_id ); + $periods = $this->get_expiration_notice_periods(); + $label = $periods[ $notice['send_period'] ]; + + return apply_filters( 'get_expiration_notice_period_label', $label, $notice_id ); + } + + /** + * Retrieve a expiration notice + * + * @param int $notice_id + * + * @return array|mixed|void Renewal notice details + */ + public function get_expiration_notice( $notice_id = 0 ) { + + $notices = $this->get_expiration_notices(); + + $defaults = array( + 'subject' => __( 'Your Subscription is About to Expire', 'give-recurring' ), + 'send_period' => '+1day', + 'message' => 'Hello {name}, + + Your subscription for {subscription_name} will expire on {expiration}. + + Click here to renew: {renewal_link}' + + ); + + $notice = isset( $notices[ $notice_id ] ) ? $notices[ $notice_id ] : $notices[0]; + + $notice = wp_parse_args( $notice, $defaults ); + + return apply_filters( 'give_recurring_expiration_notice', $notice, $notice_id ); + + } + + /** + * Retrieve expiration notice periods + * + * @return array Renewal notices defined in settings + */ + public function get_expiration_notices() { + $notices = get_option( 'give_recurring_reminder_notices', array() ); + + if ( empty( $notices ) ) { + + $message = 'Hello {name}, + + Your subscription for {subscription_name} will expire on {expiration}. + + Click here to renew: {renewal_link}'; + + $notices[0] = array( + 'send_period' => '+1day', + 'subject' => __( 'Your Subscription is About to Expire', 'give-recurring' ), + 'message' => $message + ); + + } + + return apply_filters( 'get_expiration_notices', $notices ); + } + + + /** + * This is the actual process that takes place when the CRON job + * schedules renewal reminders. + * + * @param array $notices The email notices array. + * @param Give_Recurring_Emails $give_recurring_emails Give_Recurring_Email object. + * + * @since 1.6 + * + * @return void + */ + public function reminder_process( $notices, $give_recurring_emails ) { + + /** + * This loop will loop through all the notices, both + * renewal and expiration. + */ + foreach ( $notices as $notice_id => $notice ) { + + /** + * If notice email is disabled, then continue. + */ + if ( 'disabled' === $notice['status'] ) { + continue; + } + + + /** + * This file is responsible for sending out emails for expirations, + * so we skip if the 'notice_type' is set to 'renewal'. + */ + if ( 'renewal' === $notice['notice_type'] ) { + continue; + } + + + /** + * Get all the subscriptions which will be renewed in the next + * `$notice['send_period']` time. + * + * This can be -1day, +1day, -1month, +1month, +2month, etc. + */ + $subscriptions = $this->get_expiring_subscriptions( $notice['send_period'] ); + + + /** + * If there are no such subscriptions, then check for the next + * notice. + */ + if ( ! $subscriptions ) { + continue; + } + + + foreach ( $subscriptions as $subscription ) { + + /** + * Get the payment ID of the parent payment. + */ + $parent_payment_id = $subscription->parent_payment_id; + + + /** + * Get the gateway of the payment. + */ + $gateway = give_get_payment_meta( $parent_payment_id, '_give_payment_gateway' ); + + + /** + * Don't send the email if the gateway is found + * in the exclusion list. + */ + if ( ! empty( $notice['gateway'] ) && in_array( $gateway, $notice['gateway'], true ) ) { + continue; + } + + + /* Translate each subscription into a user_id and utilize + * the usermeta to store last renewal sent. + */ + $give_subscription = new Give_Subscription( $subscription->id ); + + $sent_time = get_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_expiration_' . $subscription->id . '_sent_' . $notice['send_period'] ), true ); + + if ( $sent_time ) { + + $renew_date = strtotime( $notice['send_period'], $sent_time ); + + if ( time() < $renew_date ) { + continue; + } + + delete_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_expiration_' . $subscription->id . '_sent_' . $notice['send_period'] ) ); + + } + + $give_recurring_emails->send_reminder( 'expiration', $subscription->id, $notice_id ); + } + } + } + + + /** + * Send reminder emails + * + * @return void + */ + public function scheduled_expiration_reminders() { + + if ( ! $this->reminders_allowed() ) { + return; + } + + + /** + * This will be used to setup the sending of the email. + */ + $give_recurring_emails = new Give_Recurring_Emails; + + + /** + * Gets all the recurring email notices. + * This includes email notices for both + * renewal and expiration. + */ + $notices = $this->get_expiration_notices(); + + + /** + * This handles sending out emails to donors. + */ + $this->reminder_process( $notices, $give_recurring_emails ); + } + + + /** + * Retrieve expiration notice periods + * + * @param string $period + * + * @return array|bool|mixed|null|object Subscribers whose subscriptions are expiring within the defined period + */ + public function get_expiring_subscriptions( $period = '+1month' ) { + + $subs_db = new Give_Subscriptions_DB(); + $subscriptions = $subs_db->get_expiring_subscriptions( $period ); + + if ( ! empty( $subscriptions ) ) { + return $subscriptions; + } + + return false; + } + + /** + * Retrieve renewal notice periods + * + * @return array Renewal notices defined in settings + */ + public function get_renewal_notices() { + $notices = get_option( 'give_recurring_reminder_notices', array() ); + + if ( empty( $notices ) ) { + + $message = 'Hello {name}, + + Your subscription for {subscription_name} will renew on {expiration}.'; + + $notices[0] = array( + 'send_period' => '+1day', + 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), + 'message' => $message, + ); + + } + + return apply_filters( 'get_renewal_notices', $notices ); + } +} + +Give_Recurring_Expiration_Reminders::get_instance(); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-functions.php b/src/LegacySubscriptions/includes/give-recurring-functions.php new file mode 100644 index 0000000000..2206e8210e --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-functions.php @@ -0,0 +1,444 @@ + $subscription_id, + 'order' => 'ASC', + 'search' => $search, + 'type' => 'give_sub_note', + ) + ); + + add_action( 'pre_get_comments', 'give_hide_subscription_notes', 10 ); + add_filter( 'comments_clauses', 'give_hide_subscription_notes_pre_41', 10, 2 ); + + return $notes; +} + +/** + * Add a note to a subscription. + * + * @param int $subscription_id The subscription ID to store a note for. + * @param string $note The note to store. + * + * @since 1.8 + * + * @return int The new note ID + */ +function give_insert_subscription_note( $subscription_id = 0, $note = '' ) { + if ( empty( $subscription_id ) ) { + return false; + } + + /** + * Fires before inserting subscription note. + * + * @param int $subscription_id Subscription ID. + * @param string $note The note. + * + * @since 1.8 + */ + do_action( 'give_pre_insert_subscription_note', $subscription_id, $note ); + + $note_id = wp_insert_comment( + wp_filter_comment( + array( + 'comment_post_ID' => $subscription_id, + 'comment_content' => $note, + 'user_id' => is_admin() ? get_current_user_id() : 0, + 'comment_date' => current_time( 'mysql' ), + 'comment_date_gmt' => current_time( 'mysql', 1 ), + 'comment_approved' => 1, + 'comment_parent' => 0, + 'comment_author' => '', + 'comment_author_IP' => '', + 'comment_author_url' => '', + 'comment_author_email' => '', + 'comment_type' => 'give_sub_note', + + ) + ) + ); + + /** + * Fires after payment note inserted. + * + * @param int $note_id Note ID. + * @param int $subscription_id Subscription ID. + * @param string $note The note. + * + * @since 1.8 + */ + do_action( 'give_insert_subscription_note', $note_id, $subscription_id, $note ); + + return $note_id; +} + +/** + * Deletes a subscription note. + * + * @param int $comment_id The comment ID to delete. + * @param int $subscription_id The subscription ID the note is connected to. + * + * @since 1.0 + * + * @return bool True on success, false otherwise. + */ +function give_delete_subscription_note( $comment_id = 0, $subscription_id = 0 ) { + if ( empty( $comment_id ) ) { + return false; + } + + /** + * Fires before deleting donation note. + * + * @param int $comment_id Note ID. + * @param int $subscription_id Subscription ID. + * + * @since 1.8 + */ + do_action( 'give_pre_delete_subscription_note', $comment_id, $subscription_id ); + + $ret = wp_delete_comment( $comment_id, true ); + + /** + * Fires after donation note deleted. + * + * @param int $comment_id Note ID. + * @param int $subscription_id Subscription ID. + * + * @since 1.8 + */ + do_action( 'give_post_delete_subscription_note', $comment_id, $subscription_id ); + + return $ret; +} + +/** + * Gets the subscription note HTML + * + * @param object|int $note The comment object or ID. + * @param int $subscription_id The subscription ID the note is connected to. + * + * @since 1.8 + * + * @return string + */ +function give_get_subscription_note_html( $note, $subscription_id = 0 ) { + + if ( is_numeric( $note ) ) { + $note = get_comment( $note ); + } + + if ( ! empty( $note->user_id ) ) { + $user = get_userdata( $note->user_id ); + $user = $user->display_name; + } else { + $user = __( 'System', 'give-recurring' ); + } + + $date_format = give_date_format() . ', ' . get_option( 'time_format' ); + + $note_html = '
'; + $note_html .= '

'; + $note_html .= '' . $user . ' – ' . date_i18n( $date_format, strtotime( $note->comment_date ) ) . '
'; + $note_html .= $note->comment_content; + $note_html .= ' – ' . __( 'Delete', 'give-recurring' ) . ''; + $note_html .= '

'; + $note_html .= '
'; + + return $note_html; + +} + +/** + * Exclude notes (comments) on subscription notes from showing in Recent + * Comments widgets + * + * @param object $query WordPress Comment Query Object. + * + * @since 1.8 + * + * @return void + */ +function give_hide_subscription_notes( $query ) { + if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) { + $types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array(); + if ( ! is_array( $types ) ) { + $types = array( $types ); + } + $types[] = 'give_sub_note'; + $query->query_vars['type__not_in'] = $types; + } +} + +add_action( 'pre_get_comments', 'give_hide_subscription_notes', 10 ); + +/** + * Exclude notes (comments) on give_sub_note post type from showing in Recent Comments widgets + * + * @param array $clauses Comment clauses for comment query. + * @param object $wp_comment_query WordPress Comment Query Object. + * + * @since 1.8 + * + * @return array $clauses Updated comment clauses. + */ +function give_hide_subscription_notes_pre_41( $clauses, $wp_comment_query ) { + if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) { + $clauses['where'] .= ' AND comment_type != "give_sub_note"'; + } + + return $clauses; +} + +add_filter( 'comments_clauses', 'give_hide_subscription_notes_pre_41', 10, 2 ); + +/** + * Exclude notes (comments) give_subscription_note from showing in comment feeds + * + * @param string $where + * @param object $wp_comment_query WordPress Comment Query Object. + * + * @since 1.8 + * + * @return string $where + */ +function give_hide_subscription_notes_from_feeds( $where, $wp_comment_query ) { + global $wpdb; + + $where .= $wpdb->prepare( ' AND comment_type != %s', 'give_sub_note' ); + + return $where; +} + +add_filter( 'comment_feed_where', 'give_hide_subscription_notes_from_feeds', 10, 2 ); + +/** + * Remove Give Comments from the wp_count_comments function + * + * @param array $stats (empty from core filter). + * @param int $post_id Post ID. + * + * @access public + * @since 1.8 + * + * @return array|object Array of comment counts. + */ +function give_remove_subscription_notes_in_comment_counts( $stats, $post_id ) { + global $wpdb, $pagenow; + + if ( 'index.php' !== $pagenow ) { + return $stats; + } + + $post_id = (int) $post_id; + + if ( apply_filters( 'give_count_subscription_notes_in_comments', false ) ) { + return $stats; + } + + $stats = Give_Cache::get_group( "comments-{$post_id}", 'counts' ); + + if ( ! is_null( $stats ) ) { + return $stats; + } + + $where = 'WHERE comment_type != "give_sub_note"'; + + if ( $post_id > 0 ) { + $where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id ); + } + + $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A ); + + $total = 0; + $approved = array( + '0' => 'moderated', + '1' => 'approved', + 'spam' => 'spam', + 'trash' => 'trash', + 'post-trashed' => 'post-trashed', + ); + foreach ( (array) $count as $row ) { + // Don't count post-trashed toward totals. + if ( 'post-trashed' !== $row['comment_approved'] && 'trash' !== $row['comment_approved'] ) { + $total += $row['num_comments']; + } + if ( isset( $approved[ $row['comment_approved'] ] ) ) { + $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments']; + } + } + + $stats['total_comments'] = $total; + foreach ( $approved as $key ) { + if ( empty( $stats[ $key ] ) ) { + $stats[ $key ] = 0; + } + } + + $stats = (object) $stats; + Give_Cache::set_group( "comments-{$post_id}", $stats, 'counts' ); + + return $stats; +} + +add_filter( 'wp_count_comments', 'give_remove_subscription_notes_in_comment_counts', 10, 2 ); + +/** + * AJAX Store subscription Note. + */ +function give_ajax_store_subscription_note() { + + $subscription_id = absint( $_POST['subscription_id'] ); + $note = wp_kses( $_POST['note'], array() ); + + if ( empty( $subscription_id ) ) { + die( '-1' ); + } + + if ( empty( $note ) ) { + die( '-1' ); + } + + $note_id = give_insert_subscription_note( $subscription_id, $note ); + die( give_get_subscription_note_html( $note_id ) ); +} + +add_action( 'wp_ajax_give_insert_subscription_note', 'give_ajax_store_subscription_note' ); + +/** + * Delete a subscription note deletion with ajax. + * + * @since 1.8 + * + * @return void + */ +function give_ajax_delete_subscription_note() { + + // Gather POST variables data. + $post_data = give_clean( $_POST ); + + // Security Check. + check_admin_referer( 'give_recurring_admin_ajax_secure_nonce', 'security' ); + + // Permission Check. + if ( ! current_user_can( 'delete_give_payments' ) ) { + $permission_notice = Give()->notices->print_admin_notices( array( + 'id' => 'give-permission-error', + 'description' => __( 'You are not permitted to delete the subscription note.', 'give-recurring' ), + 'echo' => false, + 'notice_type' => 'error', + ) ); + wp_send_json_error( $permission_notice ); + } + + // Send success JSON response, if subscription note deleted successfully. + if ( give_delete_subscription_note( $post_data['note_id'], $post_data['subscription_id'] ) ) { + wp_send_json_success(); + } + + // Else send JSON error response. + $deletion_error_notice = Give()->notices->print_admin_notices( array( + 'id' => 'give-permission-error', + 'description' => __( 'Unable to delete subscription note. Please try again.', 'give-recurring' ), + 'echo' => false, + 'notice_type' => 'error', + ) ); + wp_send_json_error( $deletion_error_notice ); + +} + +add_action( 'wp_ajax_give_delete_subscription_note', 'give_ajax_delete_subscription_note' ); + +/** + * This filter will be used to trigger email access on subscriptions page to store email access session. + * + * @since 1.8.5 + */ +function give_recurring_check_email_access_on_subscription_page( $status ) { + + return ( give_recurring_is_subscriptions_page() || $status ); +} + +add_filter( 'give_is_email_access_on_page', 'give_recurring_check_email_access_on_subscription_page' ); + +/** + * Get table list + * + * @since 1.9.0 + * @return array + */ +function give_recurring_get_tables() { + return array( + 'subscription' => new Give_Subscriptions_DB(), + 'subscription_meta' => new Give_Recurring_DB_Subscription_Meta(), + ); +} + + +/** + * Register plugin tables + * + * @sinc 1.9.0 + */ +function give_recurring_register_tables(){ + $tables = give_recurring_get_tables(); + + /* @var Give_DB $table */ + foreach ( $tables as $table ) { + if( ! $table->installed() ) { + $table->register_table(); + } + } +} + + +/** + * Update a subscription as abandoned if the payment is abandoned. + * + * @since 1.12.3 + * + * @param \Give_Payment $payment + */ +function give_recurring_update_abandoned_subscription( $payment ) { + + $db = new Give_Subscriptions_DB; + $results = $db->get_subscriptions([ + 'parent_payment_id' => $payment->ID, + ]); + + if ( $results ) { + // Only one subscription should be returned, but the return value is an array. + foreach ( $results as $result ) { + $subscription = new \Give_Subscription( $result->id ); + // Using the Give_Subscription API to update the status will also add a note to the record. + $subscription->update([ 'status' => 'abandoned' ]); + } + } +} +add_action( 'give_post_abandoned_payment', 'give_recurring_update_abandoned_subscription' ); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php b/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php new file mode 100644 index 0000000000..49973795bd --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php @@ -0,0 +1,84 @@ +gateway; + + } elseif ( is_numeric( $subscription ) ) { + + $subscription = new Give_Subscription( $subscription ); + $gateway_id = $subscription->gateway; + + } + + return $this->get_gateway( $gateway_id, $subscription ); + } + + /** + * Get gateway object based on gateway_id + * + * @param string $gateway_id + * @param \Give_Subscription $subscription + * + * @return Give_Recurring_Gateway|boolean + */ + public function get_gateway( $gateway_id, $subscription ) { + $class_name = 'Give_Recurring_' . ucfirst( $gateway_id ); + + if ( class_exists( $class_name ) ) { + $ret = new $class_name(); + } else { + $ret = false; + } + + return apply_filters( 'give_recurring_gateway_factory_get_gateway', $ret, $gateway_id, $subscription ); + } +} + + +/** + * Main function for returning gateway from subscription, uses the Give_Recurring_Gateway_Factory class + * + * @param Give_Subscription|int $subscription subscription id or Give_Subscription object + * + * @return Give_Recurring_Gateway + */ +function give_recurring_get_gateway_from_subscription( $subscription ) { + return Give_Recurring()->gateway_factory->get_gateway_from_subscription( $subscription ); +} + +/** + * Main function for returning gateway, uses the Give_Recurring_Gateway_Factory class + * + * @param string $gateway_id + * @param $subscription + * + * @return Give_Recurring_Gateway + */ +function give_recurring_get_gateway( $gateway_id, $subscription ) { + return Give_Recurring()->gateway_factory->get_gateway( $gateway_id, $subscription ); +} diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php new file mode 100644 index 0000000000..1bdcb94983 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -0,0 +1,2627 @@ + 0) { + // Get pretty text for recurring time. + $pretty_time = give_recurring_pretty_time($times, true); + + // Proceed only, if interval is 1, 3, or 6 to display related label. + if (1 === $interval) { + $frequency = sprintf( + /* translators: 1. Pretty Interval, 2. Pretty Time, 3. Plural period */ + __('%1$s for %2$s %3$s', 'give-recurring'), + $pretty_period, + $pretty_time, + $plural_period + ); + } else { + $frequency = sprintf( + /* translators: 1. Pretty Interval, 2. Pretty Time, 3. Plural period */ + __('%1$s %3$s for %2$s %3$s', 'give-recurring'), + $pretty_interval, + $pretty_time, + $plural_period + ); + } + + /** + * This filter hook is used to change the recurring label. + * But, we recommend that you use 'give_recurring_pretty_subscription_frequency' filter for the same purpose. + * + * Note: This filter will be deprecated in future. + */ + $frequency = apply_filters( + 'give_recurring_receipt_details_multiple', + $frequency, + $period, + $pretty_interval, + $interval + ); + } else { + // Proceed only, if interval is 1, 3, or 6 to display related label. + if (1 === $interval) { + $frequency = "{$pretty_period}"; + } else { + $frequency = sprintf( + /* translators: 1. Pretty Recurring Interval 2. Plural Period. */ + __('%1$s %2$s', 'give-recurring'), + $pretty_interval, + $plural_period + ); + } + + /** + * This filter hook is used to change the recurring label. + * But, we recommend that you use 'give_recurring_pretty_subscription_frequency' filter for the same purpose. + * + * Note: This filter will be deprecated in future. + */ + $frequency = apply_filters('give_recurring_receipt_details', $frequency, $period, $pretty_interval, $interval); + } + + // If lowercase is true then convert the frequency label to lowercase. + if ($lowercase) { + $frequency = strtolower($frequency); + } + + // If frequency is empty then set frequency is One Time. + if (empty($frequency)) { + $frequency = __('One Time', 'give-recurring'); + } + + /** + * This filter hook is used to change the recurring label. + */ + return apply_filters( + 'give_recurring_pretty_subscription_frequency', + $frequency, + $period, + $pretty_interval, + $interval + ); +} + +/** + * This function is used to simplify the terms for the other gateways which can have different words in period. + * + * Note: Use this function for display purposes, not for storing data to DB. + * + * @param string $period Subscription Period. + * @param string $interval Subscription Interval. + * + * @return array + * @since 1.9.1 + * + */ +function give_recurring_simplify_pretty_subscription_frequency($period, $interval) +{ + if ('month' === substr($period, 0, 5)) { + if (3 === $interval) { + $period = 'quarter'; + $interval = 1; + } elseif (12 === $interval) { + $period = 'year'; + $interval = 1; + } else { + $period = 'month'; + } + } elseif ('day' === substr($period, 0, 3)) { + if (7 === $interval) { + $period = 'week'; + $interval = 1; + } else { + $period = 'day'; + } + } + + return array( + 'period' => $period, + 'interval' => $interval, + ); +} + +/** + * Get Pretty description of Interval. + * + * @param int $interval Recurring Interval. + * + * @return string + * @since 1.6.0 + * + */ +function give_recurring_pretty_interval($interval = 1) +{ + $pretty_interval_list = give_recurring_get_default_pretty_intervals(); + $recurring_interval = $pretty_interval_list[$interval]; + + /** + * Modify pretty interval string. + * + * @param string $recurring_interval + * @param string $interval + * @since 1.6.0 + * + */ + return apply_filters('give_recurring_pretty_interval', $recurring_interval, $interval); +} + +/** + * Get list of default pretty intervals. + * + * @return array + * @since 1.7.0 + * + */ +function give_recurring_get_default_pretty_intervals() +{ + /** + * This filter hook is used to set default pretty intervals. + * + * @since 1.7.0 + */ + return (array)apply_filters( + 'give_recurring_get_default_pretty_intervals', array( + '1' => __('Every', 'give-recurring'), + '2' => __('Every two', 'give-recurring'), + '3' => __('Every three', 'give-recurring'), + '4' => __('Every four', 'give-recurring'), + '5' => __('Every five', 'give-recurring'), + '6' => __('Every six', 'give-recurring'), + ) + ); +} + +/** + * Get pretty plural version of a period. + * + * Appears in recurring donation levels (e.g "for six months"). + * + * @param string $period Time period. Accepts 'day', 'week', 'month', 'year'. + * @return array + * @since 1.8.3 + * + */ +function give_recurring_get_pretty_plural_period($period) +{ + $periods = array( + 'day' => __('days', 'give-recurring'), + 'week' => __('weeks', 'give-recurring'), + 'month' => __('months', 'give-recurring'), + 'quarter' => __('quarters', 'give-recurring'), + 'year' => __('years', 'give-recurring'), + ); + + $pretty_period = isset($periods[$period]) ? $periods[$period] : ''; + + return $pretty_period; +} + +/** + * Get list of default pretty periods. + * + * @return array + * @since 1.7.0 + * + */ +function give_recurring_get_default_pretty_periods() +{ + /** + * This filter hook is used to set default pretty periods. + * + * @since 1.7.0 + */ + return (array)apply_filters( + 'give_recurring_get_default_pretty_periods', array( + 'day' => __('Daily', 'give-recurring'), + 'week' => __('Weekly', 'give-recurring'), + 'month' => __('Monthly', 'give-recurring'), + 'quarter' => __('Quarterly', 'give-recurring'), + 'half-year' => __('Semi-Annually', 'give-recurring'), + 'year' => __('Yearly', 'give-recurring'), + ) + ); +} + +/** + * Recurring Body Classes + * + * Add specific CSS class by filter + * + * @param $classes + * + * @return array + */ +function give_recurring_body_classes($classes) +{ + // add 'class-name' to the $classes array. + $classes[] = 'give-recurring'; + + // return the $classes array. + return $classes; +} + +add_filter('body_class', 'give_recurring_body_classes'); + +/** + * Recurring Form Specific Classes + * + * Add specific CSS class by filter + * + * @param $form_classes + * @param $form_id + * @param $form_args + * + * @return array + */ +function give_recurring_form_classes($form_classes, $form_id, $form_args) +{ + // Is this form recurring. + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + // Sanity check: only proceed with recurring forms. + if ('no' === $recurring_option) { + return $form_classes; + } + + // add 'class-name' to the $classes array. + $form_classes[] = 'give-recurring-form-wrap'; + $form_classes[] = 'give-recurring-form-' . ('yes_donor' === $recurring_option ? 'donor' : 'admin'); + + // return the $classes array. + return apply_filters('give_recurring_form_wrap_classes', $form_classes, $form_id, $form_args); +} + +add_filter('give_form_wrap_classes', 'give_recurring_form_classes', 10, 3); + +/** + * Add a Recurring Class to the Give Donation form Class + * + * Useful for themes and plugins JS to target recurring enabled forms + * + * @param $classes + * @param $form_id + * @param $args + * + * @return array + * @since 1.1 + * + */ +function give_recurring_enabled_form_class($classes, $form_id, $args) +{ + if (give_recurring_is_recurring($form_id)) { + $classes[] = 'give-recurring-form'; + } + + return $classes; +} + +add_filter('give_form_classes', 'give_recurring_enabled_form_class', 10, 3); + +/** + * Give Recurring Form Title + * + * Outputs the subscription title from purchase data; only form title if single level, if multi-level output will be + * the donation level followed by the selected level. If custom it will output the custom amount label. + * + * @param $purchase_data + * + * @return string + */ +function give_recurring_subscription_title($purchase_data) +{ + // Item name - pass level name if variable priced. + $item_name = $purchase_data['post_data']['give-form-title']; + $form_id = intval($purchase_data['post_data']['give-form-id']); + + // Verify has variable prices. + if (give_has_variable_prices($form_id) && isset($purchase_data['post_data']['give-price-id'])) { + $item_price_level_text = give_get_price_option_name($form_id, $purchase_data['post_data']['give-price-id']); + + $price_level_amount = give_get_price_option_amount($form_id, $purchase_data['post_data']['give-price-id']); + + // Donation given doesn't match selected level (must be a custom amount). + if ($price_level_amount != give_sanitize_amount($purchase_data['price'])) { + $custom_amount_text = give_get_meta($form_id, '_give_custom_amount_text', true); + // user custom amount text if any, fallback to default if not + $item_name .= ' - ' . (!empty($custom_amount_text) ? $custom_amount_text : __( + 'Custom Amount', + 'give-recurring' + )); + } // End if(). + elseif (!empty($item_price_level_text)) { + $item_name .= ' - ' . $item_price_level_text; + } + } // End if(). + elseif (give_get_form_price($form_id) !== give_sanitize_amount($purchase_data['price'])) { + $custom_amount_text = give_get_meta($form_id, '_give_custom_amount_text', true); + // user custom amount text if any, fallback to default if not. + $item_name .= ' - ' . (!empty($custom_amount_text) ? $custom_amount_text : __( + 'Custom Amount', + 'give-recurring' + )); + } + + return $item_name; +} + +/** + * Get pretty subscription status + * + * @param $status + * + * @return string $status_formatted + */ +function give_recurring_get_pretty_subscription_status($status) +{ + $status_formatted = ''; + $statuses = give_recurring_get_subscription_statuses(); + + // Format period details. + if (!empty($status) && array_key_exists($status, $statuses)) { + foreach ($statuses as $status_key => $value) { + if ($status === $status_key) { + $status_formatted = ' ' . $value . ''; + } + } + } else { + $status_formatted = apply_filters('give_recurring_subscription_frequency', $status_formatted, $status); + } + + return $status_formatted; +} + +/** + * Subscription Plan Name + * + * @param $form_id + * @param $price_id + * + * @return bool|string + */ +function give_recurring_generate_subscription_name($form_id, $price_id = null) +{ + if (empty($form_id)) { + return false; + } + + $subscription_name = get_post_field('post_title', $form_id); + + // Backup for forms with no titles. + if (empty($subscription_name)) { + $subscription_name = __('Untitled Donation Form', 'give-recurring'); + } + + // Check for multi-level. + if (give_has_variable_prices($form_id) && is_numeric($price_id)) { + $subscription_name .= ' - ' . give_get_price_option_name($form_id, $price_id); + } + + return apply_filters('give_recurring_subscription_name', $subscription_name); +} + +/** + * Retrieve the Subscriptions page URI + * + * @access public + * @return int $page_id Subscription Page. + * @since 1.7 + * + */ +function give_recurring_subscriptions_page_id() +{ + $page_id = absint(give_get_option('subscriptions_page', 0)); + + /** + * Filter to modify subscriptions page id. + * + * @param int $page_id + * @since 1.7 + * + */ + return apply_filters('give_recurring_subscriptions_page_id', $page_id); +} + +/** + * Retrieve the Subscriptions page URI + * + * @access public + * @return string + * @since 1.1 + */ +function give_get_subscriptions_page_uri() +{ + $subscriptions_page = get_permalink(give_recurring_subscriptions_page_id()); + + /** + * Filter to modify subscriptions page URL. + * + * @param int $subscriptions_page + * @since 1.1 + * + */ + return apply_filters('give_get_subscriptions_page_uri', $subscriptions_page); +} + +/** + * Is Donation Form Recurring + * + * @param $form_id + * + * @return bool + */ +function give_is_form_recurring($form_id) +{ + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + // Sanity check: only proceed with recurring forms. + if (!empty($recurring_option) && 'no' !== $recurring_option) { + return true; + } + + return false; +} + +/** + * Adds a hidden field so Recurring can tell whether this form is for logged in users only. + * + * @param int $form_id + * + * @since 1.4 + */ +function give_recurring_is_logged_in_only_form_hidden_field($form_id) +{ + $logged_in_only = give_get_meta($form_id, '_give_logged_in_only', true); + $logged_in_only = give_is_setting_enabled($logged_in_only); + ?> + + + + array( + 'level_id' => 'custom', + ), + '_give_amount' => 0, // We can't bring amount before submitting donation form. + '_give_text' => '', + '_give_default' => '', + '_give_recurring' => 'yes', + '_give_period' => $recurring_period, + '_give_times' => $recurring_times, + '_give_period_interval' => $recurring_interval, + ); + } + + return array(); +} + +/** + * This will add a message to the multi level forms so that user can understand whether it is a one time or recurring + * donation. + * + * @param $output + * @param $form_id + * + * @return string + * @since 1.4 + * + */ +function give_recurring_admin_defined_explanation($output, $form_id) +{ + // Only output on recurring admin defined forms. + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + if ('yes_admin' !== $recurring_option) { + return $output; + } + + $prices = give_get_variable_prices($form_id); + + // Loop through prices to identify the default price. + $default_price = give_recurring_get_default_price($form_id, $recurring_option); + foreach ($prices as $price) { + if (isset($price['_give_default']) && 'default' === $price['_give_default']) { + $default_price = $price; + } + } + + $output .= '

'; + $output .= give_recurring_get_multi_levels_notification_message($default_price, $form_id); + $output .= '

'; + + return apply_filters('give_recurring_admin_defined_explanation_output', $output); +} + +add_action('give_form_level_output', 'give_recurring_admin_defined_explanation', 10, 2); + +/** + * This ajax function will return message to be displayed to notify users. + * + * @return mixed + * @since 1.4 + * + */ +function give_recurring_notify_user_on_level_change() +{ + $form_id = isset($_POST['formID']) ? absint($_POST['formID']) : false; + // Bail Out, if formID is not present in post variables. + if (!$form_id) { + return; + } + + $value = 0; + $default_price['_give_amount'] = isset($_POST['amount']) ? give_clean($_POST['amount']) : ''; + + $price_id = isset($_POST['priceID']) ? give_clean($_POST['priceID']) : 0; + + // Get list of levels defined. + $prices = give_get_variable_prices($form_id); + + // Loop through prices to identify the default price. + $prices[] = give_recurring_get_default_price($form_id); + + foreach ($prices as $price) { + if (isset($price['_give_id']['level_id']) && $price_id === $price['_give_id']['level_id']) { + $price['_give_amount'] = empty($price['_give_amount']) ? $default_price['_give_amount'] : $price['_give_amount']; + $default_price = $price; + + if (!empty($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { + $value = 1; + } + } + } + + $response = array(); + $response['html'] = give_recurring_get_multi_levels_notification_message($default_price, $form_id); + $response['period_label'] = give_recurring_get_selected_period_label($default_price); + $response['is_recurring'] = $value; + + wp_send_json_success($response); +} + +add_action('wp_ajax_give_recurring_notify_user_on_levels', 'give_recurring_notify_user_on_level_change'); +add_action('wp_ajax_nopriv_give_recurring_notify_user_on_levels', 'give_recurring_notify_user_on_level_change'); + +/** + * This function will return a message based on the Price Level Array provided. + * + * @param array $price Donation price ID. + * @param integer $form_id Donation Form ID. + * + * @return string + * @since 1.6.2 Passing additional arg $form_id. + * + * @since 1.4 + */ +function give_recurring_get_multi_levels_notification_message($price = array(), $form_id) +{ + $message = ''; + $period_label = __('once', 'give-recurring'); + $recurring_times = isset($price['_give_times']) ? $price['_give_times'] : false; + $give_amount = isset($price['_give_amount']) ? $price['_give_amount'] : 0; + $interval = !empty($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; + + // If Recurring is enabled, then show a different message else show one time message. + if (isset($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { + $period_label = give_recurring_pretty_subscription_frequency( + $price['_give_period'], + $recurring_times, + true, + $interval + ); + } + + // Show message for custom amount whether it is one time or recurring donation. + $message .= sprintf( + __('You have chosen to donate %s.', 'give-recurring'), + sprintf( + ' %1$s %2$s', + give_currency_filter( + give_format_amount( + $give_amount, + array( + 'sanitize' => false, + ) + ), + array( + 'currency_code' => give_get_currency($form_id), + ) + ), + $period_label + ) + ); + + return apply_filters('give_recurring_multi_levels_notification_message', $message, $price, $form_id); +} + +/** + * SVG image of Give Recurring Img tag. + * + * @since 1.5.1 + */ +function give_recurring_symbol_img() +{ + return ''; +} + +/** + * This function will help identify type of donations on Donation History Page. + * + * @param int $donation_amount Donation Amount. + * @param int $donation_id Donation ID. + * + * @return string + * @since 1.4 + * + */ +function give_recurring_add_recurring_label($donation_amount, $donation_id) +{ + $subscription = new Give_Subscription(); + $status = $subscription->is_parent_payment($donation_id); + + // Add Recurring label if donation is of recurring type. + if (true === $status) { + return $donation_amount . ' ' . give_recurring_symbol_img() . ' '; + } + + return $donation_amount; +} + +add_filter('give_donation_history_row_amount', 'give_recurring_add_recurring_label', 10, 2); + + +/** + * Adds the "_give_is_donation_recurring" hidden field. + * + * This can be used to easily determine if a donation has been made recurring on submit. + * + * @param $form_id + * + * @return Void + * @since 1.5.1 + * + */ +function give_recurring_after_donation_levels($form_id) +{ + // Get the recurring is enable or not. + $recurring_support = (string)give_get_meta($form_id, '_give_recurring', true); + + if (empty($recurring_support) || 'no' === $recurring_support) { + return; + } + + // default value. + $value = 0; + $checkbox_default = ''; + $price_option = ''; + + // if it's on donor. + if ('yes_donor' === $recurring_support) { + // check if default option in form is checked or not. + $checkbox_default = give_get_meta($form_id, '_give_checkbox_default', true); + + if (!empty($checkbox_default) && 'yes' === $checkbox_default) { + $value = 1; + } + } elseif ('yes_admin' === $recurring_support) { + // Get the Donation type. + $price_option = give_get_meta($form_id, '_give_price_option', true); + + // check if donation type is multi. + if (!empty($price_option) && 'multi' === $price_option) { + $levels = maybe_unserialize(give_get_meta($form_id, '_give_donation_levels', true)); + foreach ($levels as $price) { + if (!empty($price['_give_default']) && !empty($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { + $value = 1; + } + } + } else { + $value = 1; + } + } + + printf( + '', + $value, + $recurring_support, + $checkbox_default, + $price_option + ); +} + +add_action('give_donation_form_top', 'give_recurring_after_donation_levels', 10); + +/** + * Get Recurring Donation Form Details. + * + * @param int $form_id Form ID. + * @since 1.8.1 + * + */ +function give_recurring_donation_form_details($form_id) +{ + $recurring_information = array(); + + $give_non_recurring_pretty_text = __('once', 'give-recurring'); + if (give_is_form_recurring($form_id)) { + $recurring_option = give_get_meta($form_id, '_give_recurring', true, 'no'); + $give_price_option = give_get_meta($form_id, '_give_price_option', true, 'no'); + $recurring_period_duration = ''; + $recurring_frequency = '1'; + $recurring_times = give_get_meta($form_id, '_give_times', true, '0'); + + if ('yes_admin' === $recurring_option) { + $price_option = give_get_meta($form_id, '_give_price_option', true); + + // check if donation type is multi. + if (!empty($price_option) && 'multi' === $price_option) { + $prices = give_get_variable_prices($form_id); + + foreach ($prices as $price) { + $level_id = $price['_give_id']['level_id']; + $is_recurring = isset($price['_give_recurring']) ? $price['_give_recurring'] : 'no'; + + if ('no' !== $is_recurring) { + if (isset($price['_give_period'])) { + $recurring_period_duration = $price['_give_period']; + } + + if (isset($price['_give_period_interval'])) { + $recurring_frequency = $price['_give_period_interval']; + } + + if (isset($price['_give_times'])) { + $recurring_times = $price['_give_times']; + } + + $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( + $recurring_period_duration, + $recurring_times, + $lowercase = false, + $recurring_frequency + ); + } else { + $give_recurring_pretty_text = $give_non_recurring_pretty_text; + } + + $recurring_information[$give_price_option][$level_id]['_give_recurring'] = $is_recurring; + $recurring_information[$give_price_option][$level_id]['give_recurring_pretty_text'] = $give_recurring_pretty_text; + } + + $give_custom_amount = give_get_meta($form_id, '_give_custom_amount', true, 'disabled'); + + // Check if Custom amount. + if (give_is_setting_enabled($give_custom_amount)) { + $level_id = 'custom'; + $recurring_period_duration = give_get_meta( + $form_id, + '_give_recurring_custom_amount_period', + true, + 'month' + ); + $recurring_frequency = give_get_meta($form_id, '_give_recurring_custom_amount_interval', true, '1'); + $recurring_times = give_get_meta($form_id, '_give_recurring_custom_amount_times', true, '0'); + + $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( + $recurring_period_duration, + $recurring_times, + $lowercase = false, + $recurring_frequency + ); + + if ('once' === $recurring_period_duration) { + $give_recurring_pretty_text = $give_non_recurring_pretty_text; + $recurring_information[$give_price_option][$level_id]['_give_recurring'] = 'no'; + } else { + $recurring_information[$give_price_option][$level_id]['_give_recurring'] = 'yes'; + } + + $recurring_information[$give_price_option][$level_id]['give_recurring_pretty_text'] = $give_recurring_pretty_text; + } + } + } else { + $recurring_information['give_recurring_option'] = 'yes_donor'; + } + } else { + $recurring_information['is_recurring'] = false; + } + + /** + * Get Multi-Level Admin defined Recurring Information. + * + * @param array $recurring_information + * @param int $form_id + * + * @return array $recurring_information + * @since 1.8.1 + * + */ + $recurring_information = apply_filters('give_recurring_donation_form_details', $recurring_information, $form_id); + + $recurring_details = wp_json_encode($recurring_information); + + printf( + '', + esc_js($recurring_details) + ); +} + +add_action('give_donation_form_top', 'give_recurring_donation_form_details', 10); + +/** + * Add Field to Payment Meta + * + * Store the custom field data custom post meta attached to the `give_payment` CPT. + * + * @param $payment_id + * @param $payment_data + * + * @return mixed + */ +function give_recurring_insert_payment($payment_id) +{ + if (isset($_POST['_give_is_donation_recurring'])) { + $give_recurring_donation = empty($_POST['_give_is_donation_recurring']) ? 0 : absint( + give_clean($_POST['_give_is_donation_recurring']) + ); + give_update_meta($payment_id, '_give_is_donation_recurring', $give_recurring_donation); + } +} + +add_action('give_insert_payment', 'give_recurring_insert_payment', 10); + +/** + * Updates a payment status. + * + * @param int $sub_id Subscription ID. + * @param string $new_status New Payment Status. Default is 'active'. + * + * @return bool + * @since 1.5.1 + * + */ +function give_recurring_update_subscription_status($sub_id, $new_status = 'active') +{ + $updated = false; + $subscription = new Give_Subscription(absint($sub_id)); + $old_status = $subscription->status; + + /** + * Fire Action before the subscription status is change. + * + * @since 1.5.8 + */ + do_action( + 'give_recurring_before_subscription_status_get_update', $sub_id, array( + 'new_status' => $new_status, + 'old_status' => $old_status, + ) + ); + + if ($subscription && $subscription->id > 0) { + $updated = $subscription->update( + array( + 'status' => sanitize_text_field($new_status), + ) + ); + } + + /** + * Fire Action after the subscription status is changed. + * + * @since 1.5.8 + */ + do_action( + 'give_recurring_after_subscription_status_updated', $sub_id, array( + 'new_status' => $new_status, + 'old_status' => $old_status, + 'updated' => $updated, + ) + ); + + return $updated; +} + +/** + * Cancel the subscription. + * + * @param int $sub_id Subscription ID. + * + * @return bool + * @since 1.5.1 + * + */ +function give_recurring_subscription_cancel($sub_id) +{ + $subscription = new Give_Subscription(absint($sub_id)); + + if (!$subscription->can_cancel()) { + return false; + } + + do_action('give_recurring_cancel_' . $subscription->gateway . '_subscription', $subscription, true); + + $subscription->cancel(); + + return true; +} + +/** + * Fire when subscription status change to cancelled. + * + * @param $sub_id + * @param $subscription_details + * @since 1.5.8 + * + */ +function give_recurring_get_cancel($sub_id, $subscription_details) +{ + if (!empty($subscription_details['new_status']) && 'cancelled' === $subscription_details['new_status']) { + give_recurring_subscription_cancel($sub_id); + } +} + +add_action('give_recurring_after_subscription_status_updated', 'give_recurring_get_cancel', 10, 2); + +/** + * Delete the subscription. + * + * @param int $sub_id Subscription ID. + * + * @return bool + * @since 1.5.1 + * + */ +function give_recurring_subscription_delete($sub_id) +{ + $updated = false; + $subscription = new Give_Subscription(absint($sub_id)); + + if ($subscription && $subscription->id > 0) { + delete_post_meta($subscription->parent_payment_id, '_give_subscription_payment'); + + $updated = $subscription->delete(); + } + + return $updated; +} + +/** + * Get Subscription details by ID. + * + * @param string $type Type of ID Passed ( Payment or Profile ). + * @param int $id Payment ID or Profile ID based on parameter $type + * + * @return bool|Give_Subscription + * @since 1.5.6 + * + */ +function give_recurring_get_subscription_by($type = 'payment', $id) +{ + // Bail Out, if ID is not present. + if (empty($id)) { + return false; + } + + $subscription = false; + + switch ($type) { + case 'payment': + $subscription_db = new Give_Subscriptions_DB(); + $subscription = $subscription_db->get_subscriptions( + array( + 'parent_payment_id' => $id, + 'number' => 1, + ) + ); + + if (is_array($subscription) && count($subscription) > 0) { + $subscription = $subscription[0]; + } + break; + + case 'profile': + $subscription = new Give_Subscription($id, true); + break; + } + + return $subscription; +} + +/** + * Get the Subscription for the Donor + * + * @param int $donor_id Pass the donor id or user ID of which Subscription list should get fetch. + * @param array $args Array of arguments. + * + * @return array Subscription list for the donor. + * @since 1.5.8 + * + */ +function give_recurring_get_donor_subscriptions($donor_id, $args = array()) +{ + // Set Subscription args. + $args = wp_parse_args( + $args, + array( + 'form_id' => 0, + 'by_user_id' => false, + ) + ); + + $subscriber = new Give_Recurring_Subscriber($donor_id, $args['by_user_id']); + unset($args['by_user_id']); + + return $subscriber->get_subscriptions($args['form_id'], $args); +} + +/** + * Get the list of all the subscription statuses key + * + * @return array $statuses_key + * @since 1.5.8 + * + */ +function give_recurring_get_subscription_statuses_key() +{ + /** + * Filter to modify the list of subscription statuses key. + * + * @return array $status + * @since 1.5.8 + * + */ + return (array)apply_filters( + 'give_recurring_get_subscription_statuses_key', + array_keys(give_recurring_get_subscription_statuses()) + ); +} + +/** + * Get the list of all the subscription statuses + * + * @return array $status + * @since 1.5.8 + * + */ +function give_recurring_get_subscription_statuses() +{ + /** + * Filter to modify the list of subscription statuses. + * + * @return array $statuses + * @since 1.5.8 + * + */ + return (array)apply_filters( + 'give_recurring_get_subscription_statuses', array( + 'active' => __('Active', 'give-recurring'), + 'expired' => __('Expired', 'give-recurring'), + 'completed' => __('Completed', 'give-recurring'), + 'cancelled' => __('Cancelled', 'give-recurring'), + 'pending' => __('Pending', 'give-recurring'), + 'failing' => __('Failing', 'give-recurring'), + 'suspended' => __('Suspended', 'give-recurring'), + 'abandoned' => __('Abandoned', 'give-recurring'), + ) + ); +} + +/** + * Get Selected Recurring Period Label. + * + * @param array $price List of prices. + * + * @return string + * @since 1.5.8 + * + */ +function give_recurring_get_selected_period_label($price = array()) +{ + $period_label = __('once', 'give-recurring'); + $recurring_times = isset($price['_give_times']) ? $price['_give_times'] : false; + $frequency = !empty($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; + + // If Recurring is enabled, then show a different message else show one time message. + if (isset($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { + $period_label = give_recurring_pretty_subscription_frequency( + $price['_give_period'], + $recurring_times, + true, + $frequency + ); + } + + return $period_label; +} + +/** + * Display text after final donation total label + * + * @param int $form_id Form ID. + * + * @since 1.5.8 + */ +function give_recurring_after_donation_total_text_callback($form_id) +{ + if (give_is_form_recurring($form_id)) { + $recurring_option = give_get_meta($form_id, '_give_recurring', true, 'no'); + $recurring_default = give_get_meta($form_id, '_give_checkbox_default', true, 'no'); + $recurring_period_duration = ''; + $recurring_frequency = '1'; + $recurring_times = give_get_meta($form_id, '_give_times', true, '0'); + + if ('yes_donor' === $recurring_option) { + $recurring_period = give_get_meta($form_id, '_give_period_functionality', true, 'admin_choice'); + if ('admin_choice' === $recurring_period && 'yes' === $recurring_default) { + $recurring_period_duration = give_get_meta($form_id, '_give_period', true, 'month'); + } elseif ('donors_choice' === $recurring_period && 'yes' === $recurring_default) { + $recurring_period_duration = give_get_meta( + $form_id, + '_give_period_default_donor_choice', + true, + 'month' + ); + } + + $recurring_frequency = give_get_meta($form_id, '_give_period_interval', true, '1'); + } elseif ('yes_admin' === $recurring_option) { + $price_option = give_get_meta($form_id, '_give_price_option', true); + + // check if donation type is multi. + if (!empty($price_option) && 'multi' === $price_option) { + $prices = give_get_variable_prices($form_id); + $default_price = array(); + foreach ($prices as $price) { + if ( + !empty($price['_give_default']) && + 'default' === $price['_give_default'] && + !empty($price['_give_recurring']) && + 'yes' === $price['_give_recurring'] + ) { + $default_price = $price; + } + } + + if (isset($default_price['_give_period'])) { + $recurring_period_duration = $default_price['_give_period']; + } + + if (isset($default_price['_give_period_interval'])) { + $recurring_frequency = $default_price['_give_period_interval']; + } + + if (isset($default_price['_give_times'])) { + $recurring_times = $default_price['_give_times']; + } + } else { + $recurring_period_duration = give_get_meta($form_id, '_give_period', true, 'month'); + $recurring_frequency = give_get_meta($form_id, '_give_period_interval', true, '1'); + } + } + + $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( + $recurring_period_duration, + $recurring_times, + $lowercase = false, + $recurring_frequency + ); + + echo sprintf( + '%2$s', + empty($recurring_period_duration) ? 'give-hidden' : '', + $give_recurring_pretty_text + ); + } +} + +add_action('give_donation_final_total_label_after', 'give_recurring_after_donation_total_text_callback'); + +/** + * Get Billing times for the Donation level. + * + * @param int $form_id + * + * @return array + * @since 1.6.0 + * + */ +function give_recurring_get_billing_times($form_id) +{ + $billing_limits = array(); + $levels = give_get_meta($form_id, '_give_donation_levels', true); + + // Bail out, if levels not array and empty. + if (empty($levels) && !is_array($levels)) { + return $billing_limits; + } + + foreach ($levels as $level_id => $level) { + if (isset($level['_give_times'])) { + $billing_limits[$level_id] = give_clean($level['_give_times']); + } + } + + return $billing_limits; +} + +/** + * Calculate recurring times. + * + * e.g. Quarterly for 12 months. It means that subscription will charge for 4 times. + * + * @param $times + * @param $frequency + * + * @return int + * @since 1.6.0 + * + */ +function give_recurring_calculate_times($times, $frequency) +{ + // Set frequency default if empty. + if (empty($frequency)) { + $frequency = 1; + } + + $times = absint($times) / absint($frequency); + + /** + * Modify Billing times. + * + * @param $times + * @since 1.6.0 + * + */ + return apply_filters('give_recurring_calculate_times', $times); +} + +/** + * Get pretty time string. + * + * Convert number to words if 'times' less than 10. + * + * @param string $times + * @param bool $lowercase default true, Display lowercase text + * + * @return string + * @since 1.6.0 + * + */ +function give_recurring_pretty_time($times, $lowercase = true) +{ + if ($times >= '10') { + return $times; + } + + $pretty_time = array( + '1' => __('One', 'give-recurring'), + '2' => __('Two', 'give-recurring'), + '3' => __('Three', 'give-recurring'), + '4' => __('Four', 'give-recurring'), + '5' => __('Five', 'give-recurring'), + '6' => __('Six', 'give-recurring'), + '7' => __('Seven', 'give-recurring'), + '8' => __('Eight', 'give-recurring'), + '9' => __('Nine', 'give-recurring'), + ); + + $times = $pretty_time[$times]; + + if ($lowercase) { + $times = strtolower($times); + } + + /** + * Update Recurring pretty time string. + * + * @param string $times + * @param bool $lowercase default true, Display lowercase text + * @since 1.6.0 + * + */ + return apply_filters('give_recurring_pretty_time', $times, $lowercase); +} + +/** + * Get metadata to pass in Stripe. + * + * @param array $purchase_data List of Purchase Data. + * @param int $donation_id Donation ID. + * + * @return array $metadata + * @since 1.6.0 + * + */ +function give_recurring_get_metadata($purchase_data, $donation_id = 0) +{ + $form_id = !empty($purchase_data['post_data']['give-form-id']) ? intval( + $purchase_data['post_data']['give-form-id'] + ) : 0; + + $metadata = array( + 'first_name' => $purchase_data['user_info']['first_name'], + 'last_name' => $purchase_data['user_info']['last_name'], + 'created_by' => $purchase_data['post_data']['give-form-title'], + ); + + // Add address to customer metadata if present. + if (isset($purchase_data['user_info']['address']) && !empty($purchase_data['user_info']['address'])) { + $metadata['address_line1'] = !empty($purchase_data['user_info']['address']['line1']) ? $purchase_data['user_info']['address']['line1'] : ''; + $metadata['address_line2'] = !empty($purchase_data['user_info']['address']['line2']) ? $purchase_data['user_info']['address']['line2'] : ''; + $metadata['address_city'] = !empty($purchase_data['user_info']['address']['city']) ? $purchase_data['user_info']['address']['city'] : ''; + $metadata['address_state'] = !empty($purchase_data['user_info']['address']['state']) ? $purchase_data['user_info']['address']['state'] : ''; + $metadata['address_country'] = !empty($purchase_data['user_info']['address']['country']) ? $purchase_data['user_info']['address']['country'] : ''; + $metadata['address_zip'] = !empty($purchase_data['user_info']['address']['zip']) ? $purchase_data['user_info']['address']['zip'] : ''; + } + + // Proceed to add ffm field to stripe meta only if fn exists. + if (function_exists('give_stripe_get_custom_ffm_fields')) { + // Add custom ffm fields to stripe metadata. + $metadata = array_merge($metadata, give_stripe_get_custom_ffm_fields($form_id)); + } + + /** + * Pass metadata stripe. + * + * @param array $metadata Metadata passed to the Stripe. + * @param array $donation_data Donation data. + * @since 1.6.0 + * + */ + $metadata = apply_filters('give_recurring_stripe_metadata', $metadata, $purchase_data); + + // Limit metadata passed to Stripe as maximum of 20 metadata is only allowed. + if (count($metadata) > 20) { + $metadata = array_slice($metadata, 0, 19, false); + $metadata = array_merge( + $metadata, array( + 'More Details' => esc_url_raw( + admin_url( + 'edit.php?post_type=give_forms&page=give-payment-history&view=view-payment-details&id=' . $donation_id + ) + ), + ) + ); + } + + return $metadata; +} + +/** + * Determines if we're currently on the Subscriptions page. + * + * @return bool True if on the Subscriptions page, false otherwise. + * @since 1.7 + * + */ +function give_recurring_is_subscriptions_page() +{ + $ret = is_page(give_recurring_subscriptions_page_id()); + + /** + * Filter to modify is subscriptions page. + * + * @param bool $ret True if on the Subscriptions page, false otherwise. + * @since 1.7 + * + */ + return apply_filters('give_recurring_is_subscriptions_page', $ret); +} + +/** + * Exports upcoming subscription renewals + * data in CSV format + * + * @return void + * @since 1.7 + * + */ +function give_recurring_export_subscription_renewal_csv() +{ + require_once GIVE_RECURRING_PLUGIN_DIR . 'includes/admin/tools/class-give-export-subscriptions.php'; + + $earnings_export = new Give_Subscriptions_Renewals_Export(); + + $earnings_export->export(); +} + +add_action('give_subscriptions_renewal_export', 'give_recurring_export_subscription_renewal_csv'); + +/** + * Get Card object. + * + * @param Give_Recurring_Subscriber $subscriber Subscriber. + * @param Give_Subscription $subscription Subscription. + * + * @return array|bool + * @since 1.7 + * + */ +function give_recurring_get_card_details($subscriber, $subscription) +{ + // Sanity Check: Subscribers only + if ($subscriber->id <= 0) { + Give()->notices->print_frontend_notice( + __('You have not made any recurring donations.', 'give-recurring'), + true, + 'warning' + ); + + return false; + } + + // Bail out if subscription can not be updated or gateway deactivated. + if (!$subscription->can_update()) { + Give()->notices->print_frontend_notice( + __('Subscription can not be updated.', 'give-recurring'), + true, + 'warning' + ); + + return false; + } + + $gateway = $subscription->gateway; + $payment_id = $subscription->parent_payment_id; + + $card_info = array(); + + switch ($gateway) { + case 'stripe': + case 'stripe_checkout': + case 'stripe_google_pay': + case 'stripe_apple_pay': + // Get Stripe customer id. + $customer_id = Give()->donor_meta->get_meta($subscriber->id, give_stripe_get_customer_key(), true); + + // Get Stripe Customer ID from Donation meta if not stored in Donor meta. + if (empty($customer_id)) { + $customer_id = give_get_meta($payment_id, '_give_stripe_customer_id', true); + } + + // Bail out if Stripe Customer ID not stored in DB. + if (empty($customer_id)) { + Give()->notices->print_frontend_notice( + __('Stripe Customer ID not exist.', 'give-recurring'), + true, + 'error' + ); + + return false; + } + + try { + $subscription_id = $subscription->profile_id; + $stripe_subscription = \Stripe\Subscription::retrieve($subscription_id); + + if (!empty($stripe_subscription->default_payment_method)) { + $stripe_payment_method = new Give_Stripe_Payment_Method(); + $default_payment_method = $stripe_payment_method->retrieve( + $stripe_subscription->default_payment_method + ); + $card = $default_payment_method->card; + } else { + $customer = \Stripe\Customer::retrieve($customer_id); + $default_payment_method = !empty($customer->default_source) ? + $customer->default_source : + $customer->invoice_settings->default_payment_method; + $give_payment_method = new Give_Stripe_Payment_Method(); + $payment_method_details = $give_payment_method->retrieve($default_payment_method); + $card = $payment_method_details->card; + } + } catch (Exception $e) { + give_stripe_record_log( + __('Stripe - Update Payment Method', 'give-recurring'), + sprintf( + __('Unable to fetch default payment method of the customer. Details: %1$s', 'give-recurring'), + $e + ) + ); + } + + $card_info['last_digit'] = isset($card->last4) ? $card->last4 : ''; + $card_info['exp_month'] = isset($card->exp_month) ? $card->exp_month : ''; + $card_info['exp_year'] = isset($card->exp_year) ? $card->exp_year : ''; + $card_info['cc_type'] = isset($card->brand) ? $card->brand : ''; + + break; + case 'authorize': + // Work on Authorize CC details. + $authorize = new Give_Recurring_Authorize(); + + // Get PayPal Pro Card object + $cc_details = $authorize->get_subscription_cc_details($subscription); + + $expirationDate = explode('-', $cc_details['expirationDate']); + + $card_info['exp_month'] = 'XX'; + $card_info['exp_year'] = 'XX'; + if (isset($expirationDate) && is_array($expirationDate)) { + $card_info['exp_month'] = $expirationDate[1]; + $card_info['exp_year'] = $expirationDate[0]; + } + + $card_info['last_digit'] = substr($cc_details['cardNumber'], 4); + $card_info['cc_type'] = $cc_details['cardType']; + + break; + case 'paypalpro': + $paypal_pro = new Give_Recurring_PayPal_Website_Payments_Pro(); + + // Get PayPal Pro Card object + $cc_details = $paypal_pro->get_subscription_cc_details($subscription); + $card_info['last_digit'] = isset($cc_details['ACCT']) ? $cc_details['ACCT'] : ''; + $card_info['cc_type'] = isset($cc_details['CREDITCARDTYPE']) ? $cc_details['CREDITCARDTYPE'] : ''; + $card_info['exp_month'] = isset($cc_details['EXPDATE']) ? substr($cc_details['EXPDATE'], 0, 2) : ''; + $card_info['exp_year'] = isset($cc_details['EXPDATE']) ? substr($cc_details['EXPDATE'], 2) : ''; + break; + } + + /** + * Update Card Information. + * + * @param Give_Recurring_Subscriber $subscriber + * @param Give_Subscription $subscription + * + * @return array $card_info + * @since 1.7 + * + */ + return apply_filters('give_recurring_get_card_details', $card_info, $subscriber, $subscription); +} + +/** + * Add recurring checkbox in Donation form goal format + * + * @return void + * @since 1.7 + * + */ +function give_recurring_add_goal_recurring_checkbox($field) +{ + global $thepostid; + $value = 1; + $recurring_goal_format = give_recurring_goal_format_enable($thepostid); + ?> +

+ > + +

+ absint($form_id), + ); + $args = wp_parse_args($args, $defaults); + + $db = new Give_Subscriptions_DB(); + + return $subscriptions = $db->get_subscriptions($args); +} + +/** + * Check if donation form goal based on recurring is enable + * + * @param int|null $form_id Donation form ID. + * + * @return bool $value True if goal based on recurring is enable or else false. + * @since 1.7 + * + */ +function give_recurring_goal_format_enable($form_id = '') +{ + return empty($form_id) ? false : (bool)give_get_meta($form_id, '_give_recurring_goal_format', true); +} + +/** + * Modify form earning if only count recurring option is checked + * + * @param float $income Form total earning. + * @param int $form_id Donation form ID. + * + * @return float $new_income Form total earning. + * @since 1.7 + * + */ +function give_recurring_goal_amount_raised_output($income, $form_id) +{ + if (!give_recurring_goal_format_enable($form_id)) { + return $income; + } + + $new_income = 0; + $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); + foreach ($form_subscriptions as $subscription) { + $new_income = $new_income + $subscription->initial_amount; + } + + return $new_income; +} + +add_filter('give_goal_amount_raised_output', 'give_recurring_goal_amount_raised_output', 11, 2); + +/** + * Modify form total number of donation that is being made to the form. + * + * @param int $donation_number Form total earning. + * @param int $form_id Donation Form ID. + * + * @return int $donation_number Form total earning. + * @since 1.7 + * + */ +function give_recurring_donations_raised_output($donation_number, $form_id) +{ + if (!give_recurring_goal_format_enable($form_id)) { + return $donation_number; + } + + $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); + + return count($form_subscriptions); +} + +add_filter('give_goal_donations_raised_output', 'give_recurring_donations_raised_output', 11, 2); + +/** + * Modify total number of donor who has made recurring donation to the form + * + * @param int $donors Number of donor who made recurring donation to the Form. + * @param int $form_id Donation form id. + * + * @return int $new_donors Form total earning. + * @since 1.7 + * + */ +function give_recurring_donors_target_output($donors, $form_id) +{ + if (!give_recurring_goal_format_enable($form_id)) { + return $donors; + } + + $new_donors = array(); + $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); + foreach ($form_subscriptions as $subscription) { + $new_donors[] = $subscription->donor_id; + } + $new_donors = array_unique($new_donors); + + return count($new_donors); +} + +add_filter('give_goal_donors_target_output', 'give_recurring_donors_target_output', 11, 2); + +/** + * Give Localized variables. + * + * @param array $localize_give_vars + * + * @return array $localize_give_vars + * @since 1.8 + * + */ +function give_recurring_global_script_vars($localize_give_vars) +{ + $action = (isset($_GET['action']) && !empty($_GET['action'])) ? give_clean($_GET['action']) : ''; + + if (!empty($action) && 'edit_subscription' === $action) { + $localize_give_vars['bad_minimum'] = __('The minimum renewal amount for this form is', 'give-recurring'); + $localize_give_vars['bad_maximum'] = __('The maximum renewal amount for this form is', 'give-recurring'); + } + + return $localize_give_vars; +} + +add_filter('give_global_script_vars', 'give_recurring_global_script_vars', 10, 2); + + +/** + * Display Currency Switcher Update notice. + * + * @since 1.8.1 + */ +function give_recurring_display_minimum_cs_version_notice() +{ + if ( + defined('GIVE_CURRENCY_SWITCHER_BASENAME') && + is_plugin_active(GIVE_CURRENCY_SWITCHER_BASENAME) + ) { + if (version_compare(GIVE_CURRENCY_SWITCHER_VERSION, '1.3.0', '<')) { + Give()->notices->register_notice( + array( + 'id' => 'give-recurring-require-minimum-cs-version', + 'type' => 'error', + 'dismissible' => false, + 'description' => __( + 'Please update the Give Currency Switcher add-on to version 1.3+ to be compatible with the latest version of the Recurring Add-on.', + 'give-recurring' + ), + ) + ); + } + } +} + +add_action('admin_notices', 'give_recurring_display_minimum_cs_version_notice'); + +/** + * This function will return whether the donation is a parent donation or not. + * + * @param int $donation_id Donation ID. + * + * @return bool + * @since 1.8.3 + * + */ +function give_recurring_is_parent_donation($donation_id) +{ + global $wpdb; + + if (empty($donation_id)) { + return false; + } + + $table_name = $wpdb->prefix . 'give_subscriptions'; + $sql = esc_sql($wpdb->prepare("SELECT * FROM {$table_name} WHERE `parent_payment_id` = %d", $donation_id)); + $is_parent_payment = $wpdb->get_results($sql); + + if ($is_parent_payment) { + return true; + } + + return false; +} + + +/** + * Install plugin tables on plugin version update + * + * Note: internal use only + * + * @param string $old_version + * @since 1.9.0 + */ +function give_recurring_install_table($old_version) +{ + // Fresh install? + // This hook will only run on first install after that update_option_give_recurring_version will use. + if ('add_option_give_recurring_version' === current_filter()) { + $old_version = ''; + } + + update_option('give_recurring_version_upgraded_from', $old_version, false); + + give_recurring_register_tables(); +} + +add_filter('update_option_give_recurring_version', 'give_recurring_install_table', 0, 1); +add_filter('add_option_give_recurring_version', 'give_recurring_install_table', 0, 1); + +/** + * Subscription donation processing errors + * 1. Check if current gateway support recurring donation or not. + * + * Note: only for internal use + * + * @param array $valid_data + * @since 1.8.11 + * + * + */ +function give_recurring_checkout_errors($valid_data) +{ + $post_data = give_clean($_POST); // WPCS: input var ok, sanitization ok, CSRF ok. + + // Show an error if the current payment gateway does not support subscription donations. + if ( + !empty($post_data['_give_is_donation_recurring']) + && !Give_Recurring::get_gateway_class($valid_data['gateway']) + ) { + $enabled_payment_gateways = give_get_enabled_payment_gateways(absint($post_data['give-form-id'])); + $has_multi_gateway_choice = 1 < count($enabled_payment_gateways); + + $suggestion_msg = ''; + + if ($has_multi_gateway_choice) { + $recurring_supported_gateways = array_intersect_key($enabled_payment_gateways, Give_Recurring::$gateways); + $recurring_supported_gateways_count = count($recurring_supported_gateways); + $recurring_supported_gateway_list = implode( + ', ', + wp_list_pluck($recurring_supported_gateways, 'checkout_label') + ); + + if (1 < $recurring_supported_gateways_count) { + $recurring_supported_gateway_list = substr_replace( + $recurring_supported_gateway_list, + ' ' . __('or', 'give-recurring'), + strrpos($recurring_supported_gateway_list, ','), + 1 + ); + } + + $suggestion_msg = sprintf( + _n( + 'Please switch to the %1$s payment gateway to process a subscription donation.', + 'Please switch to either the %1$s payment gateways to process a subscription donation.', + $recurring_supported_gateways_count, + 'give-recurring' + ), + $recurring_supported_gateway_list + ); + } + + + give_set_error( + 'recurring_gateway_not_supported', + sprintf( + __('Sorry we\'re unable to process subscription donations with %1$s.%2$s', 'give-recurring'), + $enabled_payment_gateways[$valid_data['gateway']]['checkout_label'], + $has_multi_gateway_choice ? ' ' . $suggestion_msg : '' + ) + ); + } +} + +add_action('give_checkout_error_checks', 'give_recurring_checkout_errors', 0, 1); + +/** + * This function will add form tags when required for update payment method. + * + * @param array $formHtmlTags HTML Form Tags. + * @param Give_Subscription $subscription Subscription object. + * + * @return mixed + * @since 1.9.11 + * + */ +function give_recurring_stripe_add_form_tags($formHtmlTags, $subscription) +{ + // If payment gateway is not Stripe. + if (!in_array($subscription->gateway, give_stripe_supported_payment_methods(), true)) { + return $formHtmlTags; + } + + $formId = !empty($subscription->form_id) ? absint($subscription->form_id) : 0; + $publishableKey = give_stripe_get_publishable_key($formId); + $accountId = give_stripe_get_connected_account_id($formId); + + $formHtmlTags['data-publishable-key'] = $publishableKey; + $formHtmlTags['data-account'] = $accountId; + + return $formHtmlTags; +} + +add_filter('give_recurring_update_subscription_form_tags', 'give_recurring_stripe_add_form_tags', 0, 2); + +/** + * This function is used to add global parameters to Stripe Global Vars. + * + * @param array $args List of Parameters. + * + * @return array + * @since 1.10.2 + * + */ +function give_recurring_stripe_add_global_parameters($args) +{ + $is_update_pm_allowed = give_stripe_is_update_payment_method_screen(); + $subscription_db = new Give_Subscriptions_DB(); + $subscription_details = !empty($is_update_pm_allowed) ? + $subscription_db->get_subscriptions(['id' => $is_update_pm_allowed]) : + false; + + // Donor can update card for only following Stripe payment methods. + $stripePaymentMethods = ['stripe', 'stripe_checkout', 'stripe_apple_pay', 'stripe_google_pay']; + + $args['stripe_card_update'] = $is_update_pm_allowed && in_array( + $subscription_details[0]->gateway, + $stripePaymentMethods + ); + $args['stripe_becs_update'] = $is_update_pm_allowed && 'stripe_becs' === $subscription_details[0]->gateway; + + return $args; +} + +add_filter('give_stripe_global_parameters', 'give_recurring_stripe_add_global_parameters'); + + +/** + * Is the donation recurring. + * + * Determines if a donation is a recurring donation; should be used only at time of making the donation. + * Use Give_Recurring_Subscriber->has_subscription() to determine after subscription is made if it is in fact + * recurring. + * + * @param array $payment_meta + * + * @return bool + * @since 1.0 + * @access public + * + */ +function give_recurring_is_donation_recurring($payment_meta) +{ + // Ensure we have proper vars set + if (isset($payment_meta['post_data'])) { + $form_id = isset($payment_meta['post_data']['give-form-id']) ? $payment_meta['post_data']['give-form-id'] : 0; + $price_id = isset($payment_meta['post_data']['give-price-id']) ? $payment_meta['post_data']['give-price-id'] : 0; + } else { + // fallback + $form_id = isset($payment_meta['form_id']) ? $payment_meta['form_id'] : 0; + $price_id = isset($payment_meta['price_id']) ? $payment_meta['price_id'] : 0; + } + + // Check for donor's choice option + $user_choice = isset($payment_meta['post_data']['give-recurring-period']) ? $payment_meta['post_data']['give-recurring-period'] : ''; + $user_custom_amount = isset($payment_meta['post_data']['give-price-id']) ? $payment_meta['post_data']['give-price-id'] : ''; + $recurring_enabled = give_get_meta($form_id, '_give_recurring', true); + $custom_amount = give_get_meta($form_id, '_give_custom_amount', true); + $custom_amount_recurring = give_get_meta($form_id, '_give_recurring_custom_amount_period', true, 'month'); + + // If not empty this is a recurring donation (checkbox is checked) + if (!empty($user_choice)) { + return true; + } + + if ((empty($user_choice) && 'yes_donor' === $recurring_enabled) || + ( + empty($user_choice) && + 'yes_admin' === $recurring_enabled && + 'once' === $custom_amount_recurring && + 'custom' === $user_custom_amount + )) { + // User only wants to give once + return false; + } + + // Admin choice: check fields + if (give_has_variable_prices($form_id) || ('yes_admin' === $recurring_enabled && give_is_setting_enabled( + $custom_amount + ))) { + // get default selected price ID + return give_recurring_is_recurring($form_id, $price_id); + } + + // Set level + return give_recurring_is_recurring($form_id); +} + +/** + * Is Donation Form Recurring? + * + * Check if a donation form is recurring. + * + * @param int $form_id The donation form ID. + * @param int $level_id The multi-level ID. + * + * @return bool + * @since 1.0 + * @access public + * @static + * + */ +function give_recurring_is_recurring($form_id, $level_id = 0) +{ + $is_recurring = false; + $levels = maybe_unserialize(give_get_meta($form_id, '_give_donation_levels', true)); + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + $period = give_recurring_get_period($form_id, $level_id); + + // If it's multi level with admin choice with admin does not choice recurring for that level. + if (empty($period)) { + return false; + } + + /** + * Check multi-level forms whether any level is recurring + * + * Conditions: + * a. Form has variable price + * b. The form has a recurring option enabled. + */ + if ( + give_has_variable_prices($form_id) + && (empty($recurring_option) || 'no' !== $recurring_option) + ) { + switch ($recurring_option) { + // Is this a multi-level donor's choice? + case 'yes_donor': + return true; + break; + + case 'yes_admin': + if ('custom' === $level_id) { + return true; + } else { + // Loop through levels and see if a level is recurring. + foreach ($levels as $level) { + // Is price recurring? + $level_recurring = (isset($level['_give_recurring']) && $level['_give_recurring'] == 'yes'); + + // check that this price is indeed recurring: + if ($level_id == $level['_give_id']['level_id'] && $level_recurring && false !== $period) { + $is_recurring = true; + } elseif (empty($level_id) && $level_recurring) { + // Checking for ANY recurring level - empty $level_id param. + $is_recurring = true; + } + } + } + break; + } + } elseif (!empty($recurring_option) && 'no' !== $recurring_option) { + // Single level donation form. + $is_recurring = true; + } + + return $is_recurring; +} + +/** + * Set up the time period IDs and labels + * + * @param int $number + * @param string $period + * + * @return array + * @since 1.6.0 Update Periods label. + * @static + * + * @since 1.0 + */ +function give_recurring_periods($number = 1, $period = '') +{ + $periods = apply_filters( + 'give_recurring_periods', + [ + // translators: placeholder is number of days. (e.g. "Bill this every day / 4 days") + 'day' => sprintf( + _nx( + 'day', + '%s days', + $number, + 'Recurring billing period.', + 'give-recurring' + ), + $number + ), + // translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 weeks") + 'week' => sprintf( + _nx( + 'week', + '%s weeks', + $number, + 'Recurring billing period.', + 'give-recurring' + ), + $number + ), + // translators: placeholder is number of months. (e.g. "Bill this every month / 4 months") + 'month' => sprintf( + _nx( + 'month', + '%s months', + $number, + 'Recurring billing period.', + 'give-recurring' + ), + $number + ), + // translators: placeholder is number of quarters. (e.g. "Bill this every quarter / 4 times in a year") + 'quarter' => sprintf( + _nx( + 'quarter', + '%s quarters', + $number, + 'Recurring billing period.', + 'give-recurring' + ), + $number + ), + // translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") + 'year' => sprintf( + _nx( + 'year', + '%s years', + $number, + 'Recurring billing period.', + 'give-recurring' + ), + $number + ), + ], + $number + ); + + return !empty($periods[$period]) ? $periods[$period] : $periods; +} + +/** + * Get billing times. + * + * @param string $billing_period + * + * @return array + * @since 1.6.0 + * + */ +function give_recurring_times($billing_period = '') +{ + $periods = give_recurring_ranges(); + + $periods = apply_filters('give_recurring_times', $periods); + + if (!empty($billing_period)) { + return $periods[$billing_period]; + } + + return $periods; +} + +/** + * Returns an array of Recurring lengths. + * + * PayPal Standard Allowable Ranges + * D – for days; allowable range is 1 to 90 + * W – for weeks; allowable range is 1 to 52 + * M – for months; allowable range is 1 to 24 + * Y – for years; allowable range is 1 to 5 + * + * @since 1.6.0 + */ +function give_recurring_ranges() +{ + $periods = array_keys(give_recurring_periods()); + + foreach ($periods as $period) { + $subscription_lengths = [ + _x('Ongoing', 'Subscription length', 'give-recurring'), + ]; + + switch ($period) { + case 'day': + $subscription_lengths[] = _x( + '1 day', + 'Subscription lengths. e.g. "For 1 day..."', + 'give-recurring' + ); + $subscription_range = range(2, 90); + break; + case 'week': + $subscription_lengths[] = _x( + '1 week', + 'Subscription lengths. e.g. "For 1 week..."', + 'give-recurring' + ); + $subscription_range = range(2, 52); + break; + case 'month': + $subscription_lengths[] = _x( + '1 month', + 'Subscription lengths. e.g. "For 1 month..."', + 'give-recurring' + ); + $subscription_range = range(2, 24); + break; + case 'quarter': + $subscription_lengths[] = _x( + '1 quarter', + 'Subscription lengths. e.g. "For 1 quarter..."', + 'give-recurring' + ); + $subscription_range = range(2, 12); + break; + case 'year': + $subscription_lengths[] = _x( + '1 year', + 'Subscription lengths. e.g. "For 1 year..."', + 'give-recurring' + ); + $subscription_range = range(2, 5); + break; + } + + foreach ($subscription_range as $number) { + $subscription_range[$number] = give_recurring_periods($number, $period); + } + + // Add the possible range to all time range + $subscription_lengths += $subscription_range; + + $subscription_ranges[$period] = $subscription_lengths; + } + + return $subscription_ranges; +} + +/** + * Set up the interval label. + * + * @param string (optional) An interval in the range 1-6 + * + * @return mixed + * @since 1.6.0 + * Return an i18n'ified associative array of all possible subscription periods. + * + */ +function give_recurring_interval($interval = '') +{ + $intervals = [1 => _x('every', 'period interval (eg "$10 _every_ 2 weeks")', 'give-recurring')]; + + foreach (range(2, 6) as $i) { + // translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) + $intervals[$i] = sprintf( + _x( + 'every %s', + 'period interval with ordinal number (e.g. "every 2nd"', + 'give-recurring' + ), + give_recurring_append_numeral_suffix($i) + ); + } + + $intervals = apply_filters('give_recurring_interval', $intervals); + + if (empty($interval)) { + return $intervals; + } + + return $intervals[$interval]; +} + +/** + * Takes a number and returns the number with its relevant suffix appended, eg. for 2, the function returns 2nd + * + * @param int $number + * + * @return string + * @since 1.6.0 + * + */ +function give_recurring_append_numeral_suffix($number) +{ + // Handle teens: if the tens digit of a number is 1, then write "th" after the number. For example: 11th, 13th, 19th, 112th, 9311th. http://en.wikipedia.org/wiki/English_numerals + if (strlen($number) > 1 && 1 == substr($number, -2, 1)) { + // translators: placeholder is a number, this is for the teens + $number_string = sprintf(__('%sth', 'give-recurring'), $number); + } else { // Append relevant suffix + switch (substr($number, -1)) { + case 1: + // translators: placeholder is a number, numbers ending in 1 + $number_string = sprintf(__('%sst', 'give-recurring'), $number); + break; + case 2: + // translators: placeholder is a number, numbers ending in 2 + $number_string = sprintf(__('%snd', 'give-recurring'), $number); + break; + case 3: + // translators: placeholder is a number, numbers ending in 3 + $number_string = sprintf(__('%srd', 'give-recurring'), $number); + break; + default: + // translators: placeholder is a number, numbers ending in 4-9, 0 + $number_string = sprintf(__('%sth', 'give-recurring'), $number); + break; + } + } + + return apply_filters('give_recurring_numeral_suffix', $number_string, $number); +} + +/** + * Get Period. + * + * Get the time period for a variable priced donation. + * + * @param $form_id + * @param $price_id + * + * @return bool|string + * @since 1.0 + * @access public + * @static + * + */ +function give_recurring_get_period($form_id, $price_id = 0) +{ + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + // Is this a variable price form & admin's choice? + if (give_has_variable_prices($form_id) && 'yes_admin' === $recurring_option) { + if ('custom' === $price_id) { + return give_get_meta($form_id, '_give_recurring_custom_amount_period', true, 'month'); + } else { + $levels = give_get_meta($form_id, '_give_donation_levels', true); + + foreach ($levels as $price) { + // Check that this indeed the recurring price. + if ($price_id == $price['_give_id']['level_id'] + && isset($price['_give_recurring']) + && 'yes' === $price['_give_recurring'] + && isset($price['_give_period']) + ) { + return isset($price['_give_period']) ? $price['_give_period'] : 'month'; + } + } + } + } else { + $recurring_period = give_get_meta($form_id, '_give_period_functionality', true, 'admin_choice'); + + // This is either a Donor's Choice multi-level or set donation form. + $period = give_get_meta($form_id, '_give_period', true); + + if ('donors_choice' === $recurring_period) { + $period = give_get_meta($form_id, '_give_period_default_donor_choice', true, 'month'); + } + + if ($period) { + return $period; + } + } + + return false; +} + +/** + * Get Interval. + * + * Get the period interval for a variable priced donation. + * + * @param $form_id + * @param $price_id + * + * @return bool|string + * @since 1.6.0 + * @access public + * @static + * + */ +function give_recurring_get_interval($form_id, $price_id = 0) +{ + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + // Is this a variable price form & admin's choice? + if (give_has_variable_prices($form_id) && 'yes_admin' === $recurring_option) { + if ('custom' === $price_id) { + return give_get_meta($form_id, '_give_recurring_custom_amount_interval', true, '1'); + } else { + $levels = give_get_meta($form_id, '_give_donation_levels', true); + + foreach ($levels as $price) { + // Check that this indeed the recurring price. + if ($price_id == $price['_give_id']['level_id'] + && isset($price['_give_recurring']) + && 'yes' === $price['_give_recurring'] + && isset($price['_give_period']) + ) { + return isset($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; + } + } + } + } else { + // This is either a Donor's Choice multi-level or set donation form. + $period = give_get_meta($form_id, '_give_period_interval', true, 1); + + if ($period) { + return $period; + } + } + + return false; +} + +/** + * Get Times. + * + * Get the number of times a price ID recurs. + * + * @param $form_id + * @param $price_id + * + * @return int + * @since 1.0 + * @access public + * @static + * + */ +function give_recurring_get_times($form_id, $price_id = 0) +{ + $recurring_option = give_get_meta($form_id, '_give_recurring', true); + + // is this a single or multi-level form? + if (give_has_variable_prices($form_id) && 'yes_admin' === $recurring_option) { + if ('custom' === $price_id) { + return give_get_meta($form_id, '_give_recurring_custom_amount_times', true, 0); + } else { + $levels = maybe_unserialize(give_get_meta($form_id, '_give_donation_levels', true)); + + foreach ($levels as $price) { + // Check that this indeed the recurring price. + if ( + $price_id == $price['_give_id']['level_id'] && + isset($price['_give_recurring']) && + 'yes' === $price['_give_recurring'] && + isset($price['_give_times']) + ) { + return isset($price['_give_times']) ? intval($price['_give_times']) : 0; + } + } + } + } else { + $times = give_get_meta($form_id, '_give_times', true, 0); + + if ($times) { + return $times; + } + } + + return 0; +} + +/** + * Get the number of times a single-price donation form recurs. + * + * @param $form_id + * + * @return int|mixed + * @since 1.0 + * @static + * + */ +function give_recurring_get_times_single($form_id) +{ + $times = give_get_meta($form_id, '_give_times', true); + + if ($times) { + return $times; + } + + return 0; +} diff --git a/src/LegacySubscriptions/includes/give-recurring-renewals.php b/src/LegacySubscriptions/includes/give-recurring-renewals.php new file mode 100644 index 0000000000..e8da2e64ea --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-renewals.php @@ -0,0 +1,311 @@ +setup(); + } + + return self::$instance; + } + + /** + * Setup + * + * @since 1.7 + * @access private + */ + private function setup(){ + add_action( 'give_daily_scheduled_events', array( $this, 'scheduled_renewal_reminders' ) ); + } + + /** + * Returns if renewals are enabled + * + * @return bool True if enabled, false if not + */ + public function reminders_allowed() { + + $renewal_reminder = give_get_option( 'recurring_send_renewal_reminders' ); + + return ( 'enabled' === $renewal_reminder ) ? true : false; + } + + /** + * Retrieve renewal notices + * + * @return array Renewal notice periods + */ + public function get_renewal_notice_periods() { + $periods = array( + '+1day' => __( 'One day before renewal', 'give-recurring' ), + '+2days' => __( 'Two days before renewal', 'give-recurring' ), + '+3days' => __( 'Three days before renewal', 'give-recurring' ), + '+1week' => __( 'One week before renewal', 'give-recurring' ), + '+2weeks' => __( 'Two weeks before renewal', 'give-recurring' ), + '+1month' => __( 'One month before renewal', 'give-recurring' ), + '+2months' => __( 'Two months before renewal', 'give-recurring' ), + '+3months' => __( 'Three months before renewal', 'give-recurring' ), + ); + + return apply_filters( 'get_renewal_notice_periods', $periods ); + } + + /** + * Retrieve the renewal label for a notice + * + * @param int $notice_id + * + * @return string + */ + public function get_renewal_notice_period_label( $notice_id = 0 ) { + + $notice = $this->get_renewal_notice( $notice_id ); + $periods = $this->get_renewal_notice_periods(); + $label = $periods[ $notice['send_period'] ]; + + return apply_filters( 'get_renewal_notice_period_label', $label, $notice_id ); + } + + /** + * Retrieve a renewal notice + * + * @param int $notice_id + * + * @return array Renewal notice details. + */ + public function get_renewal_notice( $notice_id = 0 ) { + + $notices = $this->get_renewal_notices(); + + $defaults = array( + 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), + 'send_period' => '+1day', + 'message' => 'Hello {name}, + + Your subscription for {subscription_name} will renew on {expiration}.', + + ); + + $notice = isset( $notices[ $notice_id ] ) ? $notices[ $notice_id ] : $notices[0]; + + $notice = wp_parse_args( $notice, $defaults ); + + return apply_filters( 'give_recurring_renewal_notice', $notice, $notice_id ); + + } + + /** + * Retrieve renewal notice periods + * + * @return array Renewal notices defined in settings + */ + public function get_renewal_notices() { + $notices = get_option( 'give_recurring_reminder_notices', array() ); + + if ( empty( $notices ) ) { + + $message = 'Hello {name}, + + Your subscription for {subscription_name} will renew on {expiration}.'; + + $notices[0] = array( + 'send_period' => '+1day', + 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), + 'message' => $message, + ); + + } + + return apply_filters( 'get_renewal_notices', $notices ); + } + + + /** + * This is the actual process that takes place when the CRON job + * schedules renewal reminders. + * + * @param array $notices The email notices array. + * @param Give_Recurring_Emails $give_recurring_emails Give_Recurring_Email object. + * + * @since 1.6 + * + * @return void + */ + public function reminder_process( $notices, $give_recurring_emails ) { + + /** + * This loop will loop through all the notices, both + * renewal and expiration. + */ + foreach ( $notices as $notice_id => $notice ) { + + /** + * If notice email is disabled, then continue. + */ + if ( 'disabled' === $notice['status'] ) { + continue; + } + + + /** + * This file is responsible for sending out emails for renewals, so we + * skip if the 'notice_type' is set to 'expiration'. + */ + if ( 'expiration' === $notice['notice_type'] ) { + continue; + } + + + /** + * Get all the subscriptions which will be renewed in the next + * `$notice['send_period']` time. + * + * This can be +1day, +1month, +2month, etc. + */ + $subscriptions = $this->get_renewing_subscriptions( $notice['send_period'] ); + + + /** + * If there are no such subscriptions, then check for the next + * notice. + */ + if ( ! $subscriptions ) { + continue; + } + + + foreach ( $subscriptions as $subscription ) { + + /** + * Get the payment ID of the parent payment. + */ + $parent_payment_id = $subscription->parent_payment_id; + + + /** + * Get the gateway of the payment. + */ + $gateway = give_get_payment_meta( $parent_payment_id, '_give_payment_gateway' ); + + + /** + * Don't send the email if the gateway is found + * in the exclusion list. + */ + if ( ! empty( $notice['gateway'] ) && in_array( $gateway, $notice['gateway'], true ) ) { + continue; + } + + + /* Translate each subscription into a user_id and utilize + * the usermeta to store last renewal sent. + */ + $give_subscription = new Give_Subscription( $subscription->id ); + + $sent_time = get_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_renewal_' . $subscription->id . '_sent_' . $notice['send_period'] ), true ); + + if ( $sent_time ) { + + $renew_date = strtotime( $notice['send_period'], $sent_time ); + + if ( time() < $renew_date ) { + continue; + } + + delete_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_renewal_' . $subscription->id . '_sent_' . $notice['send_period'] ) ); + + } + + $give_recurring_emails->send_reminder( 'renewal', $subscription->id, $notice_id ); + } + } + } + + /** + * Send reminder emails + * + * @return void + */ + public function scheduled_renewal_reminders() { + + if ( ! $this->reminders_allowed() ) { + return; + } + + + /** + * This will be used to setup the sending of the email. + */ + $give_recurring_emails = new Give_Recurring_Emails; + + + /** + * Gets all the recurring email notices. + * This includes email notices for both + * renewal and expiration. + */ + $notices = $this->get_renewal_notices(); + + + /** + * This handles sending out emails to donors. + */ + $this->reminder_process( $notices, $give_recurring_emails ); + } + + + /** + * Retrieve renewal notice periods + * + * @param string $period + * + * @return array|bool|mixed|null|object Subscribers whose subscriptions are renewing within the defined period + */ + public function get_renewing_subscriptions( $period = '+1month' ) { + + $subs_db = new Give_Subscriptions_DB(); + $subscriptions = $subs_db->get_renewing_subscriptions( $period ); + + if ( ! empty( $subscriptions ) ) { + return $subscriptions; + } + + return false; + } +} + +Give_Recurring_Renewal_Reminders::get_instance(); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-shortcodes.php b/src/LegacySubscriptions/includes/give-recurring-shortcodes.php new file mode 100644 index 0000000000..28722110e4 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-shortcodes.php @@ -0,0 +1,295 @@ +payment_meta->get_meta( $donation->ID, '_give_subscription_payment', true ); + + if ( 'give_subscription' === $donation->post_status || true === $is_subscription_donation ) { + give_recurring_get_manage_subscriptions_link(); + } + + } + + /** + * Update donation receipt. + * + * @param DonationReceipt $receipt + * + * @return mixed + */ + public function addSubscriptionDetailsGroupToReceipt( $receipt ){ + $updateReceipt = new UpdateDonationReceipt($receipt); + + $updateReceipt->apply(); + } + + + /** + * Sets up the process of verifying the saving of the updated payment method + * + * @since x.x + * @return void + */ + public function verify_profile_update_setup() { + + $subscription_id = ( isset( $_POST['subscription_id'] ) && ! empty( $_POST['subscription_id'] ) ) ? absint( $_POST['subscription_id'] ) : 0; + + if ( empty( $subscription_id ) ){ + give_set_error( 'give_recurring_invalid_subscription_id', __( 'Invalid subscription ID.', 'give-recurring' ) ); + } + + $subscription = new Give_Subscription( $subscription_id ); + + $this->verify_profile_update_action( $subscription->donor_id ); + + } + + /** + * Verify and fire the hook to update a recurring payment method + * + * @since x.x + * + * @param int $user_id The User ID to update. + * + * @return void + */ + private function verify_profile_update_action( $user_id ) { + $subscriptionId = $this->getSubscriptionIdFromPostedData(); + + $passed_nonce = isset( $_POST['give_recurring_update_nonce'] ) + ? give_clean( $_POST['give_recurring_update_nonce'] ) + : false; + + if ( false === $passed_nonce || ! isset( $_POST['_wp_http_referer'] ) ) { + give_set_error( 'give_recurring_invalid_payment_update', __( 'Invalid Payment Update', 'give-recurring' ) ); + } + + $verified = wp_verify_nonce( $passed_nonce, "update-payment-{$subscriptionId}" ); + + if ( 1 !== $verified || empty( $user_id ) ) { + give_set_error( 'give_recurring_unable_payment_update', __( 'Unable to verify payment update. Please try again later.', 'give-recurring' ) ); + } + + // Check if a subscription_id is passed to use the new update methods + if ( $subscriptionId ) { + do_action( 'give_recurring_update_subscription_payment_method', $user_id, absint( $_POST['subscription_id'] ), $verified ); + } + + } + + /** + * Sets up the process of verifying the saving of the updated subscription. + * + * @since 1.8 + */ + public function verify_subscription_update() { + + // Get Subscription ID. + $subscription_id = ( isset( $_POST['subscription_id'] ) && ! empty( $_POST['subscription_id'] ) ) ? absint( $_POST['subscription_id'] ) : 0; + + // Set error if Subscription Id not set. + if ( empty( $subscription_id ) ) { + give_set_error( 'give_recurring_invalid_subscription_id', __( 'Invalid subscription ID.', 'give-recurring' ) ); + } + + // Subscription object. + $subscription = new Give_Subscription( $subscription_id ); + + // Verify subscription update action. + $this->verify_subscription_update_action( $subscription->donor_id ); + } + + /** + * Verify and fire the hook to update a subscription. + * + * @since 1.8 + * + * @param int $user_id The User ID to update. + */ + private function verify_subscription_update_action( $user_id ) { + $subscriptionId = $this->getSubscriptionIdFromPostedData(); + + // Get subscription update nonce. + $passed_nonce = isset( $_POST['give_recurring_subscription_update_nonce'] ) + ? give_clean( $_POST['give_recurring_subscription_update_nonce'] ) + : false; + + // Check nonce refer. + if ( false === $passed_nonce || ! isset( $_POST['_wp_http_referer'] ) ) { + give_set_error( 'give_recurring_invalid_subscription_update', __( 'Invalid Subscription Update', 'give-recurring' ) ); + } + + // Check nonce. + $verified = wp_verify_nonce( $passed_nonce, "update-subscription-{$subscriptionId}" ); + + // Set error if nonce verification failed. + if ( 1 !== $verified || empty( $user_id ) ) { + give_set_error( 'give_recurring_unable_subscription_update', __( 'Unable to verify subscription update. Please try again later.', 'give-recurring' ) ); + } + + // Check if a subscription_id is passed to use the new update methods. + if ( $subscriptionId ) { + + /** + * Update renewal subscription. + * e.g. Update renewal amount. + * + * @since 1.8 + * + * @param int $user_id The User ID to update. + * @param int $subscription_id The Subscription to update. + * @param bool $verified Sanity check that the request to update is coming from a verified source. + * + */ + do_action( 'give_recurring_update_renewal_subscription', $user_id, absint( $_POST['subscription_id'] ), $verified ); + } + } + + /** + * Subscriptions + * + * Provides users with an historical overview of their purchased subscriptions + * + * @param array $atts Shortcode attributes + * + * @since 1.0 + * + * @return string The html for the subscriptions shortcode. + */ + public function give_subscriptions( $atts ) { + + global $give_subscription_args; + + $give_subscription_args = shortcode_atts( array( + 'show_status' => true, + 'show_renewal_date' => true, + 'show_progress' => false, + 'show_start_date' => false, + 'show_end_date' => false, + 'subscriptions_per_page' => 30, + 'pagination_type' => 'next_and_previous', + ), $atts, 'give_subscriptions' ); + + // Convert shortcode_atts values to booleans. + foreach ( $give_subscription_args as $key => $value ) { + if ( 'subscriptions_per_page' !== $key && 'pagination_type' !== $key ) { + $give_subscription_args[ $key ] = filter_var( $give_subscription_args[ $key ], FILTER_VALIDATE_BOOLEAN ); + } + } + + return Give_Recurring()->subscriptions_view(); + } + + + /** + * Get subscription id from posted data + * + * @since 1.10.1 + * + * @return int|null + */ + private function getSubscriptionIdFromPostedData(){ + return ! empty( $_POST['subscription_id'] ) ? absint( $_POST['subscription_id'] ) : null; + } + +} + +new Give_Recurring_Shortcodes(); diff --git a/src/LegacySubscriptions/includes/give-recurring-subscriber.php b/src/LegacySubscriptions/includes/give-recurring-subscriber.php new file mode 100644 index 0000000000..15877a73c5 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-subscriber.php @@ -0,0 +1,461 @@ +subs_db = new Give_Subscriptions_DB(); + } + + /** + * Has donation form subscription. + * + * @param int $form_id + * + * @return bool + */ + public function has_subscription( $form_id = 0 ) { + + // Check all subscriptions by default. + if ( empty( $form_id ) ) { + $subs = $this->get_subscriptions(); + } else { + // If filtering by form. + $subs = $this->get_subscriptions( $form_id ); + } + + $ret = ! empty( $subs ); + + return apply_filters( 'give_recurring_has_subscription', $ret, $form_id, $this ); + } + + /** + * Has active subscription. + * + * @param int $form_id Optional for filtering by form ID. + * + * @return bool + */ + public function has_active_subscription( $form_id = 0 ) { + + $ret = false; + + // Check all subscriptions by default. + if ( empty( $form_id ) ) { + $subs = $this->get_subscriptions(); + } else { + // If filtering by form. + $subs = $this->get_subscriptions( $form_id ); + } + + if ( $subs ) { + foreach ( $subs as $sub ) { + if ( $sub->is_active() ) { + $ret = true; + } + + } + } + + return apply_filters( 'give_recurring_has_active_subscription', $ret, $this ); + + } + + /** + * Add Subscription. + * + * @param array $args + * + * @return bool|object Give_Subscription + */ + public function add_subscription( $args = [] ) { + + $args = wp_parse_args( $args, $this->subs_db->get_column_defaults() ); + + if ( empty( $args['form_id'] ) ) { + return false; + } + + if ( ! empty( $this->user_id ) ) { + $this->set_as_subscriber(); + } + + $args['donor_id'] = $this->id; + + $subscription = new Give_Subscription(); + + return $subscription->create( $args ); + + } + + /** + * Add Payment + * + * @since 1.0 + * + * @param array $args + * + * @return mixed + */ + public function add_payment( $args = [] ) { + + $args = wp_parse_args( $args, [ + 'subscription_id' => 0, + 'amount' => '0.00', + 'transaction_id' => '', + ] ); + + if ( empty( $args['subscription_id'] ) ) { + return false; + } + + $subscription = new Give_Subscription( $args['subscription_id'] ); + + if ( empty( $subscription ) ) { + return false; + } + + unset( $args['subscription_id'] ); + + return $subscription->add_payment( $args ); + + } + + /** + * Get Subscription + * + * @param int $subscription_id + * + * @return object|bool + */ + public function get_subscription( $subscription_id = 0 ) { + + $sub = new Give_Subscription( $subscription_id ); + + if ( (int) $sub->donor_id !== (int) $this->id ) { + return false; + } + + return $sub; + } + + /** + * Get Subscription by Profile ID + * + * @param string $profile_id + * + * @return bool|Give_Subscription + */ + public function get_subscription_by_profile_id( $profile_id = '' ) { + + if ( empty( $profile_id ) ) { + return false; + } + + $sub = new Give_Subscription( $profile_id, true ); + + if ( (int) $sub->donor_id !== (int) $this->id ) { + return false; + } + + return $sub; + + } + + /** + * Get Subscriptions. + * + * Retrieves an array of subscriptions for a the donor. + * Optional form ID and status(es) can be supplied. + * + * @param int $form_id + * @param array $args Array of arguments + * + * @return Give_Subscription[] + */ + public function get_subscriptions( $form_id = 0, $args = [] ) { + + if ( ! $this->id > 0 ) { + return []; + } + + // Backward compatibility + if ( ! empty( $args ) && is_numeric( current( array_keys( $args ) ) ) ) { + $args = [ + 'status' => $args, + ]; + } + + $args = wp_parse_args( + $args, + [ + 'number' => - 1, + 'status' => give_recurring_get_subscription_statuses_key(), + ] + ); + + if ( ! empty( $form_id ) ) { + $args['form_id'] = $form_id; + } + + $args['donor_id'] = $this->id; + + return $this->subs_db->get_subscriptions( $args ); + } + + /** + * Set as Subscriber + * + * Set a user as a subscriber + * + * @return void + */ + public function set_as_subscriber() { + + $user = new WP_User( $this->user_id ); + + if ( $user ) { + $user->add_role( 'give_subscriber' ); + do_action( 'give_recurring_set_as_subscriber', $this->user_id ); + } + + } + + /** + * Get New Expiration + * + * Calculate a new expiration date + * + * @param int $form_id Donation Form ID. + * @param null $price_id Price ID. + * @param int $frequency Frequency/Interval Count. + * @param string $period Period/Interval. Default empty. + * + * @return bool|string + */ + public function get_new_expiration( $form_id = 0, $price_id = null, $frequency = 1, $period = '' ) { + + // If $period is empty, then try fetching it with possible scenarios. + if ( empty( $period ) ) { + if ( isset( $_POST['give-recurring-period-donors-choice'] ) ) { + $period = give_clean( $_POST['give-recurring-period-donors-choice'] ); + } else if ( give_has_variable_prices( $form_id ) ) { + $period = Give_Recurring::get_period( $form_id, $price_id ); + } else { + $period = Give_Recurring::get_period( $form_id ); + } + } + + // Calculate the quarter as times 3 months + if ( $period === 'quarter' ) { + $frequency *= 3; + $period = 'month'; + } + + return date( 'Y-m-d H:i:s', strtotime( '+ ' . $frequency . $period . ' 23:59:59' ) ); + } + + /** + * Get Recurring Customer ID + * + * Get a recurring customer ID + * + * @since 1.0 + * + * @param $gateway string The gateway to get the customer ID for + * + * @return string + */ + public function get_recurring_donor_id( $gateway ) { + + $recurring_ids = $this->get_recurring_donor_ids(); + + if ( is_array( $recurring_ids ) ) { + if ( false === $gateway || ! array_key_exists( $gateway, $recurring_ids ) ) { + $gateway = reset( $recurring_ids ); + } + + $donor_id = $recurring_ids[ $gateway ]; + } else { + $donor_id = empty( $recurring_ids ) ? false : $recurring_ids; + } + + return apply_filters( 'give_recurring_get_donor_id', $donor_id, $this ); + + } + + /** + * Store a recurring customer ID in array + * + * Sets a customer ID per gateway as needed; for instance, Stripe you create a customer and then subscribe them to a plan. The customer ID is stored here. + * + * @since 1.0 + * + * @param $gateway string The gateway to set the customer ID for + * @param $recurring_id string The recurring profile ID to set + * + * @return bool + */ + public function set_recurring_donor_id( $gateway, $recurring_id = '' ) { + + // We require a gateway identifier to be included, if it's not, return false. + if ( false === $gateway ) { + return false; + } + + $recurring_id = apply_filters( 'give_recurring_set_donor_id', $recurring_id, $this->user_id ); + $recurring_ids = $this->get_recurring_donor_ids(); + + if ( ! is_array( $recurring_ids ) ) { + + $existing = $recurring_ids; + $recurring_ids = []; + + // If the first three characters match, we know the existing ID belongs to this gateway + if ( substr( $recurring_id, 0, 3 ) === substr( $existing, 0, 3 ) ) { + + $recurring_ids[ $gateway ] = $existing; + + } + + } + + $recurring_ids[ $gateway ] = $recurring_id; + + // Update donor meta. + return $this->update_meta( '_give_recurring_id', $recurring_ids ); + + } + + /** + * Retrieve the recurring gateway specific IDs for the donor. + * + * @since 1.2 + * + * @return mixed The profile IDs + */ + public function get_recurring_donor_ids() { + + $ids = $this->get_meta( '_give_recurring_id' ); + + // Backwards compatibility for user meta. + if ( empty( $ids ) ) { + $ids = get_user_meta( $this->user_id, '_give_recurring_id', true ); + } + + return apply_filters( 'give_recurring_donor_ids', $ids, $this ); + } + + + /** + * Return subscriber object. + * + * @since 1.10.1 + * + * @return Give_Recurring_Subscriber|null + */ + public static function getSubscriber() { + // Get subscription. + $current_user_id = get_current_user_id(); + + // Get by user id. + if ( ! empty( $current_user_id ) ) { + return new static( $current_user_id, true ); + } + + // Get by email access. + if ( Give()->email_access->token_exists ) { + return new static( Give()->email_access->token_email, false ); + } + + // Get by email. + if ( Give()->session->get_session_expiration() ) { + $subscriber_email = maybe_unserialize( Give()->session->get( 'give_purchase' ) ); + $subscriber_email = isset( $subscriber_email['user_email'] ) ? $subscriber_email['user_email'] : ''; + + return new static( $subscriber_email, false ); + } + + return null; + } + + /** + * Return boolean to determine access + * + * @since 1.10.1 + * + * a. Check if a user is logged in + * b. Does an email-access token exist? + */ + public static function canAccessView() { + return is_user_logged_in() || ( give_is_setting_enabled( give_get_option( 'email_access' ) ) && Give()->email_access->token_exists ); + } + + /** + * Return boolean to determine subscription belongs to donor or not + * + * @param Give_Subscription $subscription + * @param Give_Recurring_Subscriber $subscriber + * + * @return boolean + */ + public static function doesSubscriptionBelongsTo( $subscription, $subscriber = null ) { + $subscriber = $subscriber ?: self::getSubscriber(); + + return $subscription->donor_id === $subscriber->id; + } + + /** + * Get subscriber access type. + * + * @since 1.10.1 + * @return string + */ + public static function getAccessType() { + if ( is_user_logged_in() ) { + return 'wpUser'; + } + + if ( Give()->email_access->token_exists && give_is_setting_enabled( give_get_option( 'email_access' ) ) ) { + return 'EmailAccess'; + } + + if ( false !== Give()->session->get_session_expiration() ) { + return 'DonorSession'; + } + + return ''; + } + +} diff --git a/src/LegacySubscriptions/includes/give-recurring-template.php b/src/LegacySubscriptions/includes/give-recurring-template.php new file mode 100644 index 0000000000..ed27778d33 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-recurring-template.php @@ -0,0 +1,347 @@ + $show_period, + 'period' => $period, + 'times' => $times, + ) ); + ?> +
+ ', + 'give-' . $period_functionality . '-' . $form_id, + 'give-recurring-period', + $pretty_label, + apply_filters( 'give_recurring_donors_choice_checked', $checked, $form_id ), + $period_choice_text, + esc_attr( $period ), + intval( $interval ) + ); + ?> +
+ '; + // Loop through periods. + foreach ( Give_Recurring()->periods() as $key => $item ) { + if ( 'donors_choice' === $key ) { + continue; + } + + // Make text plural if interval is greater than 1. + if ( $interval > '1' ) { + $item = sprintf( __( '%ss', 'give-recurring' ), $item ); + } + + echo ''; + } + echo ''; + + // Times enabled? + if ( $times > 0 ) { + printf( __( '%s times', 'give-recurring' ), ' ' . $times ); + } + + $output = ob_get_clean(); + + + return apply_filters( 'give_recurring_donors_choice_period_element', $output, $form_id ); + +} + +/** + * Set Admin Choice Template + * + * @param $form_id + * @param $args + * + * @param $form_id + * @param $args + * + * @return bool + */ +function give_output_admin_choice( $form_id, $args ) { + + $form_option = give_get_meta( $form_id, '_give_recurring', true ); + $set_or_multi = give_get_meta( $form_id, '_give_price_option', true ); + + // Sanity check: only allow admin's choice + if ( 'yes_admin' !== $form_option ) { + return false; + } + + // Sanity Check: admin & multi options is handled by give_recurring_multilevel_text + if ( 'yes_admin' === $form_option && 'multi' === $set_or_multi ) { + return false; + } + + $period = give_get_meta( $form_id, '_give_period', true ); + $times = give_get_meta( $form_id, '_give_times', true ); + $interval = give_get_meta( $form_id, '_give_period_interval', true, 1 ); + $pretty_period = give_recurring_pretty_subscription_frequency( $period, $times, $lowercase = false, $interval ); + + $output = '' . $pretty_period . ''; + + echo apply_filters( 'give_output_set_admin_choice_output', $output, $form_id, $args ); + +} + +add_action( 'give_after_donation_amount', 'give_output_admin_choice', 10, 2 ); + +/** + * Give Recurring Multilevel Text + * + * Pragmatically append, prepend, replace and/or alter multilevel donation form output + * + * @since 1.12.7 Do not add HTML to price name. Remove old hack which remove HTML from price name while processing donation. + * + * @param $level_text + * @param $form_id + * @param $level + * + * @return string + */ +function give_recurring_multilevel_text( $level_text, $form_id, $level ) { + + $form_option = give_get_meta( $form_id, '_give_recurring', true ); + $set_or_multi = give_get_meta( $form_id, '_give_price_option', true ); + + // Sanity check: Is this admin selection & multi? + if ( 'yes_admin' !== $form_option ) { + return $level_text; + } + // Sanity check: Is this multi? + if ( 'multi' !== $set_or_multi ) { + return $level_text; + } + + // Sanity check: Is this level recurring enabled? + if ( ! isset( $level['_give_recurring'] ) || $level['_give_recurring'] == 'no' ) { + return $level_text; + } + + $period = isset( $level['_give_period'] ) ? $level['_give_period'] : ''; + $times = isset( $level['_give_times'] ) ? $level['_give_times'] : 0; + $interval = isset( $level['_give_period_interval'] ) ? $level['_give_period_interval'] : 1; + $pretty_period = give_recurring_pretty_subscription_frequency( $period, $times, $lowercase = false, $interval ); + + $text = sprintf( + '%1$s%2$s%3$s', + $level_text, + apply_filters( 'give_recurring_multilevel_text_separator', ', ', $form_id, $level ), + $pretty_period + ); + + return apply_filters( 'give_recurring_multilevel_text', $text, $form_id, $level ); + +} + +add_filter( 'give_form_level_text', 'give_recurring_multilevel_text', 10, 3 ); + + +/** + * Add a class to recurring levels + * + * @since 1.1 + * + * @param $classes + * @param $form_id + * @param $level + * + * @return string $classes + */ +function give_recurring_multilevel_classes( $classes, $form_id, $level ) { + + $level_id = isset( $level['_give_id']['level_id'] ) ? $level['_give_id']['level_id'] : ''; + + if ( empty( $level_id ) ) { + return $classes; + } + + $recurring = isset( $level['_give_recurring'] ) && $level['_give_recurring'] == 'yes' ? true : false; + + if ( $recurring ) { + $classes .= ' give-recurring-level'; + } + + return apply_filters( 'give_recurring_multilevel_classes', $classes, $form_id, $level_id ); + +} + +add_filter( 'give_form_level_classes', 'give_recurring_multilevel_classes', 10, 3 ); + + +/** + * Gets Times Billed for a subscription + * + * @param Give_Subscription $subscription + * + * @return string + */ +function get_times_billed_text( $subscription ) { + + // Bill times will show infinite symbol if 0 == bill times + $bill_times = ( $subscription->bill_times == 0 ) ? __( 'Ongoing', 'give-recurring' ) : $subscription->bill_times; + $total_payments = $subscription->get_total_payments(); + $times_billed = $total_payments . ' / ' . $bill_times; + + return apply_filters( 'give_recurring_times_billed_text', $times_billed, $bill_times, $total_payments, $subscription ); +} + +/** + * This function will be used to add renewal notice for donation receipt. + * + * @param mixed $notices Notice. + * @param int $id Post ID. + * @param string $status Payment Status. + * + * @since 1.8.2 + * + * @return string + */ +function give_recurring_add_renewal_notice( $notices, $id, $status ) { + + if ( 'give_subscription' === $status ) { + return Give()->notices->print_frontend_notice( + __( 'Renewal Payment Complete: Thank you for donation!', 'give-recurring' ), + false, + 'success' + ); + } + + return $notices; +} + +add_filter( 'give_receipt_status_notice', 'give_recurring_add_renewal_notice', 10, 3 ); + +/** + * This function is used to fetch the HTML markup of Manage Subscriptions Link. + * + * @since 1.8.2 + * + * @return void + */ +function give_recurring_get_manage_subscriptions_link() { + + // Link to the subscriptions page if set and exists. + $donation_id = give_clean( filter_input( INPUT_GET, 'donation_id' ) ); + + if ( + give_can_view_receipt( $donation_id ) || + is_user_logged_in() + ) { + echo sprintf( + '%2$s', + esc_url( give_get_subscriptions_page_uri() ), + esc_html__( 'Manage Subscriptions', 'give-recurring' ) . ' »' + ); + } +} diff --git a/src/LegacySubscriptions/includes/give-subscription.php b/src/LegacySubscriptions/includes/give-subscription.php new file mode 100644 index 0000000000..ad0620b037 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-subscription.php @@ -0,0 +1,1225 @@ +subs_db = new Give_Subscriptions_DB(); + + if ( $_by_profile_id ) { + + $_sub = $this->subs_db->get_by( 'profile_id', $_id_or_object ); + + if ( empty( $_sub ) ) { + return false; + } + + $_id_or_object = $_sub; + + } + + return $this->setup_subscription( $_id_or_object ); + } + + /** + * Setup the subscription object. + * + * @param int $id_or_object + * + * @return Give_Subscription|bool + */ + private function setup_subscription( $id_or_object = 0 ) { + + if ( empty( $id_or_object ) ) { + return false; + } + if ( is_numeric( $id_or_object ) ) { + + $sub = $this->subs_db->get( $id_or_object ); + + } elseif ( is_object( $id_or_object ) ) { + + $sub = $id_or_object; + + } + + if ( empty( $sub ) ) { + return false; + } + + foreach ( $sub as $key => $value ) { + + // Backwards compatibility: + // Ensure product_id get sent to new form_id. + if ( 'product_id' === $key ) { + $this->form_id = $value; + } + if ( 'customer_id' === $key ) { + $this->donor_id = $value; + } + + $this->$key = $value; + } + + $this->donor = new Give_Donor( $this->donor_id ); + $this->gateway = give_get_payment_gateway( $this->parent_payment_id ); + + do_action( 'give_recurring_setup_subscription', $this ); + + return $this; + } + + /** + * Magic __get function to dispatch a call to retrieve a private property. + * + * @param $key + * + * @return mixed|WP_Error + */ + public function __get( $key ) { + + if ( method_exists( $this, 'get_' . $key ) ) { + + return call_user_func( array( $this, 'get_' . $key ) ); + + } else { + + return new WP_Error( 'give-subscription-invalid-property', sprintf( __( 'Can\'t get property %s', 'give-recurring' ), $key ) ); + + } + + } + + /** + * Creates a subscription. + * + * @since 1.0 + * + * @param array $data Array of attributes for a subscription + * + * @return mixed false if data isn't passed and class not instantiated for creation + */ + public function create( $data = array() ) { + + if ( $this->id != 0 ) { + return false; + } + + $defaults = array( + 'customer_id' => 0, + 'period' => '', + 'frequency' => 1, + 'initial_amount' => '', + 'recurring_amount' => '', + 'recurring_fee_amount' => 0, + 'bill_times' => 0, + 'parent_payment_id' => 0, + 'form_id' => 0, + 'created' => '', + 'expiration' => '', + 'status' => '', + 'profile_id' => '', + ); + + $args = wp_parse_args( $data, $defaults ); + + if ( $args['expiration'] && strtotime( 'NOW', current_time( 'timestamp' ) ) > strtotime( $args['expiration'], current_time( 'timestamp' ) ) ) { + + if ( 'active' == $args['status'] ) { + + // Force an active subscription to expired if expiration date is in the past + $args['status'] = 'expired'; + + } + } + + do_action( 'give_subscription_pre_create', $args ); + + // @TODO: DB column should be updated to 'form_id' in future and remove this backwards compatibility. + if ( ! empty( $args['form_id'] ) ) { + $args['product_id'] = $args['form_id']; + } + // @TODO: DB column should be updated to 'customer_id' in future and remove this backwards compatibility. + if ( ! empty( $args['donor_id'] ) ) { + $args['customer_id'] = $args['donor_id']; + } + + $id = $this->subs_db->create( $args ); + + do_action( 'give_subscription_post_create', $id, $args ); + + // If Payment status is renewal, then update purchase count and amount of donor. + $payment = new Give_Payment( $args['parent_payment_id'] ); + if ( ( 'give_subscription' === $payment->post_status ) && ! empty( $args['customer_id'] ) ) { + $donor = new Give_Donor( $args['customer_id'] ); + $donor->increase_purchase_count(); + $donor->increase_value( $args['recurring_amount'] ); + } + + return $this->setup_subscription( $id ); + + } + + /** + * Update. + * + * Updates a subscription. + * + * @param array $args Array of fields to update + * + * @return bool + */ + public function update( $args ) { + + if ( isset( $args['status'] ) && strtolower( $this->status ) !== strtolower( $args['status'] ) ) { + $this->add_note( sprintf( __( 'Status changed from %s to %s', 'give-recurring' ), $this->status, $args['status'] ) ); + } + + $ret = $this->subs_db->update( $this->id, $args ); + + do_action( 'give_recurring_update_subscription', $this->id, $args, $this ); + + return $ret; + + } + + /** + * Delete the subscription. + * + * @return bool + */ + public function delete() { + do_action( 'give_recurring_before_delete_subscription', $this ); + $deleted = $this->subs_db->delete( $this->id ); + do_action( 'give_recurring_after_delete_subscription', $deleted, $this ); + + return $deleted; + } + + /** + * Get Original Payment ID. + * + * @return int + */ + public function get_original_payment_id() { + return $this->parent_payment_id; + } + + /** + * Get Child Payments. + * + * Retrieves subscription renewal payments for a subscription. + * + * @return array + */ + public function get_child_payments() { + $args = array( + 'post_parent' => (int) $this->parent_payment_id, + 'posts_per_page' => '9999', + 'post_status' => 'any', + 'post_type' => 'give_payment', + ); + + $cache_key = Give_Cache::get_key( 'child_payments', $args, false ); + $payments = Give_Recurring_Cache::get_db_query( $cache_key ); + + if( is_null( $payments ) ) { + $payments = get_posts( $args ); + Give_Recurring_Cache::set_db_query( $cache_key, $payments ); + } + + return $payments; + } + + /** + * Get the Initial Payment. + * + * Retrieves the first payment object for the subscription. + * + * @return array|bool + */ + public function get_initial_payment() { + + $initial_payment = get_posts( array( + 'include' => (int) $this->parent_payment_id, + 'posts_per_page' => '1', + 'post_status' => 'any', + 'post_type' => 'give_payment', + ) ); + + if ( isset( $initial_payment[0] ) ) { + return $initial_payment[0]; + } + + return false; + + } + + + /** + * Get Total Payments. + * + * Returns the total number of times a subscription has been paid including the initial payment (that's the +1). + * + * @return int + */ + public function get_total_payments() { + return count( $this->get_child_payments() ) + 1; + } + + /** + * Get the last payment made. + * + * Returns the subscriptions last payment made regardless of whether it was a renewal or initial payment. + * + * @since 1.8 + * + * @return WP_Post object + */ + public function get_last_payment() { + + // If renewals, return the latest renewal. + $renewals = $this->get_child_payments(); + if ( count( $renewals ) !== 0 ) { + return $renewals[0]; + } + + $initial_payment = get_posts( array( + 'include' => (int) $this->parent_payment_id, + 'posts_per_page' => '1', + 'post_status' => 'any', + 'post_type' => 'give_payment', + ) ); + + // If no renewals return parent payment. + return isset( $initial_payment[0] ) ? $initial_payment[0] : false; + + } + + /** + * Get Lifetime Value. + * + * @return int $amount + */ + public function get_lifetime_value() { + + $amount = 0.00; + + $parent_payment = give_get_payment_by( 'id', $this->parent_payment_id ); + $parent_payment_status = give_get_payment_status( $parent_payment ); + $ignored_statuses = array( 'refunded', 'pending', 'abandoned', 'failed' ); + + if ( false === in_array( $parent_payment_status, $ignored_statuses ) ) { + $amount = give_donation_amount( $this->parent_payment_id ); + } + + $children = $this->get_child_payments(); + + if ( $children ) { + + foreach ( $children as $child ) { + $child_payment_status = give_get_payment_status( $child ); + if ( 'refunded' === $child_payment_status ) { + continue; + } + + $amount += give_donation_amount( $child->ID ); + } + } + + return $amount; + + } + + /** + * Add Payment. + * + * Records a new payment on the subscription. + * + * @since 1.12.7 Set donor first and last name in new donation + * + * @param array $args Array of values for the payment, including amount and transaction ID. + * + * @return bool + */ + public function add_payment( $args = array() ) { + + $args = wp_parse_args( $args, array( + 'amount' => '', + 'transaction_id' => '', + 'gateway' => '', + 'post_date' => '', + ) ); + + // Check if the payment exists. + if ( $this->payment_exists( $args['transaction_id'] ) ) { + return false; + } + + $payment = new Give_Payment(); + $parent = new Give_Payment( $this->parent_payment_id ); + + // Sanitize donation amount. + $args['amount'] = $this->mayBeSanitizeWebhookResponseDonationAmount( $args['amount'], $parent->currency ); + + + $payment->parent_payment = $this->parent_payment_id; + $payment->total = $args['amount']; + $payment->form_title = $parent->form_title; + $payment->form_id = $parent->form_id; + $payment->customer_id = $parent->customer_id; + $payment->address = $parent->address; + $payment->first_name = $parent->user_info['first_name']; + $payment->last_name = $parent->user_info['last_name']; + $payment->user_info = $parent->user_info; + $payment->user_id = $parent->user_id; + $payment->email = $parent->email; + $payment->currency = $parent->currency; + $payment->status = 'give_subscription'; + $payment->transaction_id = $args['transaction_id']; + $payment->key = $parent->key; + $payment->mode = $parent->mode; + + $donor = new Give_Donor( $payment->customer_id ); + $price_id = give_get_price_id( $parent->form_id, $args['amount'] ); + + /** + * Get Correct Donation Level ID for renewal amount. + * + * @param integer $price_id Price ID. + * @param float $amount Renewal amount + * @param \Give_Payment $payment Renewal Payment + * + * @return integer $price_id + * @since 1.8 + * + */ + $price_id = apply_filters( 'give_recurring_renewal_price_id', $price_id, $args['amount'], $parent ); + + // Set price id. + $payment->price_id = $price_id; + + if ( empty( $args['gateway'] ) ) { + $payment->gateway = $parent->gateway; + } else { + $payment->gateway = $args['gateway']; + } + + // If post_date is set (by synchronizer for past payments for example) then pass it along. + if ( ! empty( $args['post_date'] ) ) { + $payment->date = $args['post_date']; + } + + // Increase the earnings for the form in the subscription. + give_increase_earnings( $parent->form_id, $args['amount'] ); + // Increase the donation count for this form as well. + give_increase_donation_count( $parent->form_id ); + + $payment->add_donation( $parent->form_id, array( 'price' => $args['amount'], 'price_id' => $price_id ) ); + $payment->save(); + $payment->update_meta( 'subscription_id', $this->id ); + $donor->increase_purchase_count( 1 ); + $donor->increase_value( $args['amount'] ); + + // Add give recurring subscription notification + do_action( 'give_recurring_add_subscription_payment', $payment, $this ); + do_action( 'give_recurring_record_payment', $payment, $this->parent_payment_id, $args['amount'], $args['transaction_id'] ); + + return true; + } + + /** + * Get Transaction ID. + * + * Retrieves the transaction ID from the subscription. + * + * @since 1.2 + * @return bool + */ + public function get_transaction_id() { + + if ( empty( $this->transaction_id ) ) { + + $txn_id = give_get_payment_transaction_id( $this->parent_payment_id ); + + if ( ! empty( $txn_id ) && (int) $this->parent_payment_id !== (int) $txn_id ) { + $this->set_transaction_id( $txn_id ); + } + } + + return $this->transaction_id; + + } + + /** + * Stores the transaction ID for the subscription donation. + * + * @since 1.2 + * + * @param string $txn_id + * + * @return bool + */ + public function set_transaction_id( $txn_id = '' ) { + $this->update( array( + 'transaction_id' => $txn_id, + ) ); + give_set_payment_transaction_id( $this->parent_payment_id, $txn_id ); + $this->transaction_id = $txn_id; + } + + /** + * Renew Payment. + * + * This method is responsible for renewing a subscription (not adding payments). + * It checks the expiration date, whether the subscription is active, run hooks, sets notes, and updates the + * subscription status as necessary. If the subscription has reached the total number of bill times the + * subscription will be completed. + * + * @since 1.0 + * @return bool + */ + public function renew() { + + $expires = $this->get_expiration_time(); + + // Determine what date to use as the start for the new expiration calculation. + if ( $expires > current_time( 'timestamp' ) && $this->is_active() ) { + $base_date = $expires; + } else { + $base_date = current_time( 'timestamp' ); + } + + $last_day = cal_days_in_month( CAL_GREGORIAN, date( 'n', $base_date ), date( 'Y', $base_date ) ); + $expiration = date( 'Y-m-d H:i:s', strtotime( '+1 ' . $this->period . ' 23:59:59', $base_date ) ); + + if ( date( 'j', $base_date ) == $last_day && 'day' != $this->period ) { + $expiration = date( 'Y-m-d H:i:s', strtotime( $expiration . ' +2 days' ) ); + } + + $expiration = apply_filters( 'give_subscription_renewal_expiration', $expiration, $this->id, $this ); + + do_action( 'give_subscription_pre_renew', $this->id, $expiration, $this ); + + $status = 'active'; + $times_billed = $this->get_total_payments(); + + // Complete subscription if applicable. + if ( $this->bill_times > 0 && $times_billed >= $this->bill_times ) { + $this->complete(); + $status = 'completed'; + } + + $args = array( + 'expiration' => $expiration, + 'status' => $status, + ); + + $this->update( $args ); + + do_action( 'give_subscription_post_renew', $this->id, $expiration, $this ); + do_action( 'give_recurring_set_subscription_status', $this->id, $status, $this ); + + } + + /** + * Subscription Complete. + * + * Subscription is completed when the number of payments matches the billing_times field. + * + * @return void + */ + public function complete() { + + $args = array( + 'status' => 'completed', + ); + + // Prevent duplicate update. + if( ! $this->can_update_status('completed') ) { + return; + } + + if ( $this->subs_db->update( $this->id, $args ) ) { + + do_action( 'give_subscription_completed', $this->id, $this ); + + } + + } + + /** + * Subscription Expire. + * + * Marks a subscription as expired. Subscription is completed when the billing times is reached. + * + * @since 1.1.2 + * @return void + */ + public function expire() { + + $args = array( + 'status' => 'expired', + ); + + // Prevent duplicate update. + if( ! $this->can_update_status('expired') ) { + return; + } + + if ( $this->subs_db->update( $this->id, $args ) ) { + + do_action( 'give_subscription_expired', $this->id, $this ); + + } + + $this->status = 'expired'; + + } + + /** + * Marks a subscription as failing. + * + * @since 1.1.2 + * @return void + */ + public function failing() { + + $args = array( + 'status' => 'failing', + ); + + // Prevent duplicate update. + if( ! $this->can_update_status('failing') ) { + return; + } + + if ( $this->subs_db->update( $this->id, $args ) ) { + do_action( 'give_subscription_failing', $this->id, $this ); + } + + $this->status = 'failing'; + + } + + /** + * Subscription Cancelled. + * + * Marks a subscription as cancelled. + * + * @return void + */ + public function cancel() { + + $args = array( + 'status' => 'cancelled', + ); + + // Prevent duplicate update. + if( ! $this->can_update_status('cancelled') ) { + return; + } + + if ( $this->subs_db->update( $this->id, $args ) ) { + + if ( is_user_logged_in() ) { + + $userdata = get_userdata( get_current_user_id() ); + $user = $userdata->user_login; + + } else { + + $user = __( 'gateway', 'give-recurring' ); + + } + + $note = sprintf( __( 'Subscription #%1$d cancelled by %2$s', 'give-recurring' ), $this->id, $user ); + $this->donor->add_note( $note ); + $this->status = 'cancelled'; + + // Add give subscription cancelled notification + do_action( 'give_subscription_cancelled', $this->id, $this ); + + } + + } + + /** + * Can Cancel. + * + * This method is filtered by payment gateways in order to return true on subscriptions + * that can be cancelled with a profile ID through the merchant processor. + * + * @return mixed + */ + public function can_cancel() { + return apply_filters( 'give_subscription_can_cancel', false, $this ); + } + + /** + * Can Sync. + * + * This method is filtered by payment gateways in order to return true on subscriptions + * that can sync through the merchant processor. + * + * @return mixed + */ + public function can_sync() { + return apply_filters( 'give_subscription_can_sync', false, $this ); + } + + /** + * Get Cancel URL. + * + * @return mixed + */ + public function get_cancel_url() { + + $url = wp_nonce_url( add_query_arg( array( + 'give_action' => 'cancel_subscription', + 'sub_id' => $this->id, + ) ), "give-recurring-cancel-{$this->id}" ); + + return apply_filters( 'give_subscription_cancel_url', $url, $this ); + } + + + /** + * Can Update. + * + * @since 1.1.2 + * @return mixed + */ + public function can_update() { + return apply_filters( 'give_subscription_can_update', false, $this ); + } + + /** + * Can Update Subscription. + * + * @since 1.8 + * @return mixed + */ + public function can_update_subscription() { + return apply_filters( 'give_subscription_can_update_subscription', false, $this ); + } + + /** + * Get Update URL. + * + * Retrieves the URL to update subscription. + * + * @since 1.1.2 + * @return string $url + */ + public function get_update_url() { + + $url = add_query_arg( array( + 'action' => 'update', + 'subscription_id' => $this->id, + ) ); + + return apply_filters( 'give_subscription_update_url', $url, $this ); + } + + /** + * Get Edit Subscription URL + * + * @since 1.8 + * @return string + */ + public function get_edit_subscription_url() { + + $url = add_query_arg( array( + 'action' => 'edit_subscription', + 'subscription_id' => $this->id, + ), give_get_subscriptions_page_uri() ); + + return apply_filters( 'give_subscription_edit_subscription_url', $url, $this ); + } + + /** + * Is Active. + * + * @return bool $ret Whether the subscription is active or not. + */ + public function is_active() { + + $ret = false; + + if ( ! $this->is_expired() && ( $this->status == 'active' || $this->status == 'cancelled' ) ) { + $ret = true; + } + + return apply_filters( 'give_subscription_is_active', $ret, $this->id, $this ); + + } + + /** + * Is Complete. + * + * @return bool $ret Whether the subscription is complete or not. + */ + public function is_complete() { + + $ret = false; + + if ( 'completed' === $this->status ) { + $ret = true; + } + + return apply_filters( 'give_subscription_is_complete', $ret, $this->id, $this ); + + } + + + /** + * Is Expired. + * + * @return bool|string + */ + public function is_expired() { + + $ret = false; + + if ( 'expired' === $this->status ) { + $ret = true; + } + + return apply_filters( 'give_subscription_is_expired', $ret, $this->id, $this ); + + } + + /** + * Retrieves the expiration date. + * + * @return string + */ + public function get_expiration() { + return $this->expiration; + } + + /** + * Get Expiration Time. + * + * Retrieves the expiration date in a timestamp. + * + * @return int + */ + public function get_expiration_time() { + return strtotime( $this->expiration, current_time( 'timestamp' ) ); + } + + /** + * Retrieves the subscription status. + * + * @return int + */ + public function get_status() { + return $this->status; + } + + /** + * Get Subscription Progress. + * + * Returns the subscription progress compared to `bill_times` such as "1/3" or "1/ Ongoing". + * + * @return int + */ + public function get_subscription_progress() { + return sprintf( + '%1$s / %2$s', + $this->get_total_payments(), + 0 === intval( $this->bill_times ) ? __( 'Ongoing', 'give-recurring' ) : $this->bill_times + ); + } + + /** + * Get Subscription End Date. + * + * @return int + */ + public function get_subscription_end_time() { + + $bill_times = intval( $this->bill_times ); + + // Date out = the end of the subscription. + // Subtract 1 due to initial donation being counted. + $date_out = '+' . ( $bill_times - 1 ) . ' ' . $this->period; + + return strtotime( $date_out, strtotime( $this->created ) ); + + } + + /** + * Get the Subscription Renewal Date. + * + * @param bool $localized Flag to return date in localized format or not + * + * @return string + */ + public function get_renewal_date( $localized = true ) { + + $expires = $this->get_expiration_time(); + $frequency = ! empty( $this->frequency ) ? intval( $this->frequency ) : 1; + + // If renewal date is already in the future it's set so return it. + if ( $expires > current_time( 'timestamp' ) && $this->is_active() ) { + return $localized + ? date_i18n( give_date_format(), strtotime( $this->expiration ) ) + : date( 'Y-m-d H:i:s', strtotime( $this->expiration ) ); + } + + $last_payment = $this->get_last_payment(); + + // The renewal date is in the past, recalculate it based off last payment made on subscription. + // Fallback to current time if last payment returns nothing to prevent PHP notice and 1970 date. + $last_payment_timestamp = isset( $last_payment->post_date ) ? strtotime( $last_payment->post_date ) : current_time( 'timestamp' ); + $renewal_timestamp = strtotime( '+ ' . $frequency . $this->period . ' 23:59:59', $last_payment_timestamp ); + + return $localized + ? date_i18n( give_date_format(), $renewal_timestamp ) + : date( 'Y-m-d H:i:s', $renewal_timestamp ); + + } + + + /** + * Is Parent Payment. + * + * @since 1.2 + * + * @param int $donation_id Donation ID. + * + * @return bool + */ + public function is_parent_payment( $donation_id ) { + return give_recurring_is_parent_donation( $donation_id ); + } + + /** + * Payment Exists. + * + * @param string $txn_id transaction ID. + * + * @return bool + */ + public function payment_exists( $txn_id = '' ) { + global $wpdb; + + if ( empty( $txn_id ) ) { + return false; + } + + $txn_id = esc_sql( $txn_id ); + + $donation_meta_table_name = Give()->payment_meta->table_name; + $donation_id_col_name = Give()->payment_meta->get_meta_type() . '_id'; + + $donation = $wpdb->get_var( + " + SELECT {$donation_id_col_name} + FROM {$donation_meta_table_name} + WHERE meta_key = '_give_payment_transaction_id' + AND meta_value = '{$txn_id}' + LIMIT 1 + " + ); + + if ( $donation != null ) { + return true; + } + + return false; + } + + /** + * Get the parsed notes for a subscription as an array + * + * @since 1.4 + * + * @param integer $length The number of notes to get + * @param integer $paged What note to start at + * + * @return array The notes requsted + */ + public function get_notes( $length = 20, $paged = 1 ) { + + $length = is_numeric( $length ) ? $length : 20; + $offset = is_numeric( $paged ) && $paged != 1 ? ( ( absint( $paged ) - 1 ) * $length ) : 0; + + $all_notes = $this->get_raw_notes(); + $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) ); + + $desired_notes = array_slice( $notes_array, $offset, $length ); + + return $desired_notes; + + } + + /** + * Get the total number of notes we have after parsing + * + * @since 1.4 + * @return int The number of notes for the subscription + */ + public function get_notes_count() { + + $all_notes = $this->get_raw_notes(); + $notes_array = array_reverse( array_filter( explode( "\n\n", $all_notes ) ) ); + + return count( $notes_array ); + + } + + + /** + * Add a note for the subscription + * + * @since 1.4 + * + * @param string $note The note to add + * + * @return string|boolean The new note if added successfully, false otherwise. + */ + public function add_note( $note = '' ) { + + $note = trim( $note ); + if ( empty( $note ) ) { + return false; + } + + $notes = $this->get_raw_notes(); + + if ( empty( $notes ) ) { + $notes = ''; + } + + $note_string = date_i18n( 'F j, Y H:i:s', current_time( 'timestamp' ) ) . ' - ' . $note; + $new_note = apply_filters( 'give_subscription_add_note_string', $note_string ); + $notes .= "\n\n" . $new_note; + + do_action( 'give_subscription_pre_add_note', $new_note, $this->id ); + + $updated = $this->update( array( 'notes' => $notes ) ); + + if ( $updated ) { + $this->notes = $this->get_notes(); + } + + do_action( 'give_subscription_post_add_note', $this->notes, $new_note, $this->id ); + + // Return the formatted note, so we can test, as well as update any displays + return $new_note; + + } + + /** + * Get the notes column for the subscription. + * + * @since 1.4 + * @return string The Notes for the subscription, non-parsed + */ + private function get_raw_notes() { + + $all_notes = $this->subs_db->get_column( 'notes', $this->id ); + + return (string) $all_notes; + + } + + /** + * Convert object to array + * + * @since 1.4 + * + * @return array + */ + public function to_array() { + + $array = array(); + foreach ( get_object_vars( $this ) as $prop => $var ) { + + if ( is_object( $var ) && is_callable( array( $var, 'to_array' ) ) ) { + + $array[ get_class( $var ) ] = $var->to_array(); + + } else { + + $array[ $prop ] = $var; + + } + } + + return $array; + } + + /** + * Check if we can update subscription status or not + * + * It will help to prevent duplicate updates + * + * @param string $status + * + * @return bool + * @since 1.9.8 + * + */ + private function can_update_status( $status = '' ) { + return $status && ( $status !== $this->subs_db->get_column( 'status', $this->id ) ); + } + + /** + * Return sanitized donation amount which comes from webhook and formatted with standard formatting setting. (number of decimal: "2", decimal separator: "." ). + * + * @param float $donationAmount + * @param string $currencyCode + * + * @return float + * @since 1.10.5 + */ + private function mayBeSanitizeWebhookResponseDonationAmount( $donationAmount, $currencyCode ) { + // Is processing webhook for any payment gateway. + if ( empty( $_GET['give-listener'] ) ) { + return $donationAmount; + } + + $donationAmountStr = (string) $donationAmount; + $numberOfDecimal = give_get_price_decimals( $currencyCode ); + $thousandSeparator = give_get_price_thousand_separator( $currencyCode ); + $decimalSeparator = give_get_price_decimal_separator( $currencyCode ); + $amountPart = explode( '.', $donationAmountStr ); + + // Sanitize donation amount only if + // 1. number of decimal is set to zero for give currency. + // 2. "." is thousand separator. + // 3. amount formatted with ".". + // 4. number of decimal for amount is two. like 10.25 or 40.00 + if ( + ! $numberOfDecimal && + '.' === $thousandSeparator && + false !== strpos( $donationAmountStr, $thousandSeparator ) && + false === strpos( $donationAmountStr, $decimalSeparator ) && + 2 === count( $amountPart ) && + 2 === strlen( $amountPart[1] ) + ) { + $donationAmount = number_format( (float) $donationAmount, 10 ); + } + + return $donationAmount; + } +} diff --git a/src/LegacySubscriptions/includes/give-subscriptions-api.php b/src/LegacySubscriptions/includes/give-subscriptions-api.php new file mode 100644 index 0000000000..0946f14497 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-subscriptions-api.php @@ -0,0 +1,272 @@ +query_vars['status'] ) ? $wp_query->query_vars['status'] : null; + + if ( in_array( $input_status, $allowed ) ) { + $status = $input_status; + } + + if ( null !== $input_status && '' === $status ) { + $error['error'] = sprintf( __( '\'%s\' is not a valid status.', 'give-recurring' ), $input_status ); + + return $error; + } else { + return $status; + } + } + + + /** + * Give_Subscriptions_API constructor. + */ + public function __construct() { + add_filter( 'give_api_valid_query_modes', array( $this, 'add_valid_subscriptions_query' ) ); + add_filter( 'give_api_output_data', array( $this, 'add_give_subscription_endpoint' ), 10, 3 ); + } + + /** + * Add 'subscriptions' api endpoint. + * + * @param $queries + * + * @return array + */ + public function add_valid_subscriptions_query( $queries ) { + $queries[] .= 'subscriptions'; + $this->override = false; + + return $queries; + } + + /** + * Add Subscribers Endpoint + * + * @param $data + * @param $query_mode + * @param $api_object + * + * @return array $subscriptions + */ + public function add_give_subscription_endpoint( $data, $query_mode, $api_object ) { + + // Sanity check: don't mess with other API queries! + if ( 'subscriptions' !== $query_mode ) { + return $data; + } + + // Get query vars. + global $wp_query; + + // Get the status from input. + $status = $this->get_status_from_url(); + + if ( is_array( $status ) && array_key_exists( 'error', $status ) ) { + $error = $status; + + return $error; + } + + // Get the donor information from the input. + $queried_c = isset( $wp_query->query_vars['donor'] ) ? sanitize_text_field( $wp_query->query_vars['customer'] ) : null; + $donor = new Give_Donor( $queried_c ); + + if ( ! empty( $queried_c ) && ( ! $donor || ! $donor->id > 0 ) ) { + $error['error'] = sprintf( __( 'No donor found for %s!', 'give-recurring' ), $queried_c ); + + return $error; + } + + $count = 0; + $response_data = array(); + if ( isset( $wp_query->query_vars['id'] ) && is_numeric( $wp_query->query_vars['id'] ) ) { + + $subscriptions = array( + new Give_Subscription( $wp_query->query_vars['id'] ), + ); + + } else { + $paged = $this->get_paged(); + $per_page = $this->per_page(); + $offset = $per_page * ( $paged - 1 ); + $db = new Give_Subscriptions_DB(); + $subscriptions = $db->get_subscriptions( array( + 'number' => $per_page, + 'offset' => $offset, + 'customer_id' => $donor->id, + 'status' => $status, + ) ); + } + + if ( $subscriptions ) { + + $unset_info_keys = array( + 'product_id', + 'customer_id', + 'subs_db', + ); + + /** @var Give_Subscription $subscription */ + foreach ( $subscriptions as $subscription ) { + // Subscription object to array. + $response_data['subscriptions'][ $count ]['info'] = $subscription->to_array(); + $tmp_donor = (array) $response_data['subscriptions'][ $count ]['info']['donor']; + + // Remove `:protected` index key from array + $donor = array(); + foreach ( $tmp_donor as $donor_key => $donor_data ){ + if( false !== strpos( $donor_key, '*') ) { + continue; + } + + $donor[$donor_key] = $donor_data; + } + $response_data['subscriptions'][ $count ]['info']['donor'] = $donor; + + // Remove legacy array keys. + foreach ($unset_info_keys as $info_key ) { + if ( isset( $response_data['subscriptions'][ $count ]['info'][$info_key] ) ) { + unset( $response_data['subscriptions'][ $count ]['info'][$info_key] ); + } + } + + // Format amount. + $response_data['subscriptions'][ $count ]['info']['initial_amount'] = give_format_decimal( array( + 'donation_id' => $response_data['subscriptions'][ $count ]['info']['parent_payment_id'], + 'amount' => $response_data['subscriptions'][ $count ]['info']['initial_amount'], + 'dp' => true + ) ); + + // Format amount. + $response_data['subscriptions'][ $count ]['info']['recurring_amount'] = give_format_decimal( array( + 'donation_id' => $response_data['subscriptions'][ $count ]['info']['parent_payment_id'], + 'amount' => $response_data['subscriptions'][ $count ]['info']['recurring_amount'], + 'dp' => true + ) ); + + // Format amount. + $response_data['subscriptions'][ $count ]['info']['donor']['purchase_value'] = give_format_decimal( array( + 'donation_id' => $response_data['subscriptions'][ $count ]['info']['parent_payment_id'], + 'amount' => $response_data['subscriptions'][ $count ]['info']['donor']['purchase_value'], + 'dp' => true, + ) ); + + $response_data['subscriptions'][ $count ]['info']['currency'] = give_get_payment_currency_code( $response_data['subscriptions'][ $count ]['info']['parent_payment_id'] ); + $response_data['subscriptions'][ $count ]['info']['form_title'] = get_the_title( $response_data['subscriptions'][ $count ]['info']['form_id'] ); + + // Subscription Payments. + $subscription_payments = $subscription->get_child_payments(); + $response_data['subscriptions'][ $count ]['payments'] = array(); + + if ( ! empty( $subscription_payments ) ) : + + foreach ( $subscription_payments as $payment ) { + + array_push( $response_data['subscriptions'][ $count ]['payments'], array( + 'id' => $payment->ID, + 'amount' => $payment->total, + 'date' => date_i18n( get_option( 'date_format' ), strtotime( $payment->date ) ), + 'status' => $payment->status_nicename, + ) ); + + } + + endif; + + $count ++; + + } + } elseif ( ! empty( $queried_c ) ) { + + $error['error'] = sprintf( __( 'No subscriptions found for %s!', 'give-recurring' ), $queried_c ); + + return $error; + + } else { + + $error['error'] = __( 'No subscriptions found!', 'give-recurring' ); + + return $error; + + }// End if(). + + return $response_data; + + } +} diff --git a/src/LegacySubscriptions/includes/give-subscriptions-db.php b/src/LegacySubscriptions/includes/give-subscriptions-db.php new file mode 100644 index 0000000000..2c3e713287 --- /dev/null +++ b/src/LegacySubscriptions/includes/give-subscriptions-db.php @@ -0,0 +1,713 @@ +table_name = $wpdb->prefix . 'give_subscriptions'; + $this->primary_key = 'id'; + $this->version = '1.1'; + + parent::__construct(); + } + + /** + * Get columns and formats + * + * @access public + * @since 1.0 + */ + public function get_columns() + { + return array( + 'id' => '%d', + 'customer_id' => '%d', + 'period' => '%s', + 'frequency' => '%d', + 'initial_amount' => '%s', + 'recurring_amount' => '%s', + 'recurring_fee_amount' => '%F', + 'bill_times' => '%d', + 'transaction_id' => '%s', + 'parent_payment_id' => '%d', + 'product_id' => '%d', + 'created' => '%s', + 'expiration' => '%s', + 'status' => '%s', + 'notes' => '%s', + 'profile_id' => '%s', + ); + } + + + /** + * Get default column values + * + * @access public + * @since 1.0 + */ + public function get_column_defaults() + { + return array( + 'customer_id' => 0, + 'period' => '', + 'frequency' => 1, + 'initial_amount' => '', + 'recurring_amount' => '', + 'recurring_fee_amount' => 0, + 'bill_times' => 0, + 'transaction_id' => '', + 'parent_payment_id' => 0, + 'product_id' => 0, + 'created' => date('Y-m-d H:i:s'), + 'expiration' => date('Y-m-d H:i:s'), + 'status' => '', + 'notes' => '', + 'profile_id' => '', + ); + } + + /** + * Get subscription by specific data + * + * @param int $column + * @param int $row_id + * + * @return mixed|object + * @since 1.6 + * + */ + public function get_by($column, $row_id) + { + $cache_key = Give_Cache::get_key("{$column}_{$row_id}", array($column, $row_id), false); + $subscription = Give_Recurring_Cache::get_subscription($cache_key); + + if (is_null($subscription)) { + $subscription = parent::get_by($column, $row_id); + Give_Recurring_Cache::set_subscription($cache_key, $subscription); + } + + return $subscription; + } + + /** + * Get subscription + * + * @param int $row_id + * + * @return mixed|object + * @since 1.6 + */ + public function get($row_id) + { + $cache_key = Give_Cache::get_key($row_id, '', false); + $subscription = Give_Recurring_Cache::get_subscription($cache_key); + + if (is_null($subscription)) { + $subscription = parent::get($row_id); + Give_Recurring_Cache::set_subscription($cache_key, $subscription); + } + + return $subscription; + } + + /** + * Update subscription + * + * @param int $row_id + * @param array $data + * @param string $where + * + * @return bool + * @since 1.6 + * + */ + public function update($row_id, $data = array(), $where = '') + { + $status = parent::update($row_id, $data, $where); + + /** + * Fire the action when subscriptions updated + * + * @since 1.6 + */ + do_action('give_subscription_updated', $status, $row_id, $data, $where); + + return $status; + } + + /** + * Create subscription + * + * @param array $data + * + * @return int|mixed + * @since 1.6 + * + */ + public function create($data) + { + $subcription_id = parent::insert($data, 'subscription'); + + /** + * Fire the action when subscriptions updated + * + * @since 1.6 + */ + do_action('give_subscription_inserted', $subcription_id, $data); + + return $subcription_id; + } + + /** + * Delete subscription + * + * @param int $subscription_id + * + * @return bool + */ + public function delete($subscription_id = 0) + { + $subscriptionData = $this->get($subscription_id); + $status = parent::delete($subscription_id); + + /** + * Fire the action when subscriptions updated + * + * @since 1.6 + * @since 1.11.0 Added third parameter + */ + do_action('give_subscription_deleted', $status, $subscription_id, $subscriptionData); + + return $status; + } + + + /** + * Retrieve all subscriptions for a donor. + * + * @param array $args + * + * @access public + * @return Give_Subscription[] + * @since 1.0 + * + */ + public function get_subscriptions($args = array()) + { + global $wpdb; + + $defaults = array( + 'number' => 20, + 'offset' => 0, + 'search' => '', + 'form_id' => 0, + 'customer_id' => 0, + 'orderby' => 'id', + 'order' => 'DESC', + ); + + $args = wp_parse_args($args, $defaults); + + if ($args['number'] < 1) { + $args['number'] = 999999999999; + } + + + $args['orderby'] = !array_key_exists($args['orderby'], $this->get_columns()) ? 'id' : $args['orderby']; + + if ('amount' == $args['orderby']) { + $args['orderby'] = 'amount+0'; + } + + $cache_key = Give_Cache::get_key('give_subscriptions', $args, false); + $subscriptions = Give_Recurring_Cache::get_db_query($cache_key); + + // If no cache key, get subscriptions. + if (is_null($subscriptions)) { + $where = $this->generate_where_clause($args); + + $args['orderby'] = esc_sql($args['orderby']); + $args['order'] = esc_sql($args['order']); + + $subscriptions = $wpdb->get_results( + $wpdb->prepare( + "SELECT * FROM $this->table_name $where ORDER BY {$args['orderby']} {$args['order']} LIMIT %d,%d;", + absint($args['offset']), + absint($args['number']) + ), + OBJECT + ); + + if (!empty($subscriptions)) { + foreach ($subscriptions as $key => $subscription) { + $subscriptions[$key] = new Give_Subscription($subscription); + } + + Give_Recurring_Cache::set_db_query($cache_key, $subscriptions); + } + } + + return $subscriptions; + } + + + /** + * Count the total number of subscriptions in the database. + * + * @param array $args + * + * @return int|array/null + */ + public function count($args = array()) + { + global $wpdb; + + $cache_key = Give_Cache::get_key('give_subscriptions_count', $args, false); + $count = Give_Recurring_Cache::get_db_query($cache_key); + $group_by_args = !empty($args['groupBy']) ? $args['groupBy'] : ''; + $return_count = empty($group_by_args); + + $result = null; + + if (null === $count) { + $groupBy = $this->generate_groupby_clause($group_by_args); + $where = $this->generate_where_clause($args); + $count = $return_count ? "COUNT({$this->primary_key})" : "{$group_by_args}, COUNT({$this->primary_key})"; + $sql = "SELECT {$count} FROM {$this->table_name} {$where} {$groupBy};"; + + $result = $return_count ? $wpdb->get_var($sql) : $wpdb->get_results($sql, ARRAY_A); + + // Simplify result if query for groupBy. + if ($group_by_args && $result) { + $temp = array(); + foreach ($result as $data) { + $temp[$data[$group_by_args]] = $data['COUNT(id)']; + } + + $result = $temp; + } + + Give_Recurring_Cache::set_db_query($cache_key, $result); + } + + return $return_count ? absint($result) : $result; + } + + /** + * Create the table. + * + * @access public + * @since 1.0 + */ + public function create_table() + { + global $wpdb; + + if ($wpdb->get_var("SHOW TABLES LIKE '$this->table_name'") !== $this->table_name) { + require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); + + $sql = 'CREATE TABLE ' . $this->table_name . ' ( + id bigint(20) NOT NULL AUTO_INCREMENT, + customer_id bigint(20) NOT NULL, + period varchar(20) NOT NULL, + frequency bigint(20) DEFAULT "1" NOT NULL, + initial_amount decimal(18,10) NOT NULL, + recurring_amount decimal(18,10) NOT NULL, + recurring_fee_amount decimal(18,10) NOT NULL, + bill_times bigint(20) NOT NULL, + transaction_id varchar(60) NOT NULL, + parent_payment_id bigint(20) NOT NULL, + product_id bigint(20) NOT NULL, + created datetime NOT NULL, + expiration datetime NOT NULL, + status varchar(20) NOT NULL, + profile_id varchar(60) NOT NULL, + notes longtext NOT NULL, + PRIMARY KEY (id), + KEY profile_id (profile_id), + KEY customer (customer_id), + KEY transaction (transaction_id), + INDEX customer_and_status ( customer_id, status) + ) CHARACTER SET utf8 COLLATE utf8_general_ci;'; + + dbDelta($sql); + + update_option($this->table_name . '_db_version', $this->version); + } + } + + /** + * Get Renewing Subscriptions + * + * @param string $period + * + * @return array|bool|mixed|null|object + */ + public function get_renewing_subscriptions($period = '+1month') + { + global $wpdb; + + $args = array( + 'number' => 99999, + 'status' => 'active', + 'offset' => 0, + 'orderby' => 'id', + 'order' => 'DESC', + 'expiration' => array( + 'start' => date('Y-m-d H:i:s', strtotime($period . ' midnight')), + 'end' => date('Y-m-d H:i:s', strtotime($period . ' midnight') + (DAY_IN_SECONDS - 1)), + ), + ); + + $cache_key = Give_Cache::get_key('give_renewing_subscriptions', $args, false); + $subscriptions = Give_Recurring_Cache::get_db_query($cache_key); + + if (is_null($subscriptions)) { + $where = $this->generate_where_clause($args); + $where .= ' AND `bill_times` != 0'; + $where .= ' AND ( SELECT COUNT(ID) FROM ' . $wpdb->prefix . 'posts WHERE `post_parent` = ' . $this->table_name . '.`parent_payment_id` OR `ID` = ' . $this->table_name . '.`parent_payment_id` ) + 1 < `bill_times`'; + + $query = $wpdb->prepare( + "SELECT * FROM $this->table_name $where ORDER BY {$args['orderby']} {$args['order']} LIMIT %d,%d;", + absint($args['offset']), + absint($args['number']) + ); + $subscriptions = $wpdb->get_results($query); + Give_Recurring_Cache::set_db_query($cache_key, $subscriptions); + } + + return $subscriptions; + } + + /** + * Get expiring subscriptions. + * + * @param string $period + * + * @return array|bool|mixed|null|object + */ + public function get_expiring_subscriptions($period = '+1month') + { + global $wpdb; + + $args = array( + 'number' => 99999, + 'status' => 'active', + 'offset' => 0, + 'orderby' => 'id', + 'order' => 'DESC', + 'expiration' => array( + 'start' => date('Y-m-d H:i:s', strtotime($period . ' midnight')), + 'end' => date('Y-m-d H:i:s', strtotime($period . ' midnight') + (DAY_IN_SECONDS - 1)), + ), + ); + + $cache_key = Give_Cache::get_key('give_expiring_subscriptions', $args, false); + $subscriptions = Give_Recurring_Cache::get_db_query($cache_key); + + if (is_null($subscriptions)) { + $where = $this->generate_where_clause($args); + $where .= ' AND `bill_times` != 0'; + $where .= ' AND ( SELECT COUNT(ID) FROM ' . $wpdb->prefix . 'posts WHERE `post_parent` = ' . $this->table_name . '.`parent_payment_id` OR `ID` = ' . $this->table_name . '.`parent_payment_id` ) + 1 >= `bill_times`'; + + $query = $wpdb->prepare( + "SELECT * FROM $this->table_name $where ORDER BY {$args['orderby']} {$args['order']} LIMIT %d,%d;", + absint($args['offset']), + absint($args['number']) + ); + $subscriptions = $wpdb->get_results($query); + Give_Recurring_Cache::set_db_query($cache_key, $subscriptions); + } + + return $subscriptions; + } + + /** + * Generate a cache key from args. + * + * @param $prefix + * @param $args + * + * @return string + * @deprecated 1.6 + * + */ + protected function generate_cache_key($prefix, $args) + { + return md5($prefix . serialize($args)); + } + + /** + * Build the query args for subscriptions. + * + * @param array $args + * + * @return string The mysql "where" query part. + */ + public function generate_where_clause($args = array()) + { + $where = ' WHERE 1=1'; + + // Specific ID. + if (!empty($args['id'])) { + if (is_array($args['id'])) { + $ids = implode(',', array_map('intval', $args['id'])); + } else { + $ids = intval($args['id']); + } + + $where .= " AND `id` IN( {$ids} ) "; + } + + // Specific donation forms. + if (!empty($args['form_id'])) { + if (is_array($args['form_id'])) { + $form_ids = implode(',', array_map('intval', $args['form_id'])); + } else { + $form_ids = intval($args['form_id']); + } + + $where .= " AND `product_id` IN( {$form_ids} ) "; + } + + // Specific parent payments + if (!empty($args['parent_payment_id'])) { + if (is_array($args['parent_payment_id'])) { + $parent_payment_ids = implode(',', array_map('intval', $args['parent_payment_id'])); + } else { + $parent_payment_ids = intval($args['parent_payment_id']); + } + + $where .= " AND `parent_payment_id` IN( {$parent_payment_ids} ) "; + } + + // @TODO: Remove after consolidating terminology. + if (isset($args['donor_id']) && !empty($args['donor_id'])) { + $args['customer_id'] = $args['donor_id']; + } + + // Subscriptions for specific customers/donors + if (!empty($args['customer_id'])) { + if (is_array($args['customer_id'])) { + $customer_ids = implode(',', array_map('intval', $args['customer_id'])); + } else { + $customer_ids = intval($args['customer_id']); + } + + $where .= " AND `customer_id` IN( {$customer_ids} ) "; + } + + // Subscriptions for specific profile IDs + if (!empty($args['profile_id'])) { + if (is_array($args['profile_id'])) { + $profile_ids = implode('\',\'', $args['profile_id']); + } else { + $profile_ids = $args['profile_id']; + } + + $where .= " AND `profile_id` IN( '{$profile_ids}' ) "; + } + + // Specific transaction IDs + if (!empty($args['transaction_id'])) { + if (is_array($args['transaction_id'])) { + $transaction_ids = implode('\',\'', array_map('sanitize_text_field', $args['transaction_id'])); + } else { + $transaction_ids = sanitize_text_field($args['transaction_id']); + } + + $where .= " AND `transaction_id` IN( '{$transaction_ids}' ) "; + } + + // Subscriptions for specific statuses + if (!empty($args['status'])) { + if (is_array($args['status'])) { + $statuses = implode('\',\'', $args['status']); + $where .= " AND `status` IN( '{$statuses}' ) "; + } else { + $statuses = $args['status']; + $where .= " AND `status` = '{$statuses}' "; + } + } + + if (!empty($args['date'])) { + $where .= $this->mysql_where_args_date($args); + } + + if (!empty($args['expiration'])) { + $where .= $this->mysql_where_args_expiration($args); + } + + if (!empty($args['search'])) { + $where .= $this->mysql_where_args_search($args); + } + + return apply_filters('give_subscriptions_mysql_query', $where); + } + + /** + * Build the query args for subscriptions. + * + * @param string $groupby + * + * @return string The mysql "where" query part. + */ + private function generate_groupby_clause($groupby = '') + { + if (!$groupby) { + return ''; + } + + return "GROUP BY {$groupby}"; + } + + /** + * @param $args + * + * @return string + */ + private function mysql_where_args_search($args) + { + $where = ''; + $donors_db = new Give_DB_Donors(); + if (is_email($args['search'])) { + $customer = new Give_Donor($args['search']); + if ($customer && $customer->id > 0) { + $where = " AND `customer_id` = " . absint($customer->id) . ""; + } + } elseif (false !== strpos($args['search'], 'txn:')) { + $args['search'] = trim(str_replace('txn:', '', $args['search'])); + $where .= " AND `transaction_id` = '" . esc_sql($args['search']) . "'"; + } elseif (false !== strpos($args['search'], 'profile_id:')) { + $args['search'] = trim(str_replace('profile_id:', '', $args['search'])); + $where .= " AND `profile_id` = '" . esc_sql($args['search']) . "'"; + } elseif (false !== strpos($args['search'], 'form_id:')) { + $args['search'] = trim(str_replace('form_id:', '', $args['search'])); + $where .= " AND `product_id` = " . absint($args['search']) . ""; + } elseif (false !== strpos($args['search'], 'product_id:')) { + $args['search'] = trim(str_replace('product_id:', '', $args['search'])); + $where .= " AND `product_id` = " . absint($args['search']) . ""; + } elseif (false !== strpos($args['search'], 'customer_id:')) { + $args['search'] = trim(str_replace('customer_id:', '', $args['search'])); + $where .= " AND `customer_id` = '" . esc_sql($args['search']) . "'"; + } elseif (false !== strpos($args['search'], 'id:') || is_numeric($args['search'])) { + $args['search'] = trim(str_replace('id:', '', $args['search'])); + $where .= " AND `id` = " . absint($args['search']) . ""; + } else { + // See if search matches a product name + $form = get_page_by_title(trim($args['search']), OBJECT, 'give_forms'); + if ($form) { + $args['search'] = $form->ID; + $where .= " AND `product_id` = " . absint($args['search']) . ""; + } else { + global $wpdb; + $query = $wpdb->prepare( + " + SELECT id,name FROM {$donors_db->table_name} + WHERE name + LIKE '%%%s%%'", + $args['search'] + ); + $subscription_donor_id = array(); + $donor_ids = $wpdb->get_results($query, ARRAY_A); + if (!empty($donor_ids) && count($donor_ids) > 0) { + foreach ($donor_ids as $key => $val) { + $subscription_donor_id[] = absint($val['id']); + } + } + $subscription_donor_id = implode(',', array_map('intval', $subscription_donor_id)); + $where .= " AND {$this->table_name}.customer_id IN ({$subscription_donor_id})"; + } + }// End if(). + return $where; + } + + /** + * @param $args + * + * @return string + */ + private function mysql_where_args_date($args) + { + $where = ''; + if (is_array($args['date'])) { + if (!empty($args['date']['start'])) { + $start = date('Y-m-d H:i:s', strtotime($args['date']['start'])); + $where .= " AND `expiration` >= '{$start}'"; + } + if (!empty($args['date']['end'])) { + $end = date('Y-m-d H:i:s', strtotime($args['date']['end'])); + $where .= " AND `expiration` <= '{$end}'"; + } + } else { + $year = date('Y', strtotime($args['date'])); + $month = date('m', strtotime($args['date'])); + $day = date('d', strtotime($args['date'])); + $where .= " AND $year = YEAR ( created ) AND $month = MONTH ( created ) AND $day = DAY ( created )"; + } + + return $where; + } + + /** + * @param $args + * + * @return string + */ + private function mysql_where_args_expiration($args) + { + $where = ''; + + if (is_array($args['expiration'])) { + if (!empty($args['expiration']['start'])) { + $start = date('Y-m-d H:i:s', strtotime($args['expiration']['start'])); + + $where .= " AND `expiration` >= '{$start}'"; + } + + if (!empty($args['expiration']['end'])) { + $end = date('Y-m-d H:i:s', strtotime($args['expiration']['end'])); + + $where .= " AND `expiration` <= '{$end}'"; + } + } else { + $year = date('Y', strtotime($args['expiration'])); + $month = date('m', strtotime($args['expiration'])); + $day = date('d', strtotime($args['expiration'])); + + $where .= " AND $year = YEAR ( expiration ) AND $month = MONTH ( expiration ) AND $day = DAY ( expiration )"; + } + + return $where; + } + +} diff --git a/src/Subscriptions/ServiceProvider.php b/src/Subscriptions/ServiceProvider.php new file mode 100644 index 0000000000..2f7ea85f84 --- /dev/null +++ b/src/Subscriptions/ServiceProvider.php @@ -0,0 +1,27 @@ + Date: Fri, 7 Jan 2022 14:23:02 -0500 Subject: [PATCH 02/15] refactor: move checkout action back into recurring --- .../includes/give-recurring-helpers.php | 67 ------------------- .../includes/give-recurring-template.php | 18 ++--- 2 files changed, 9 insertions(+), 76 deletions(-) diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index 1bdcb94983..4fd9af1f4a 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -1944,73 +1944,6 @@ function give_recurring_install_table($old_version) add_filter('update_option_give_recurring_version', 'give_recurring_install_table', 0, 1); add_filter('add_option_give_recurring_version', 'give_recurring_install_table', 0, 1); -/** - * Subscription donation processing errors - * 1. Check if current gateway support recurring donation or not. - * - * Note: only for internal use - * - * @param array $valid_data - * @since 1.8.11 - * - * - */ -function give_recurring_checkout_errors($valid_data) -{ - $post_data = give_clean($_POST); // WPCS: input var ok, sanitization ok, CSRF ok. - - // Show an error if the current payment gateway does not support subscription donations. - if ( - !empty($post_data['_give_is_donation_recurring']) - && !Give_Recurring::get_gateway_class($valid_data['gateway']) - ) { - $enabled_payment_gateways = give_get_enabled_payment_gateways(absint($post_data['give-form-id'])); - $has_multi_gateway_choice = 1 < count($enabled_payment_gateways); - - $suggestion_msg = ''; - - if ($has_multi_gateway_choice) { - $recurring_supported_gateways = array_intersect_key($enabled_payment_gateways, Give_Recurring::$gateways); - $recurring_supported_gateways_count = count($recurring_supported_gateways); - $recurring_supported_gateway_list = implode( - ', ', - wp_list_pluck($recurring_supported_gateways, 'checkout_label') - ); - - if (1 < $recurring_supported_gateways_count) { - $recurring_supported_gateway_list = substr_replace( - $recurring_supported_gateway_list, - ' ' . __('or', 'give-recurring'), - strrpos($recurring_supported_gateway_list, ','), - 1 - ); - } - - $suggestion_msg = sprintf( - _n( - 'Please switch to the %1$s payment gateway to process a subscription donation.', - 'Please switch to either the %1$s payment gateways to process a subscription donation.', - $recurring_supported_gateways_count, - 'give-recurring' - ), - $recurring_supported_gateway_list - ); - } - - - give_set_error( - 'recurring_gateway_not_supported', - sprintf( - __('Sorry we\'re unable to process subscription donations with %1$s.%2$s', 'give-recurring'), - $enabled_payment_gateways[$valid_data['gateway']]['checkout_label'], - $has_multi_gateway_choice ? ' ' . $suggestion_msg : '' - ) - ); - } -} - -add_action('give_checkout_error_checks', 'give_recurring_checkout_errors', 0, 1); - /** * This function will add form tags when required for update payment method. * diff --git a/src/LegacySubscriptions/includes/give-recurring-template.php b/src/LegacySubscriptions/includes/give-recurring-template.php index ed27778d33..5b5f0f6d99 100644 --- a/src/LegacySubscriptions/includes/give-recurring-template.php +++ b/src/LegacySubscriptions/includes/give-recurring-template.php @@ -131,17 +131,17 @@ function give_recurring_donors_choice_period_element( $form_id ) { echo ''; From 2a77b5d1a498aaa6a677a8292711c3a8da3523e0 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Fri, 7 Jan 2022 14:54:49 -0500 Subject: [PATCH 03/15] refactor: move filter/action specific functions back into recurring --- src/LegacySubscriptions/ServiceProvider.php | 3 - .../includes/give-recurring-functions.php | 444 ---- .../includes/give-recurring-helpers.php | 1997 ----------------- .../includes/give-recurring-shortcodes.php | 295 --- .../includes/give-recurring-template.php | 347 --- src/Subscriptions/Models/LegacySubscriber.php | 12 +- 6 files changed, 4 insertions(+), 3094 deletions(-) delete mode 100644 src/LegacySubscriptions/includes/give-recurring-functions.php delete mode 100644 src/LegacySubscriptions/includes/give-recurring-shortcodes.php delete mode 100644 src/LegacySubscriptions/includes/give-recurring-template.php diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index cee3be4d0b..78dc03c366 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -42,11 +42,8 @@ private function includeLegacyFiles() require_once __DIR__ . '/includes/give-recurring-cache.php'; require_once __DIR__ . '/includes/give-subscription.php'; require_once __DIR__ . '/includes/give-subscriptions-api.php'; - require_once __DIR__ . '/includes/give-recurring-shortcodes.php'; require_once __DIR__ . '/includes/give-recurring-subscriber.php'; - require_once __DIR__ . '/includes/give-recurring-template.php'; require_once __DIR__ . '/includes/give-recurring-helpers.php'; - require_once __DIR__ . '/includes/give-recurring-functions.php'; require_once __DIR__ . '/includes/give-recurring-emails.php'; require_once __DIR__ . '/includes/give-recurring-renewals.php'; require_once __DIR__ . '/includes/give-recurring-expirations.php'; diff --git a/src/LegacySubscriptions/includes/give-recurring-functions.php b/src/LegacySubscriptions/includes/give-recurring-functions.php deleted file mode 100644 index 2206e8210e..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-functions.php +++ /dev/null @@ -1,444 +0,0 @@ - $subscription_id, - 'order' => 'ASC', - 'search' => $search, - 'type' => 'give_sub_note', - ) - ); - - add_action( 'pre_get_comments', 'give_hide_subscription_notes', 10 ); - add_filter( 'comments_clauses', 'give_hide_subscription_notes_pre_41', 10, 2 ); - - return $notes; -} - -/** - * Add a note to a subscription. - * - * @param int $subscription_id The subscription ID to store a note for. - * @param string $note The note to store. - * - * @since 1.8 - * - * @return int The new note ID - */ -function give_insert_subscription_note( $subscription_id = 0, $note = '' ) { - if ( empty( $subscription_id ) ) { - return false; - } - - /** - * Fires before inserting subscription note. - * - * @param int $subscription_id Subscription ID. - * @param string $note The note. - * - * @since 1.8 - */ - do_action( 'give_pre_insert_subscription_note', $subscription_id, $note ); - - $note_id = wp_insert_comment( - wp_filter_comment( - array( - 'comment_post_ID' => $subscription_id, - 'comment_content' => $note, - 'user_id' => is_admin() ? get_current_user_id() : 0, - 'comment_date' => current_time( 'mysql' ), - 'comment_date_gmt' => current_time( 'mysql', 1 ), - 'comment_approved' => 1, - 'comment_parent' => 0, - 'comment_author' => '', - 'comment_author_IP' => '', - 'comment_author_url' => '', - 'comment_author_email' => '', - 'comment_type' => 'give_sub_note', - - ) - ) - ); - - /** - * Fires after payment note inserted. - * - * @param int $note_id Note ID. - * @param int $subscription_id Subscription ID. - * @param string $note The note. - * - * @since 1.8 - */ - do_action( 'give_insert_subscription_note', $note_id, $subscription_id, $note ); - - return $note_id; -} - -/** - * Deletes a subscription note. - * - * @param int $comment_id The comment ID to delete. - * @param int $subscription_id The subscription ID the note is connected to. - * - * @since 1.0 - * - * @return bool True on success, false otherwise. - */ -function give_delete_subscription_note( $comment_id = 0, $subscription_id = 0 ) { - if ( empty( $comment_id ) ) { - return false; - } - - /** - * Fires before deleting donation note. - * - * @param int $comment_id Note ID. - * @param int $subscription_id Subscription ID. - * - * @since 1.8 - */ - do_action( 'give_pre_delete_subscription_note', $comment_id, $subscription_id ); - - $ret = wp_delete_comment( $comment_id, true ); - - /** - * Fires after donation note deleted. - * - * @param int $comment_id Note ID. - * @param int $subscription_id Subscription ID. - * - * @since 1.8 - */ - do_action( 'give_post_delete_subscription_note', $comment_id, $subscription_id ); - - return $ret; -} - -/** - * Gets the subscription note HTML - * - * @param object|int $note The comment object or ID. - * @param int $subscription_id The subscription ID the note is connected to. - * - * @since 1.8 - * - * @return string - */ -function give_get_subscription_note_html( $note, $subscription_id = 0 ) { - - if ( is_numeric( $note ) ) { - $note = get_comment( $note ); - } - - if ( ! empty( $note->user_id ) ) { - $user = get_userdata( $note->user_id ); - $user = $user->display_name; - } else { - $user = __( 'System', 'give-recurring' ); - } - - $date_format = give_date_format() . ', ' . get_option( 'time_format' ); - - $note_html = '
'; - $note_html .= '

'; - $note_html .= '' . $user . ' – ' . date_i18n( $date_format, strtotime( $note->comment_date ) ) . '
'; - $note_html .= $note->comment_content; - $note_html .= ' – ' . __( 'Delete', 'give-recurring' ) . ''; - $note_html .= '

'; - $note_html .= '
'; - - return $note_html; - -} - -/** - * Exclude notes (comments) on subscription notes from showing in Recent - * Comments widgets - * - * @param object $query WordPress Comment Query Object. - * - * @since 1.8 - * - * @return void - */ -function give_hide_subscription_notes( $query ) { - if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '>=' ) ) { - $types = isset( $query->query_vars['type__not_in'] ) ? $query->query_vars['type__not_in'] : array(); - if ( ! is_array( $types ) ) { - $types = array( $types ); - } - $types[] = 'give_sub_note'; - $query->query_vars['type__not_in'] = $types; - } -} - -add_action( 'pre_get_comments', 'give_hide_subscription_notes', 10 ); - -/** - * Exclude notes (comments) on give_sub_note post type from showing in Recent Comments widgets - * - * @param array $clauses Comment clauses for comment query. - * @param object $wp_comment_query WordPress Comment Query Object. - * - * @since 1.8 - * - * @return array $clauses Updated comment clauses. - */ -function give_hide_subscription_notes_pre_41( $clauses, $wp_comment_query ) { - if ( version_compare( floatval( get_bloginfo( 'version' ) ), '4.1', '<' ) ) { - $clauses['where'] .= ' AND comment_type != "give_sub_note"'; - } - - return $clauses; -} - -add_filter( 'comments_clauses', 'give_hide_subscription_notes_pre_41', 10, 2 ); - -/** - * Exclude notes (comments) give_subscription_note from showing in comment feeds - * - * @param string $where - * @param object $wp_comment_query WordPress Comment Query Object. - * - * @since 1.8 - * - * @return string $where - */ -function give_hide_subscription_notes_from_feeds( $where, $wp_comment_query ) { - global $wpdb; - - $where .= $wpdb->prepare( ' AND comment_type != %s', 'give_sub_note' ); - - return $where; -} - -add_filter( 'comment_feed_where', 'give_hide_subscription_notes_from_feeds', 10, 2 ); - -/** - * Remove Give Comments from the wp_count_comments function - * - * @param array $stats (empty from core filter). - * @param int $post_id Post ID. - * - * @access public - * @since 1.8 - * - * @return array|object Array of comment counts. - */ -function give_remove_subscription_notes_in_comment_counts( $stats, $post_id ) { - global $wpdb, $pagenow; - - if ( 'index.php' !== $pagenow ) { - return $stats; - } - - $post_id = (int) $post_id; - - if ( apply_filters( 'give_count_subscription_notes_in_comments', false ) ) { - return $stats; - } - - $stats = Give_Cache::get_group( "comments-{$post_id}", 'counts' ); - - if ( ! is_null( $stats ) ) { - return $stats; - } - - $where = 'WHERE comment_type != "give_sub_note"'; - - if ( $post_id > 0 ) { - $where .= $wpdb->prepare( ' AND comment_post_ID = %d', $post_id ); - } - - $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} {$where} GROUP BY comment_approved", ARRAY_A ); - - $total = 0; - $approved = array( - '0' => 'moderated', - '1' => 'approved', - 'spam' => 'spam', - 'trash' => 'trash', - 'post-trashed' => 'post-trashed', - ); - foreach ( (array) $count as $row ) { - // Don't count post-trashed toward totals. - if ( 'post-trashed' !== $row['comment_approved'] && 'trash' !== $row['comment_approved'] ) { - $total += $row['num_comments']; - } - if ( isset( $approved[ $row['comment_approved'] ] ) ) { - $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments']; - } - } - - $stats['total_comments'] = $total; - foreach ( $approved as $key ) { - if ( empty( $stats[ $key ] ) ) { - $stats[ $key ] = 0; - } - } - - $stats = (object) $stats; - Give_Cache::set_group( "comments-{$post_id}", $stats, 'counts' ); - - return $stats; -} - -add_filter( 'wp_count_comments', 'give_remove_subscription_notes_in_comment_counts', 10, 2 ); - -/** - * AJAX Store subscription Note. - */ -function give_ajax_store_subscription_note() { - - $subscription_id = absint( $_POST['subscription_id'] ); - $note = wp_kses( $_POST['note'], array() ); - - if ( empty( $subscription_id ) ) { - die( '-1' ); - } - - if ( empty( $note ) ) { - die( '-1' ); - } - - $note_id = give_insert_subscription_note( $subscription_id, $note ); - die( give_get_subscription_note_html( $note_id ) ); -} - -add_action( 'wp_ajax_give_insert_subscription_note', 'give_ajax_store_subscription_note' ); - -/** - * Delete a subscription note deletion with ajax. - * - * @since 1.8 - * - * @return void - */ -function give_ajax_delete_subscription_note() { - - // Gather POST variables data. - $post_data = give_clean( $_POST ); - - // Security Check. - check_admin_referer( 'give_recurring_admin_ajax_secure_nonce', 'security' ); - - // Permission Check. - if ( ! current_user_can( 'delete_give_payments' ) ) { - $permission_notice = Give()->notices->print_admin_notices( array( - 'id' => 'give-permission-error', - 'description' => __( 'You are not permitted to delete the subscription note.', 'give-recurring' ), - 'echo' => false, - 'notice_type' => 'error', - ) ); - wp_send_json_error( $permission_notice ); - } - - // Send success JSON response, if subscription note deleted successfully. - if ( give_delete_subscription_note( $post_data['note_id'], $post_data['subscription_id'] ) ) { - wp_send_json_success(); - } - - // Else send JSON error response. - $deletion_error_notice = Give()->notices->print_admin_notices( array( - 'id' => 'give-permission-error', - 'description' => __( 'Unable to delete subscription note. Please try again.', 'give-recurring' ), - 'echo' => false, - 'notice_type' => 'error', - ) ); - wp_send_json_error( $deletion_error_notice ); - -} - -add_action( 'wp_ajax_give_delete_subscription_note', 'give_ajax_delete_subscription_note' ); - -/** - * This filter will be used to trigger email access on subscriptions page to store email access session. - * - * @since 1.8.5 - */ -function give_recurring_check_email_access_on_subscription_page( $status ) { - - return ( give_recurring_is_subscriptions_page() || $status ); -} - -add_filter( 'give_is_email_access_on_page', 'give_recurring_check_email_access_on_subscription_page' ); - -/** - * Get table list - * - * @since 1.9.0 - * @return array - */ -function give_recurring_get_tables() { - return array( - 'subscription' => new Give_Subscriptions_DB(), - 'subscription_meta' => new Give_Recurring_DB_Subscription_Meta(), - ); -} - - -/** - * Register plugin tables - * - * @sinc 1.9.0 - */ -function give_recurring_register_tables(){ - $tables = give_recurring_get_tables(); - - /* @var Give_DB $table */ - foreach ( $tables as $table ) { - if( ! $table->installed() ) { - $table->register_table(); - } - } -} - - -/** - * Update a subscription as abandoned if the payment is abandoned. - * - * @since 1.12.3 - * - * @param \Give_Payment $payment - */ -function give_recurring_update_abandoned_subscription( $payment ) { - - $db = new Give_Subscriptions_DB; - $results = $db->get_subscriptions([ - 'parent_payment_id' => $payment->ID, - ]); - - if ( $results ) { - // Only one subscription should be returned, but the return value is an array. - foreach ( $results as $result ) { - $subscription = new \Give_Subscription( $result->id ); - // Using the Give_Subscription API to update the status will also add a note to the record. - $subscription->update([ 'status' => 'abandoned' ]); - } - } -} -add_action( 'give_post_abandoned_payment', 'give_recurring_update_abandoned_subscription' ); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index 4fd9af1f4a..b65aa2565a 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -8,2003 +8,6 @@ * @since 1.0 */ -// Exit if accessed directly. -if (!defined('ABSPATH')) { - exit; -} - -/** - * Get pretty subscription frequency - * - * @param string $period Recurring Period. - * @param string|bool $times Recurring Times. - * @param bool $lowercase Lowercase Label. - * @param int $interval Recurring Interval. - * - * @return mixed|string - */ -function give_recurring_pretty_subscription_frequency($period, $times = false, $lowercase = false, $interval = 1) -{ - // Convert interval to integer, if it is string. - if (is_string($interval)) { - $interval = (int)$interval; - } - - $frequency = ''; - $frequency_data = give_recurring_simplify_pretty_subscription_frequency($period, $interval); - $period = $frequency_data['period']; - $interval = $frequency_data['interval']; - $pretty_interval = give_recurring_pretty_interval($interval); - $pretty_periods = give_recurring_get_default_pretty_periods(); - $pretty_period = isset($pretty_periods[$period]) ? $pretty_periods[$period] : ''; - $plural_period = give_recurring_get_pretty_plural_period($period); - - // Proceed only, if recurring times is positive number. - if ($times > 0) { - // Get pretty text for recurring time. - $pretty_time = give_recurring_pretty_time($times, true); - - // Proceed only, if interval is 1, 3, or 6 to display related label. - if (1 === $interval) { - $frequency = sprintf( - /* translators: 1. Pretty Interval, 2. Pretty Time, 3. Plural period */ - __('%1$s for %2$s %3$s', 'give-recurring'), - $pretty_period, - $pretty_time, - $plural_period - ); - } else { - $frequency = sprintf( - /* translators: 1. Pretty Interval, 2. Pretty Time, 3. Plural period */ - __('%1$s %3$s for %2$s %3$s', 'give-recurring'), - $pretty_interval, - $pretty_time, - $plural_period - ); - } - - /** - * This filter hook is used to change the recurring label. - * But, we recommend that you use 'give_recurring_pretty_subscription_frequency' filter for the same purpose. - * - * Note: This filter will be deprecated in future. - */ - $frequency = apply_filters( - 'give_recurring_receipt_details_multiple', - $frequency, - $period, - $pretty_interval, - $interval - ); - } else { - // Proceed only, if interval is 1, 3, or 6 to display related label. - if (1 === $interval) { - $frequency = "{$pretty_period}"; - } else { - $frequency = sprintf( - /* translators: 1. Pretty Recurring Interval 2. Plural Period. */ - __('%1$s %2$s', 'give-recurring'), - $pretty_interval, - $plural_period - ); - } - - /** - * This filter hook is used to change the recurring label. - * But, we recommend that you use 'give_recurring_pretty_subscription_frequency' filter for the same purpose. - * - * Note: This filter will be deprecated in future. - */ - $frequency = apply_filters('give_recurring_receipt_details', $frequency, $period, $pretty_interval, $interval); - } - - // If lowercase is true then convert the frequency label to lowercase. - if ($lowercase) { - $frequency = strtolower($frequency); - } - - // If frequency is empty then set frequency is One Time. - if (empty($frequency)) { - $frequency = __('One Time', 'give-recurring'); - } - - /** - * This filter hook is used to change the recurring label. - */ - return apply_filters( - 'give_recurring_pretty_subscription_frequency', - $frequency, - $period, - $pretty_interval, - $interval - ); -} - -/** - * This function is used to simplify the terms for the other gateways which can have different words in period. - * - * Note: Use this function for display purposes, not for storing data to DB. - * - * @param string $period Subscription Period. - * @param string $interval Subscription Interval. - * - * @return array - * @since 1.9.1 - * - */ -function give_recurring_simplify_pretty_subscription_frequency($period, $interval) -{ - if ('month' === substr($period, 0, 5)) { - if (3 === $interval) { - $period = 'quarter'; - $interval = 1; - } elseif (12 === $interval) { - $period = 'year'; - $interval = 1; - } else { - $period = 'month'; - } - } elseif ('day' === substr($period, 0, 3)) { - if (7 === $interval) { - $period = 'week'; - $interval = 1; - } else { - $period = 'day'; - } - } - - return array( - 'period' => $period, - 'interval' => $interval, - ); -} - -/** - * Get Pretty description of Interval. - * - * @param int $interval Recurring Interval. - * - * @return string - * @since 1.6.0 - * - */ -function give_recurring_pretty_interval($interval = 1) -{ - $pretty_interval_list = give_recurring_get_default_pretty_intervals(); - $recurring_interval = $pretty_interval_list[$interval]; - - /** - * Modify pretty interval string. - * - * @param string $recurring_interval - * @param string $interval - * @since 1.6.0 - * - */ - return apply_filters('give_recurring_pretty_interval', $recurring_interval, $interval); -} - -/** - * Get list of default pretty intervals. - * - * @return array - * @since 1.7.0 - * - */ -function give_recurring_get_default_pretty_intervals() -{ - /** - * This filter hook is used to set default pretty intervals. - * - * @since 1.7.0 - */ - return (array)apply_filters( - 'give_recurring_get_default_pretty_intervals', array( - '1' => __('Every', 'give-recurring'), - '2' => __('Every two', 'give-recurring'), - '3' => __('Every three', 'give-recurring'), - '4' => __('Every four', 'give-recurring'), - '5' => __('Every five', 'give-recurring'), - '6' => __('Every six', 'give-recurring'), - ) - ); -} - -/** - * Get pretty plural version of a period. - * - * Appears in recurring donation levels (e.g "for six months"). - * - * @param string $period Time period. Accepts 'day', 'week', 'month', 'year'. - * @return array - * @since 1.8.3 - * - */ -function give_recurring_get_pretty_plural_period($period) -{ - $periods = array( - 'day' => __('days', 'give-recurring'), - 'week' => __('weeks', 'give-recurring'), - 'month' => __('months', 'give-recurring'), - 'quarter' => __('quarters', 'give-recurring'), - 'year' => __('years', 'give-recurring'), - ); - - $pretty_period = isset($periods[$period]) ? $periods[$period] : ''; - - return $pretty_period; -} - -/** - * Get list of default pretty periods. - * - * @return array - * @since 1.7.0 - * - */ -function give_recurring_get_default_pretty_periods() -{ - /** - * This filter hook is used to set default pretty periods. - * - * @since 1.7.0 - */ - return (array)apply_filters( - 'give_recurring_get_default_pretty_periods', array( - 'day' => __('Daily', 'give-recurring'), - 'week' => __('Weekly', 'give-recurring'), - 'month' => __('Monthly', 'give-recurring'), - 'quarter' => __('Quarterly', 'give-recurring'), - 'half-year' => __('Semi-Annually', 'give-recurring'), - 'year' => __('Yearly', 'give-recurring'), - ) - ); -} - -/** - * Recurring Body Classes - * - * Add specific CSS class by filter - * - * @param $classes - * - * @return array - */ -function give_recurring_body_classes($classes) -{ - // add 'class-name' to the $classes array. - $classes[] = 'give-recurring'; - - // return the $classes array. - return $classes; -} - -add_filter('body_class', 'give_recurring_body_classes'); - -/** - * Recurring Form Specific Classes - * - * Add specific CSS class by filter - * - * @param $form_classes - * @param $form_id - * @param $form_args - * - * @return array - */ -function give_recurring_form_classes($form_classes, $form_id, $form_args) -{ - // Is this form recurring. - $recurring_option = give_get_meta($form_id, '_give_recurring', true); - - // Sanity check: only proceed with recurring forms. - if ('no' === $recurring_option) { - return $form_classes; - } - - // add 'class-name' to the $classes array. - $form_classes[] = 'give-recurring-form-wrap'; - $form_classes[] = 'give-recurring-form-' . ('yes_donor' === $recurring_option ? 'donor' : 'admin'); - - // return the $classes array. - return apply_filters('give_recurring_form_wrap_classes', $form_classes, $form_id, $form_args); -} - -add_filter('give_form_wrap_classes', 'give_recurring_form_classes', 10, 3); - -/** - * Add a Recurring Class to the Give Donation form Class - * - * Useful for themes and plugins JS to target recurring enabled forms - * - * @param $classes - * @param $form_id - * @param $args - * - * @return array - * @since 1.1 - * - */ -function give_recurring_enabled_form_class($classes, $form_id, $args) -{ - if (give_recurring_is_recurring($form_id)) { - $classes[] = 'give-recurring-form'; - } - - return $classes; -} - -add_filter('give_form_classes', 'give_recurring_enabled_form_class', 10, 3); - -/** - * Give Recurring Form Title - * - * Outputs the subscription title from purchase data; only form title if single level, if multi-level output will be - * the donation level followed by the selected level. If custom it will output the custom amount label. - * - * @param $purchase_data - * - * @return string - */ -function give_recurring_subscription_title($purchase_data) -{ - // Item name - pass level name if variable priced. - $item_name = $purchase_data['post_data']['give-form-title']; - $form_id = intval($purchase_data['post_data']['give-form-id']); - - // Verify has variable prices. - if (give_has_variable_prices($form_id) && isset($purchase_data['post_data']['give-price-id'])) { - $item_price_level_text = give_get_price_option_name($form_id, $purchase_data['post_data']['give-price-id']); - - $price_level_amount = give_get_price_option_amount($form_id, $purchase_data['post_data']['give-price-id']); - - // Donation given doesn't match selected level (must be a custom amount). - if ($price_level_amount != give_sanitize_amount($purchase_data['price'])) { - $custom_amount_text = give_get_meta($form_id, '_give_custom_amount_text', true); - // user custom amount text if any, fallback to default if not - $item_name .= ' - ' . (!empty($custom_amount_text) ? $custom_amount_text : __( - 'Custom Amount', - 'give-recurring' - )); - } // End if(). - elseif (!empty($item_price_level_text)) { - $item_name .= ' - ' . $item_price_level_text; - } - } // End if(). - elseif (give_get_form_price($form_id) !== give_sanitize_amount($purchase_data['price'])) { - $custom_amount_text = give_get_meta($form_id, '_give_custom_amount_text', true); - // user custom amount text if any, fallback to default if not. - $item_name .= ' - ' . (!empty($custom_amount_text) ? $custom_amount_text : __( - 'Custom Amount', - 'give-recurring' - )); - } - - return $item_name; -} - -/** - * Get pretty subscription status - * - * @param $status - * - * @return string $status_formatted - */ -function give_recurring_get_pretty_subscription_status($status) -{ - $status_formatted = ''; - $statuses = give_recurring_get_subscription_statuses(); - - // Format period details. - if (!empty($status) && array_key_exists($status, $statuses)) { - foreach ($statuses as $status_key => $value) { - if ($status === $status_key) { - $status_formatted = ' ' . $value . ''; - } - } - } else { - $status_formatted = apply_filters('give_recurring_subscription_frequency', $status_formatted, $status); - } - - return $status_formatted; -} - -/** - * Subscription Plan Name - * - * @param $form_id - * @param $price_id - * - * @return bool|string - */ -function give_recurring_generate_subscription_name($form_id, $price_id = null) -{ - if (empty($form_id)) { - return false; - } - - $subscription_name = get_post_field('post_title', $form_id); - - // Backup for forms with no titles. - if (empty($subscription_name)) { - $subscription_name = __('Untitled Donation Form', 'give-recurring'); - } - - // Check for multi-level. - if (give_has_variable_prices($form_id) && is_numeric($price_id)) { - $subscription_name .= ' - ' . give_get_price_option_name($form_id, $price_id); - } - - return apply_filters('give_recurring_subscription_name', $subscription_name); -} - -/** - * Retrieve the Subscriptions page URI - * - * @access public - * @return int $page_id Subscription Page. - * @since 1.7 - * - */ -function give_recurring_subscriptions_page_id() -{ - $page_id = absint(give_get_option('subscriptions_page', 0)); - - /** - * Filter to modify subscriptions page id. - * - * @param int $page_id - * @since 1.7 - * - */ - return apply_filters('give_recurring_subscriptions_page_id', $page_id); -} - -/** - * Retrieve the Subscriptions page URI - * - * @access public - * @return string - * @since 1.1 - */ -function give_get_subscriptions_page_uri() -{ - $subscriptions_page = get_permalink(give_recurring_subscriptions_page_id()); - - /** - * Filter to modify subscriptions page URL. - * - * @param int $subscriptions_page - * @since 1.1 - * - */ - return apply_filters('give_get_subscriptions_page_uri', $subscriptions_page); -} - -/** - * Is Donation Form Recurring - * - * @param $form_id - * - * @return bool - */ -function give_is_form_recurring($form_id) -{ - $recurring_option = give_get_meta($form_id, '_give_recurring', true); - - // Sanity check: only proceed with recurring forms. - if (!empty($recurring_option) && 'no' !== $recurring_option) { - return true; - } - - return false; -} - -/** - * Adds a hidden field so Recurring can tell whether this form is for logged in users only. - * - * @param int $form_id - * - * @since 1.4 - */ -function give_recurring_is_logged_in_only_form_hidden_field($form_id) -{ - $logged_in_only = give_get_meta($form_id, '_give_logged_in_only', true); - $logged_in_only = give_is_setting_enabled($logged_in_only); - ?> - - - - array( - 'level_id' => 'custom', - ), - '_give_amount' => 0, // We can't bring amount before submitting donation form. - '_give_text' => '', - '_give_default' => '', - '_give_recurring' => 'yes', - '_give_period' => $recurring_period, - '_give_times' => $recurring_times, - '_give_period_interval' => $recurring_interval, - ); - } - - return array(); -} - -/** - * This will add a message to the multi level forms so that user can understand whether it is a one time or recurring - * donation. - * - * @param $output - * @param $form_id - * - * @return string - * @since 1.4 - * - */ -function give_recurring_admin_defined_explanation($output, $form_id) -{ - // Only output on recurring admin defined forms. - $recurring_option = give_get_meta($form_id, '_give_recurring', true); - - if ('yes_admin' !== $recurring_option) { - return $output; - } - - $prices = give_get_variable_prices($form_id); - - // Loop through prices to identify the default price. - $default_price = give_recurring_get_default_price($form_id, $recurring_option); - foreach ($prices as $price) { - if (isset($price['_give_default']) && 'default' === $price['_give_default']) { - $default_price = $price; - } - } - - $output .= '

'; - $output .= give_recurring_get_multi_levels_notification_message($default_price, $form_id); - $output .= '

'; - - return apply_filters('give_recurring_admin_defined_explanation_output', $output); -} - -add_action('give_form_level_output', 'give_recurring_admin_defined_explanation', 10, 2); - -/** - * This ajax function will return message to be displayed to notify users. - * - * @return mixed - * @since 1.4 - * - */ -function give_recurring_notify_user_on_level_change() -{ - $form_id = isset($_POST['formID']) ? absint($_POST['formID']) : false; - // Bail Out, if formID is not present in post variables. - if (!$form_id) { - return; - } - - $value = 0; - $default_price['_give_amount'] = isset($_POST['amount']) ? give_clean($_POST['amount']) : ''; - - $price_id = isset($_POST['priceID']) ? give_clean($_POST['priceID']) : 0; - - // Get list of levels defined. - $prices = give_get_variable_prices($form_id); - - // Loop through prices to identify the default price. - $prices[] = give_recurring_get_default_price($form_id); - - foreach ($prices as $price) { - if (isset($price['_give_id']['level_id']) && $price_id === $price['_give_id']['level_id']) { - $price['_give_amount'] = empty($price['_give_amount']) ? $default_price['_give_amount'] : $price['_give_amount']; - $default_price = $price; - - if (!empty($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { - $value = 1; - } - } - } - - $response = array(); - $response['html'] = give_recurring_get_multi_levels_notification_message($default_price, $form_id); - $response['period_label'] = give_recurring_get_selected_period_label($default_price); - $response['is_recurring'] = $value; - - wp_send_json_success($response); -} - -add_action('wp_ajax_give_recurring_notify_user_on_levels', 'give_recurring_notify_user_on_level_change'); -add_action('wp_ajax_nopriv_give_recurring_notify_user_on_levels', 'give_recurring_notify_user_on_level_change'); - -/** - * This function will return a message based on the Price Level Array provided. - * - * @param array $price Donation price ID. - * @param integer $form_id Donation Form ID. - * - * @return string - * @since 1.6.2 Passing additional arg $form_id. - * - * @since 1.4 - */ -function give_recurring_get_multi_levels_notification_message($price = array(), $form_id) -{ - $message = ''; - $period_label = __('once', 'give-recurring'); - $recurring_times = isset($price['_give_times']) ? $price['_give_times'] : false; - $give_amount = isset($price['_give_amount']) ? $price['_give_amount'] : 0; - $interval = !empty($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; - - // If Recurring is enabled, then show a different message else show one time message. - if (isset($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { - $period_label = give_recurring_pretty_subscription_frequency( - $price['_give_period'], - $recurring_times, - true, - $interval - ); - } - - // Show message for custom amount whether it is one time or recurring donation. - $message .= sprintf( - __('You have chosen to donate %s.', 'give-recurring'), - sprintf( - ' %1$s %2$s', - give_currency_filter( - give_format_amount( - $give_amount, - array( - 'sanitize' => false, - ) - ), - array( - 'currency_code' => give_get_currency($form_id), - ) - ), - $period_label - ) - ); - - return apply_filters('give_recurring_multi_levels_notification_message', $message, $price, $form_id); -} - -/** - * SVG image of Give Recurring Img tag. - * - * @since 1.5.1 - */ -function give_recurring_symbol_img() -{ - return ''; -} - -/** - * This function will help identify type of donations on Donation History Page. - * - * @param int $donation_amount Donation Amount. - * @param int $donation_id Donation ID. - * - * @return string - * @since 1.4 - * - */ -function give_recurring_add_recurring_label($donation_amount, $donation_id) -{ - $subscription = new Give_Subscription(); - $status = $subscription->is_parent_payment($donation_id); - - // Add Recurring label if donation is of recurring type. - if (true === $status) { - return $donation_amount . ' ' . give_recurring_symbol_img() . ' '; - } - - return $donation_amount; -} - -add_filter('give_donation_history_row_amount', 'give_recurring_add_recurring_label', 10, 2); - - -/** - * Adds the "_give_is_donation_recurring" hidden field. - * - * This can be used to easily determine if a donation has been made recurring on submit. - * - * @param $form_id - * - * @return Void - * @since 1.5.1 - * - */ -function give_recurring_after_donation_levels($form_id) -{ - // Get the recurring is enable or not. - $recurring_support = (string)give_get_meta($form_id, '_give_recurring', true); - - if (empty($recurring_support) || 'no' === $recurring_support) { - return; - } - - // default value. - $value = 0; - $checkbox_default = ''; - $price_option = ''; - - // if it's on donor. - if ('yes_donor' === $recurring_support) { - // check if default option in form is checked or not. - $checkbox_default = give_get_meta($form_id, '_give_checkbox_default', true); - - if (!empty($checkbox_default) && 'yes' === $checkbox_default) { - $value = 1; - } - } elseif ('yes_admin' === $recurring_support) { - // Get the Donation type. - $price_option = give_get_meta($form_id, '_give_price_option', true); - - // check if donation type is multi. - if (!empty($price_option) && 'multi' === $price_option) { - $levels = maybe_unserialize(give_get_meta($form_id, '_give_donation_levels', true)); - foreach ($levels as $price) { - if (!empty($price['_give_default']) && !empty($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { - $value = 1; - } - } - } else { - $value = 1; - } - } - - printf( - '', - $value, - $recurring_support, - $checkbox_default, - $price_option - ); -} - -add_action('give_donation_form_top', 'give_recurring_after_donation_levels', 10); - -/** - * Get Recurring Donation Form Details. - * - * @param int $form_id Form ID. - * @since 1.8.1 - * - */ -function give_recurring_donation_form_details($form_id) -{ - $recurring_information = array(); - - $give_non_recurring_pretty_text = __('once', 'give-recurring'); - if (give_is_form_recurring($form_id)) { - $recurring_option = give_get_meta($form_id, '_give_recurring', true, 'no'); - $give_price_option = give_get_meta($form_id, '_give_price_option', true, 'no'); - $recurring_period_duration = ''; - $recurring_frequency = '1'; - $recurring_times = give_get_meta($form_id, '_give_times', true, '0'); - - if ('yes_admin' === $recurring_option) { - $price_option = give_get_meta($form_id, '_give_price_option', true); - - // check if donation type is multi. - if (!empty($price_option) && 'multi' === $price_option) { - $prices = give_get_variable_prices($form_id); - - foreach ($prices as $price) { - $level_id = $price['_give_id']['level_id']; - $is_recurring = isset($price['_give_recurring']) ? $price['_give_recurring'] : 'no'; - - if ('no' !== $is_recurring) { - if (isset($price['_give_period'])) { - $recurring_period_duration = $price['_give_period']; - } - - if (isset($price['_give_period_interval'])) { - $recurring_frequency = $price['_give_period_interval']; - } - - if (isset($price['_give_times'])) { - $recurring_times = $price['_give_times']; - } - - $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( - $recurring_period_duration, - $recurring_times, - $lowercase = false, - $recurring_frequency - ); - } else { - $give_recurring_pretty_text = $give_non_recurring_pretty_text; - } - - $recurring_information[$give_price_option][$level_id]['_give_recurring'] = $is_recurring; - $recurring_information[$give_price_option][$level_id]['give_recurring_pretty_text'] = $give_recurring_pretty_text; - } - - $give_custom_amount = give_get_meta($form_id, '_give_custom_amount', true, 'disabled'); - - // Check if Custom amount. - if (give_is_setting_enabled($give_custom_amount)) { - $level_id = 'custom'; - $recurring_period_duration = give_get_meta( - $form_id, - '_give_recurring_custom_amount_period', - true, - 'month' - ); - $recurring_frequency = give_get_meta($form_id, '_give_recurring_custom_amount_interval', true, '1'); - $recurring_times = give_get_meta($form_id, '_give_recurring_custom_amount_times', true, '0'); - - $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( - $recurring_period_duration, - $recurring_times, - $lowercase = false, - $recurring_frequency - ); - - if ('once' === $recurring_period_duration) { - $give_recurring_pretty_text = $give_non_recurring_pretty_text; - $recurring_information[$give_price_option][$level_id]['_give_recurring'] = 'no'; - } else { - $recurring_information[$give_price_option][$level_id]['_give_recurring'] = 'yes'; - } - - $recurring_information[$give_price_option][$level_id]['give_recurring_pretty_text'] = $give_recurring_pretty_text; - } - } - } else { - $recurring_information['give_recurring_option'] = 'yes_donor'; - } - } else { - $recurring_information['is_recurring'] = false; - } - - /** - * Get Multi-Level Admin defined Recurring Information. - * - * @param array $recurring_information - * @param int $form_id - * - * @return array $recurring_information - * @since 1.8.1 - * - */ - $recurring_information = apply_filters('give_recurring_donation_form_details', $recurring_information, $form_id); - - $recurring_details = wp_json_encode($recurring_information); - - printf( - '', - esc_js($recurring_details) - ); -} - -add_action('give_donation_form_top', 'give_recurring_donation_form_details', 10); - -/** - * Add Field to Payment Meta - * - * Store the custom field data custom post meta attached to the `give_payment` CPT. - * - * @param $payment_id - * @param $payment_data - * - * @return mixed - */ -function give_recurring_insert_payment($payment_id) -{ - if (isset($_POST['_give_is_donation_recurring'])) { - $give_recurring_donation = empty($_POST['_give_is_donation_recurring']) ? 0 : absint( - give_clean($_POST['_give_is_donation_recurring']) - ); - give_update_meta($payment_id, '_give_is_donation_recurring', $give_recurring_donation); - } -} - -add_action('give_insert_payment', 'give_recurring_insert_payment', 10); - -/** - * Updates a payment status. - * - * @param int $sub_id Subscription ID. - * @param string $new_status New Payment Status. Default is 'active'. - * - * @return bool - * @since 1.5.1 - * - */ -function give_recurring_update_subscription_status($sub_id, $new_status = 'active') -{ - $updated = false; - $subscription = new Give_Subscription(absint($sub_id)); - $old_status = $subscription->status; - - /** - * Fire Action before the subscription status is change. - * - * @since 1.5.8 - */ - do_action( - 'give_recurring_before_subscription_status_get_update', $sub_id, array( - 'new_status' => $new_status, - 'old_status' => $old_status, - ) - ); - - if ($subscription && $subscription->id > 0) { - $updated = $subscription->update( - array( - 'status' => sanitize_text_field($new_status), - ) - ); - } - - /** - * Fire Action after the subscription status is changed. - * - * @since 1.5.8 - */ - do_action( - 'give_recurring_after_subscription_status_updated', $sub_id, array( - 'new_status' => $new_status, - 'old_status' => $old_status, - 'updated' => $updated, - ) - ); - - return $updated; -} - -/** - * Cancel the subscription. - * - * @param int $sub_id Subscription ID. - * - * @return bool - * @since 1.5.1 - * - */ -function give_recurring_subscription_cancel($sub_id) -{ - $subscription = new Give_Subscription(absint($sub_id)); - - if (!$subscription->can_cancel()) { - return false; - } - - do_action('give_recurring_cancel_' . $subscription->gateway . '_subscription', $subscription, true); - - $subscription->cancel(); - - return true; -} - -/** - * Fire when subscription status change to cancelled. - * - * @param $sub_id - * @param $subscription_details - * @since 1.5.8 - * - */ -function give_recurring_get_cancel($sub_id, $subscription_details) -{ - if (!empty($subscription_details['new_status']) && 'cancelled' === $subscription_details['new_status']) { - give_recurring_subscription_cancel($sub_id); - } -} - -add_action('give_recurring_after_subscription_status_updated', 'give_recurring_get_cancel', 10, 2); - -/** - * Delete the subscription. - * - * @param int $sub_id Subscription ID. - * - * @return bool - * @since 1.5.1 - * - */ -function give_recurring_subscription_delete($sub_id) -{ - $updated = false; - $subscription = new Give_Subscription(absint($sub_id)); - - if ($subscription && $subscription->id > 0) { - delete_post_meta($subscription->parent_payment_id, '_give_subscription_payment'); - - $updated = $subscription->delete(); - } - - return $updated; -} - -/** - * Get Subscription details by ID. - * - * @param string $type Type of ID Passed ( Payment or Profile ). - * @param int $id Payment ID or Profile ID based on parameter $type - * - * @return bool|Give_Subscription - * @since 1.5.6 - * - */ -function give_recurring_get_subscription_by($type = 'payment', $id) -{ - // Bail Out, if ID is not present. - if (empty($id)) { - return false; - } - - $subscription = false; - - switch ($type) { - case 'payment': - $subscription_db = new Give_Subscriptions_DB(); - $subscription = $subscription_db->get_subscriptions( - array( - 'parent_payment_id' => $id, - 'number' => 1, - ) - ); - - if (is_array($subscription) && count($subscription) > 0) { - $subscription = $subscription[0]; - } - break; - - case 'profile': - $subscription = new Give_Subscription($id, true); - break; - } - - return $subscription; -} - -/** - * Get the Subscription for the Donor - * - * @param int $donor_id Pass the donor id or user ID of which Subscription list should get fetch. - * @param array $args Array of arguments. - * - * @return array Subscription list for the donor. - * @since 1.5.8 - * - */ -function give_recurring_get_donor_subscriptions($donor_id, $args = array()) -{ - // Set Subscription args. - $args = wp_parse_args( - $args, - array( - 'form_id' => 0, - 'by_user_id' => false, - ) - ); - - $subscriber = new Give_Recurring_Subscriber($donor_id, $args['by_user_id']); - unset($args['by_user_id']); - - return $subscriber->get_subscriptions($args['form_id'], $args); -} - -/** - * Get the list of all the subscription statuses key - * - * @return array $statuses_key - * @since 1.5.8 - * - */ -function give_recurring_get_subscription_statuses_key() -{ - /** - * Filter to modify the list of subscription statuses key. - * - * @return array $status - * @since 1.5.8 - * - */ - return (array)apply_filters( - 'give_recurring_get_subscription_statuses_key', - array_keys(give_recurring_get_subscription_statuses()) - ); -} - -/** - * Get the list of all the subscription statuses - * - * @return array $status - * @since 1.5.8 - * - */ -function give_recurring_get_subscription_statuses() -{ - /** - * Filter to modify the list of subscription statuses. - * - * @return array $statuses - * @since 1.5.8 - * - */ - return (array)apply_filters( - 'give_recurring_get_subscription_statuses', array( - 'active' => __('Active', 'give-recurring'), - 'expired' => __('Expired', 'give-recurring'), - 'completed' => __('Completed', 'give-recurring'), - 'cancelled' => __('Cancelled', 'give-recurring'), - 'pending' => __('Pending', 'give-recurring'), - 'failing' => __('Failing', 'give-recurring'), - 'suspended' => __('Suspended', 'give-recurring'), - 'abandoned' => __('Abandoned', 'give-recurring'), - ) - ); -} - -/** - * Get Selected Recurring Period Label. - * - * @param array $price List of prices. - * - * @return string - * @since 1.5.8 - * - */ -function give_recurring_get_selected_period_label($price = array()) -{ - $period_label = __('once', 'give-recurring'); - $recurring_times = isset($price['_give_times']) ? $price['_give_times'] : false; - $frequency = !empty($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; - - // If Recurring is enabled, then show a different message else show one time message. - if (isset($price['_give_recurring']) && 'yes' === $price['_give_recurring']) { - $period_label = give_recurring_pretty_subscription_frequency( - $price['_give_period'], - $recurring_times, - true, - $frequency - ); - } - - return $period_label; -} - -/** - * Display text after final donation total label - * - * @param int $form_id Form ID. - * - * @since 1.5.8 - */ -function give_recurring_after_donation_total_text_callback($form_id) -{ - if (give_is_form_recurring($form_id)) { - $recurring_option = give_get_meta($form_id, '_give_recurring', true, 'no'); - $recurring_default = give_get_meta($form_id, '_give_checkbox_default', true, 'no'); - $recurring_period_duration = ''; - $recurring_frequency = '1'; - $recurring_times = give_get_meta($form_id, '_give_times', true, '0'); - - if ('yes_donor' === $recurring_option) { - $recurring_period = give_get_meta($form_id, '_give_period_functionality', true, 'admin_choice'); - if ('admin_choice' === $recurring_period && 'yes' === $recurring_default) { - $recurring_period_duration = give_get_meta($form_id, '_give_period', true, 'month'); - } elseif ('donors_choice' === $recurring_period && 'yes' === $recurring_default) { - $recurring_period_duration = give_get_meta( - $form_id, - '_give_period_default_donor_choice', - true, - 'month' - ); - } - - $recurring_frequency = give_get_meta($form_id, '_give_period_interval', true, '1'); - } elseif ('yes_admin' === $recurring_option) { - $price_option = give_get_meta($form_id, '_give_price_option', true); - - // check if donation type is multi. - if (!empty($price_option) && 'multi' === $price_option) { - $prices = give_get_variable_prices($form_id); - $default_price = array(); - foreach ($prices as $price) { - if ( - !empty($price['_give_default']) && - 'default' === $price['_give_default'] && - !empty($price['_give_recurring']) && - 'yes' === $price['_give_recurring'] - ) { - $default_price = $price; - } - } - - if (isset($default_price['_give_period'])) { - $recurring_period_duration = $default_price['_give_period']; - } - - if (isset($default_price['_give_period_interval'])) { - $recurring_frequency = $default_price['_give_period_interval']; - } - - if (isset($default_price['_give_times'])) { - $recurring_times = $default_price['_give_times']; - } - } else { - $recurring_period_duration = give_get_meta($form_id, '_give_period', true, 'month'); - $recurring_frequency = give_get_meta($form_id, '_give_period_interval', true, '1'); - } - } - - $give_recurring_pretty_text = give_recurring_pretty_subscription_frequency( - $recurring_period_duration, - $recurring_times, - $lowercase = false, - $recurring_frequency - ); - - echo sprintf( - '%2$s', - empty($recurring_period_duration) ? 'give-hidden' : '', - $give_recurring_pretty_text - ); - } -} - -add_action('give_donation_final_total_label_after', 'give_recurring_after_donation_total_text_callback'); - -/** - * Get Billing times for the Donation level. - * - * @param int $form_id - * - * @return array - * @since 1.6.0 - * - */ -function give_recurring_get_billing_times($form_id) -{ - $billing_limits = array(); - $levels = give_get_meta($form_id, '_give_donation_levels', true); - - // Bail out, if levels not array and empty. - if (empty($levels) && !is_array($levels)) { - return $billing_limits; - } - - foreach ($levels as $level_id => $level) { - if (isset($level['_give_times'])) { - $billing_limits[$level_id] = give_clean($level['_give_times']); - } - } - - return $billing_limits; -} - -/** - * Calculate recurring times. - * - * e.g. Quarterly for 12 months. It means that subscription will charge for 4 times. - * - * @param $times - * @param $frequency - * - * @return int - * @since 1.6.0 - * - */ -function give_recurring_calculate_times($times, $frequency) -{ - // Set frequency default if empty. - if (empty($frequency)) { - $frequency = 1; - } - - $times = absint($times) / absint($frequency); - - /** - * Modify Billing times. - * - * @param $times - * @since 1.6.0 - * - */ - return apply_filters('give_recurring_calculate_times', $times); -} - -/** - * Get pretty time string. - * - * Convert number to words if 'times' less than 10. - * - * @param string $times - * @param bool $lowercase default true, Display lowercase text - * - * @return string - * @since 1.6.0 - * - */ -function give_recurring_pretty_time($times, $lowercase = true) -{ - if ($times >= '10') { - return $times; - } - - $pretty_time = array( - '1' => __('One', 'give-recurring'), - '2' => __('Two', 'give-recurring'), - '3' => __('Three', 'give-recurring'), - '4' => __('Four', 'give-recurring'), - '5' => __('Five', 'give-recurring'), - '6' => __('Six', 'give-recurring'), - '7' => __('Seven', 'give-recurring'), - '8' => __('Eight', 'give-recurring'), - '9' => __('Nine', 'give-recurring'), - ); - - $times = $pretty_time[$times]; - - if ($lowercase) { - $times = strtolower($times); - } - - /** - * Update Recurring pretty time string. - * - * @param string $times - * @param bool $lowercase default true, Display lowercase text - * @since 1.6.0 - * - */ - return apply_filters('give_recurring_pretty_time', $times, $lowercase); -} - -/** - * Get metadata to pass in Stripe. - * - * @param array $purchase_data List of Purchase Data. - * @param int $donation_id Donation ID. - * - * @return array $metadata - * @since 1.6.0 - * - */ -function give_recurring_get_metadata($purchase_data, $donation_id = 0) -{ - $form_id = !empty($purchase_data['post_data']['give-form-id']) ? intval( - $purchase_data['post_data']['give-form-id'] - ) : 0; - - $metadata = array( - 'first_name' => $purchase_data['user_info']['first_name'], - 'last_name' => $purchase_data['user_info']['last_name'], - 'created_by' => $purchase_data['post_data']['give-form-title'], - ); - - // Add address to customer metadata if present. - if (isset($purchase_data['user_info']['address']) && !empty($purchase_data['user_info']['address'])) { - $metadata['address_line1'] = !empty($purchase_data['user_info']['address']['line1']) ? $purchase_data['user_info']['address']['line1'] : ''; - $metadata['address_line2'] = !empty($purchase_data['user_info']['address']['line2']) ? $purchase_data['user_info']['address']['line2'] : ''; - $metadata['address_city'] = !empty($purchase_data['user_info']['address']['city']) ? $purchase_data['user_info']['address']['city'] : ''; - $metadata['address_state'] = !empty($purchase_data['user_info']['address']['state']) ? $purchase_data['user_info']['address']['state'] : ''; - $metadata['address_country'] = !empty($purchase_data['user_info']['address']['country']) ? $purchase_data['user_info']['address']['country'] : ''; - $metadata['address_zip'] = !empty($purchase_data['user_info']['address']['zip']) ? $purchase_data['user_info']['address']['zip'] : ''; - } - - // Proceed to add ffm field to stripe meta only if fn exists. - if (function_exists('give_stripe_get_custom_ffm_fields')) { - // Add custom ffm fields to stripe metadata. - $metadata = array_merge($metadata, give_stripe_get_custom_ffm_fields($form_id)); - } - - /** - * Pass metadata stripe. - * - * @param array $metadata Metadata passed to the Stripe. - * @param array $donation_data Donation data. - * @since 1.6.0 - * - */ - $metadata = apply_filters('give_recurring_stripe_metadata', $metadata, $purchase_data); - - // Limit metadata passed to Stripe as maximum of 20 metadata is only allowed. - if (count($metadata) > 20) { - $metadata = array_slice($metadata, 0, 19, false); - $metadata = array_merge( - $metadata, array( - 'More Details' => esc_url_raw( - admin_url( - 'edit.php?post_type=give_forms&page=give-payment-history&view=view-payment-details&id=' . $donation_id - ) - ), - ) - ); - } - - return $metadata; -} - -/** - * Determines if we're currently on the Subscriptions page. - * - * @return bool True if on the Subscriptions page, false otherwise. - * @since 1.7 - * - */ -function give_recurring_is_subscriptions_page() -{ - $ret = is_page(give_recurring_subscriptions_page_id()); - - /** - * Filter to modify is subscriptions page. - * - * @param bool $ret True if on the Subscriptions page, false otherwise. - * @since 1.7 - * - */ - return apply_filters('give_recurring_is_subscriptions_page', $ret); -} - -/** - * Exports upcoming subscription renewals - * data in CSV format - * - * @return void - * @since 1.7 - * - */ -function give_recurring_export_subscription_renewal_csv() -{ - require_once GIVE_RECURRING_PLUGIN_DIR . 'includes/admin/tools/class-give-export-subscriptions.php'; - - $earnings_export = new Give_Subscriptions_Renewals_Export(); - - $earnings_export->export(); -} - -add_action('give_subscriptions_renewal_export', 'give_recurring_export_subscription_renewal_csv'); - -/** - * Get Card object. - * - * @param Give_Recurring_Subscriber $subscriber Subscriber. - * @param Give_Subscription $subscription Subscription. - * - * @return array|bool - * @since 1.7 - * - */ -function give_recurring_get_card_details($subscriber, $subscription) -{ - // Sanity Check: Subscribers only - if ($subscriber->id <= 0) { - Give()->notices->print_frontend_notice( - __('You have not made any recurring donations.', 'give-recurring'), - true, - 'warning' - ); - - return false; - } - - // Bail out if subscription can not be updated or gateway deactivated. - if (!$subscription->can_update()) { - Give()->notices->print_frontend_notice( - __('Subscription can not be updated.', 'give-recurring'), - true, - 'warning' - ); - - return false; - } - - $gateway = $subscription->gateway; - $payment_id = $subscription->parent_payment_id; - - $card_info = array(); - - switch ($gateway) { - case 'stripe': - case 'stripe_checkout': - case 'stripe_google_pay': - case 'stripe_apple_pay': - // Get Stripe customer id. - $customer_id = Give()->donor_meta->get_meta($subscriber->id, give_stripe_get_customer_key(), true); - - // Get Stripe Customer ID from Donation meta if not stored in Donor meta. - if (empty($customer_id)) { - $customer_id = give_get_meta($payment_id, '_give_stripe_customer_id', true); - } - - // Bail out if Stripe Customer ID not stored in DB. - if (empty($customer_id)) { - Give()->notices->print_frontend_notice( - __('Stripe Customer ID not exist.', 'give-recurring'), - true, - 'error' - ); - - return false; - } - - try { - $subscription_id = $subscription->profile_id; - $stripe_subscription = \Stripe\Subscription::retrieve($subscription_id); - - if (!empty($stripe_subscription->default_payment_method)) { - $stripe_payment_method = new Give_Stripe_Payment_Method(); - $default_payment_method = $stripe_payment_method->retrieve( - $stripe_subscription->default_payment_method - ); - $card = $default_payment_method->card; - } else { - $customer = \Stripe\Customer::retrieve($customer_id); - $default_payment_method = !empty($customer->default_source) ? - $customer->default_source : - $customer->invoice_settings->default_payment_method; - $give_payment_method = new Give_Stripe_Payment_Method(); - $payment_method_details = $give_payment_method->retrieve($default_payment_method); - $card = $payment_method_details->card; - } - } catch (Exception $e) { - give_stripe_record_log( - __('Stripe - Update Payment Method', 'give-recurring'), - sprintf( - __('Unable to fetch default payment method of the customer. Details: %1$s', 'give-recurring'), - $e - ) - ); - } - - $card_info['last_digit'] = isset($card->last4) ? $card->last4 : ''; - $card_info['exp_month'] = isset($card->exp_month) ? $card->exp_month : ''; - $card_info['exp_year'] = isset($card->exp_year) ? $card->exp_year : ''; - $card_info['cc_type'] = isset($card->brand) ? $card->brand : ''; - - break; - case 'authorize': - // Work on Authorize CC details. - $authorize = new Give_Recurring_Authorize(); - - // Get PayPal Pro Card object - $cc_details = $authorize->get_subscription_cc_details($subscription); - - $expirationDate = explode('-', $cc_details['expirationDate']); - - $card_info['exp_month'] = 'XX'; - $card_info['exp_year'] = 'XX'; - if (isset($expirationDate) && is_array($expirationDate)) { - $card_info['exp_month'] = $expirationDate[1]; - $card_info['exp_year'] = $expirationDate[0]; - } - - $card_info['last_digit'] = substr($cc_details['cardNumber'], 4); - $card_info['cc_type'] = $cc_details['cardType']; - - break; - case 'paypalpro': - $paypal_pro = new Give_Recurring_PayPal_Website_Payments_Pro(); - - // Get PayPal Pro Card object - $cc_details = $paypal_pro->get_subscription_cc_details($subscription); - $card_info['last_digit'] = isset($cc_details['ACCT']) ? $cc_details['ACCT'] : ''; - $card_info['cc_type'] = isset($cc_details['CREDITCARDTYPE']) ? $cc_details['CREDITCARDTYPE'] : ''; - $card_info['exp_month'] = isset($cc_details['EXPDATE']) ? substr($cc_details['EXPDATE'], 0, 2) : ''; - $card_info['exp_year'] = isset($cc_details['EXPDATE']) ? substr($cc_details['EXPDATE'], 2) : ''; - break; - } - - /** - * Update Card Information. - * - * @param Give_Recurring_Subscriber $subscriber - * @param Give_Subscription $subscription - * - * @return array $card_info - * @since 1.7 - * - */ - return apply_filters('give_recurring_get_card_details', $card_info, $subscriber, $subscription); -} - -/** - * Add recurring checkbox in Donation form goal format - * - * @return void - * @since 1.7 - * - */ -function give_recurring_add_goal_recurring_checkbox($field) -{ - global $thepostid; - $value = 1; - $recurring_goal_format = give_recurring_goal_format_enable($thepostid); - ?> -

- > - -

- absint($form_id), - ); - $args = wp_parse_args($args, $defaults); - - $db = new Give_Subscriptions_DB(); - - return $subscriptions = $db->get_subscriptions($args); -} - -/** - * Check if donation form goal based on recurring is enable - * - * @param int|null $form_id Donation form ID. - * - * @return bool $value True if goal based on recurring is enable or else false. - * @since 1.7 - * - */ -function give_recurring_goal_format_enable($form_id = '') -{ - return empty($form_id) ? false : (bool)give_get_meta($form_id, '_give_recurring_goal_format', true); -} - -/** - * Modify form earning if only count recurring option is checked - * - * @param float $income Form total earning. - * @param int $form_id Donation form ID. - * - * @return float $new_income Form total earning. - * @since 1.7 - * - */ -function give_recurring_goal_amount_raised_output($income, $form_id) -{ - if (!give_recurring_goal_format_enable($form_id)) { - return $income; - } - - $new_income = 0; - $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); - foreach ($form_subscriptions as $subscription) { - $new_income = $new_income + $subscription->initial_amount; - } - - return $new_income; -} - -add_filter('give_goal_amount_raised_output', 'give_recurring_goal_amount_raised_output', 11, 2); - -/** - * Modify form total number of donation that is being made to the form. - * - * @param int $donation_number Form total earning. - * @param int $form_id Donation Form ID. - * - * @return int $donation_number Form total earning. - * @since 1.7 - * - */ -function give_recurring_donations_raised_output($donation_number, $form_id) -{ - if (!give_recurring_goal_format_enable($form_id)) { - return $donation_number; - } - - $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); - - return count($form_subscriptions); -} - -add_filter('give_goal_donations_raised_output', 'give_recurring_donations_raised_output', 11, 2); - -/** - * Modify total number of donor who has made recurring donation to the form - * - * @param int $donors Number of donor who made recurring donation to the Form. - * @param int $form_id Donation form id. - * - * @return int $new_donors Form total earning. - * @since 1.7 - * - */ -function give_recurring_donors_target_output($donors, $form_id) -{ - if (!give_recurring_goal_format_enable($form_id)) { - return $donors; - } - - $new_donors = array(); - $form_subscriptions = give_recurring_get_form_subscriptions($form_id, array('status' => 'active', 'number' => -1)); - foreach ($form_subscriptions as $subscription) { - $new_donors[] = $subscription->donor_id; - } - $new_donors = array_unique($new_donors); - - return count($new_donors); -} - -add_filter('give_goal_donors_target_output', 'give_recurring_donors_target_output', 11, 2); - -/** - * Give Localized variables. - * - * @param array $localize_give_vars - * - * @return array $localize_give_vars - * @since 1.8 - * - */ -function give_recurring_global_script_vars($localize_give_vars) -{ - $action = (isset($_GET['action']) && !empty($_GET['action'])) ? give_clean($_GET['action']) : ''; - - if (!empty($action) && 'edit_subscription' === $action) { - $localize_give_vars['bad_minimum'] = __('The minimum renewal amount for this form is', 'give-recurring'); - $localize_give_vars['bad_maximum'] = __('The maximum renewal amount for this form is', 'give-recurring'); - } - - return $localize_give_vars; -} - -add_filter('give_global_script_vars', 'give_recurring_global_script_vars', 10, 2); - - -/** - * Display Currency Switcher Update notice. - * - * @since 1.8.1 - */ -function give_recurring_display_minimum_cs_version_notice() -{ - if ( - defined('GIVE_CURRENCY_SWITCHER_BASENAME') && - is_plugin_active(GIVE_CURRENCY_SWITCHER_BASENAME) - ) { - if (version_compare(GIVE_CURRENCY_SWITCHER_VERSION, '1.3.0', '<')) { - Give()->notices->register_notice( - array( - 'id' => 'give-recurring-require-minimum-cs-version', - 'type' => 'error', - 'dismissible' => false, - 'description' => __( - 'Please update the Give Currency Switcher add-on to version 1.3+ to be compatible with the latest version of the Recurring Add-on.', - 'give-recurring' - ), - ) - ); - } - } -} - -add_action('admin_notices', 'give_recurring_display_minimum_cs_version_notice'); - -/** - * This function will return whether the donation is a parent donation or not. - * - * @param int $donation_id Donation ID. - * - * @return bool - * @since 1.8.3 - * - */ -function give_recurring_is_parent_donation($donation_id) -{ - global $wpdb; - - if (empty($donation_id)) { - return false; - } - - $table_name = $wpdb->prefix . 'give_subscriptions'; - $sql = esc_sql($wpdb->prepare("SELECT * FROM {$table_name} WHERE `parent_payment_id` = %d", $donation_id)); - $is_parent_payment = $wpdb->get_results($sql); - - if ($is_parent_payment) { - return true; - } - - return false; -} - - -/** - * Install plugin tables on plugin version update - * - * Note: internal use only - * - * @param string $old_version - * @since 1.9.0 - */ -function give_recurring_install_table($old_version) -{ - // Fresh install? - // This hook will only run on first install after that update_option_give_recurring_version will use. - if ('add_option_give_recurring_version' === current_filter()) { - $old_version = ''; - } - - update_option('give_recurring_version_upgraded_from', $old_version, false); - - give_recurring_register_tables(); -} - -add_filter('update_option_give_recurring_version', 'give_recurring_install_table', 0, 1); -add_filter('add_option_give_recurring_version', 'give_recurring_install_table', 0, 1); - -/** - * This function will add form tags when required for update payment method. - * - * @param array $formHtmlTags HTML Form Tags. - * @param Give_Subscription $subscription Subscription object. - * - * @return mixed - * @since 1.9.11 - * - */ -function give_recurring_stripe_add_form_tags($formHtmlTags, $subscription) -{ - // If payment gateway is not Stripe. - if (!in_array($subscription->gateway, give_stripe_supported_payment_methods(), true)) { - return $formHtmlTags; - } - - $formId = !empty($subscription->form_id) ? absint($subscription->form_id) : 0; - $publishableKey = give_stripe_get_publishable_key($formId); - $accountId = give_stripe_get_connected_account_id($formId); - - $formHtmlTags['data-publishable-key'] = $publishableKey; - $formHtmlTags['data-account'] = $accountId; - - return $formHtmlTags; -} - -add_filter('give_recurring_update_subscription_form_tags', 'give_recurring_stripe_add_form_tags', 0, 2); - -/** - * This function is used to add global parameters to Stripe Global Vars. - * - * @param array $args List of Parameters. - * - * @return array - * @since 1.10.2 - * - */ -function give_recurring_stripe_add_global_parameters($args) -{ - $is_update_pm_allowed = give_stripe_is_update_payment_method_screen(); - $subscription_db = new Give_Subscriptions_DB(); - $subscription_details = !empty($is_update_pm_allowed) ? - $subscription_db->get_subscriptions(['id' => $is_update_pm_allowed]) : - false; - - // Donor can update card for only following Stripe payment methods. - $stripePaymentMethods = ['stripe', 'stripe_checkout', 'stripe_apple_pay', 'stripe_google_pay']; - - $args['stripe_card_update'] = $is_update_pm_allowed && in_array( - $subscription_details[0]->gateway, - $stripePaymentMethods - ); - $args['stripe_becs_update'] = $is_update_pm_allowed && 'stripe_becs' === $subscription_details[0]->gateway; - - return $args; -} - -add_filter('give_stripe_global_parameters', 'give_recurring_stripe_add_global_parameters'); - - /** * Is the donation recurring. * diff --git a/src/LegacySubscriptions/includes/give-recurring-shortcodes.php b/src/LegacySubscriptions/includes/give-recurring-shortcodes.php deleted file mode 100644 index 28722110e4..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-shortcodes.php +++ /dev/null @@ -1,295 +0,0 @@ -payment_meta->get_meta( $donation->ID, '_give_subscription_payment', true ); - - if ( 'give_subscription' === $donation->post_status || true === $is_subscription_donation ) { - give_recurring_get_manage_subscriptions_link(); - } - - } - - /** - * Update donation receipt. - * - * @param DonationReceipt $receipt - * - * @return mixed - */ - public function addSubscriptionDetailsGroupToReceipt( $receipt ){ - $updateReceipt = new UpdateDonationReceipt($receipt); - - $updateReceipt->apply(); - } - - - /** - * Sets up the process of verifying the saving of the updated payment method - * - * @since x.x - * @return void - */ - public function verify_profile_update_setup() { - - $subscription_id = ( isset( $_POST['subscription_id'] ) && ! empty( $_POST['subscription_id'] ) ) ? absint( $_POST['subscription_id'] ) : 0; - - if ( empty( $subscription_id ) ){ - give_set_error( 'give_recurring_invalid_subscription_id', __( 'Invalid subscription ID.', 'give-recurring' ) ); - } - - $subscription = new Give_Subscription( $subscription_id ); - - $this->verify_profile_update_action( $subscription->donor_id ); - - } - - /** - * Verify and fire the hook to update a recurring payment method - * - * @since x.x - * - * @param int $user_id The User ID to update. - * - * @return void - */ - private function verify_profile_update_action( $user_id ) { - $subscriptionId = $this->getSubscriptionIdFromPostedData(); - - $passed_nonce = isset( $_POST['give_recurring_update_nonce'] ) - ? give_clean( $_POST['give_recurring_update_nonce'] ) - : false; - - if ( false === $passed_nonce || ! isset( $_POST['_wp_http_referer'] ) ) { - give_set_error( 'give_recurring_invalid_payment_update', __( 'Invalid Payment Update', 'give-recurring' ) ); - } - - $verified = wp_verify_nonce( $passed_nonce, "update-payment-{$subscriptionId}" ); - - if ( 1 !== $verified || empty( $user_id ) ) { - give_set_error( 'give_recurring_unable_payment_update', __( 'Unable to verify payment update. Please try again later.', 'give-recurring' ) ); - } - - // Check if a subscription_id is passed to use the new update methods - if ( $subscriptionId ) { - do_action( 'give_recurring_update_subscription_payment_method', $user_id, absint( $_POST['subscription_id'] ), $verified ); - } - - } - - /** - * Sets up the process of verifying the saving of the updated subscription. - * - * @since 1.8 - */ - public function verify_subscription_update() { - - // Get Subscription ID. - $subscription_id = ( isset( $_POST['subscription_id'] ) && ! empty( $_POST['subscription_id'] ) ) ? absint( $_POST['subscription_id'] ) : 0; - - // Set error if Subscription Id not set. - if ( empty( $subscription_id ) ) { - give_set_error( 'give_recurring_invalid_subscription_id', __( 'Invalid subscription ID.', 'give-recurring' ) ); - } - - // Subscription object. - $subscription = new Give_Subscription( $subscription_id ); - - // Verify subscription update action. - $this->verify_subscription_update_action( $subscription->donor_id ); - } - - /** - * Verify and fire the hook to update a subscription. - * - * @since 1.8 - * - * @param int $user_id The User ID to update. - */ - private function verify_subscription_update_action( $user_id ) { - $subscriptionId = $this->getSubscriptionIdFromPostedData(); - - // Get subscription update nonce. - $passed_nonce = isset( $_POST['give_recurring_subscription_update_nonce'] ) - ? give_clean( $_POST['give_recurring_subscription_update_nonce'] ) - : false; - - // Check nonce refer. - if ( false === $passed_nonce || ! isset( $_POST['_wp_http_referer'] ) ) { - give_set_error( 'give_recurring_invalid_subscription_update', __( 'Invalid Subscription Update', 'give-recurring' ) ); - } - - // Check nonce. - $verified = wp_verify_nonce( $passed_nonce, "update-subscription-{$subscriptionId}" ); - - // Set error if nonce verification failed. - if ( 1 !== $verified || empty( $user_id ) ) { - give_set_error( 'give_recurring_unable_subscription_update', __( 'Unable to verify subscription update. Please try again later.', 'give-recurring' ) ); - } - - // Check if a subscription_id is passed to use the new update methods. - if ( $subscriptionId ) { - - /** - * Update renewal subscription. - * e.g. Update renewal amount. - * - * @since 1.8 - * - * @param int $user_id The User ID to update. - * @param int $subscription_id The Subscription to update. - * @param bool $verified Sanity check that the request to update is coming from a verified source. - * - */ - do_action( 'give_recurring_update_renewal_subscription', $user_id, absint( $_POST['subscription_id'] ), $verified ); - } - } - - /** - * Subscriptions - * - * Provides users with an historical overview of their purchased subscriptions - * - * @param array $atts Shortcode attributes - * - * @since 1.0 - * - * @return string The html for the subscriptions shortcode. - */ - public function give_subscriptions( $atts ) { - - global $give_subscription_args; - - $give_subscription_args = shortcode_atts( array( - 'show_status' => true, - 'show_renewal_date' => true, - 'show_progress' => false, - 'show_start_date' => false, - 'show_end_date' => false, - 'subscriptions_per_page' => 30, - 'pagination_type' => 'next_and_previous', - ), $atts, 'give_subscriptions' ); - - // Convert shortcode_atts values to booleans. - foreach ( $give_subscription_args as $key => $value ) { - if ( 'subscriptions_per_page' !== $key && 'pagination_type' !== $key ) { - $give_subscription_args[ $key ] = filter_var( $give_subscription_args[ $key ], FILTER_VALIDATE_BOOLEAN ); - } - } - - return Give_Recurring()->subscriptions_view(); - } - - - /** - * Get subscription id from posted data - * - * @since 1.10.1 - * - * @return int|null - */ - private function getSubscriptionIdFromPostedData(){ - return ! empty( $_POST['subscription_id'] ) ? absint( $_POST['subscription_id'] ) : null; - } - -} - -new Give_Recurring_Shortcodes(); diff --git a/src/LegacySubscriptions/includes/give-recurring-template.php b/src/LegacySubscriptions/includes/give-recurring-template.php deleted file mode 100644 index 5b5f0f6d99..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-template.php +++ /dev/null @@ -1,347 +0,0 @@ - $show_period, - 'period' => $period, - 'times' => $times, - ) ); - ?> -
- ', - 'give-' . $period_functionality . '-' . $form_id, - 'give-recurring-period', - $pretty_label, - apply_filters( 'give_recurring_donors_choice_checked', $checked, $form_id ), - $period_choice_text, - esc_attr( $period ), - intval( $interval ) - ); - ?> -
- '; - // Loop through periods. - foreach (give_recurring_periods() as $key => $item) { - if ('donors_choice' === $key) { - continue; - } - - // Make text plural if interval is greater than 1. - if ($interval > '1') { - $item = sprintf(__('%ss', 'give-recurring'), $item); - } - - echo ''; - } - echo ''; - - // Times enabled? - if ( $times > 0 ) { - printf( __( '%s times', 'give-recurring' ), ' ' . $times ); - } - - $output = ob_get_clean(); - - - return apply_filters( 'give_recurring_donors_choice_period_element', $output, $form_id ); - -} - -/** - * Set Admin Choice Template - * - * @param $form_id - * @param $args - * - * @param $form_id - * @param $args - * - * @return bool - */ -function give_output_admin_choice( $form_id, $args ) { - - $form_option = give_get_meta( $form_id, '_give_recurring', true ); - $set_or_multi = give_get_meta( $form_id, '_give_price_option', true ); - - // Sanity check: only allow admin's choice - if ( 'yes_admin' !== $form_option ) { - return false; - } - - // Sanity Check: admin & multi options is handled by give_recurring_multilevel_text - if ( 'yes_admin' === $form_option && 'multi' === $set_or_multi ) { - return false; - } - - $period = give_get_meta( $form_id, '_give_period', true ); - $times = give_get_meta( $form_id, '_give_times', true ); - $interval = give_get_meta( $form_id, '_give_period_interval', true, 1 ); - $pretty_period = give_recurring_pretty_subscription_frequency( $period, $times, $lowercase = false, $interval ); - - $output = '' . $pretty_period . ''; - - echo apply_filters( 'give_output_set_admin_choice_output', $output, $form_id, $args ); - -} - -add_action( 'give_after_donation_amount', 'give_output_admin_choice', 10, 2 ); - -/** - * Give Recurring Multilevel Text - * - * Pragmatically append, prepend, replace and/or alter multilevel donation form output - * - * @since 1.12.7 Do not add HTML to price name. Remove old hack which remove HTML from price name while processing donation. - * - * @param $level_text - * @param $form_id - * @param $level - * - * @return string - */ -function give_recurring_multilevel_text( $level_text, $form_id, $level ) { - - $form_option = give_get_meta( $form_id, '_give_recurring', true ); - $set_or_multi = give_get_meta( $form_id, '_give_price_option', true ); - - // Sanity check: Is this admin selection & multi? - if ( 'yes_admin' !== $form_option ) { - return $level_text; - } - // Sanity check: Is this multi? - if ( 'multi' !== $set_or_multi ) { - return $level_text; - } - - // Sanity check: Is this level recurring enabled? - if ( ! isset( $level['_give_recurring'] ) || $level['_give_recurring'] == 'no' ) { - return $level_text; - } - - $period = isset( $level['_give_period'] ) ? $level['_give_period'] : ''; - $times = isset( $level['_give_times'] ) ? $level['_give_times'] : 0; - $interval = isset( $level['_give_period_interval'] ) ? $level['_give_period_interval'] : 1; - $pretty_period = give_recurring_pretty_subscription_frequency( $period, $times, $lowercase = false, $interval ); - - $text = sprintf( - '%1$s%2$s%3$s', - $level_text, - apply_filters( 'give_recurring_multilevel_text_separator', ', ', $form_id, $level ), - $pretty_period - ); - - return apply_filters( 'give_recurring_multilevel_text', $text, $form_id, $level ); - -} - -add_filter( 'give_form_level_text', 'give_recurring_multilevel_text', 10, 3 ); - - -/** - * Add a class to recurring levels - * - * @since 1.1 - * - * @param $classes - * @param $form_id - * @param $level - * - * @return string $classes - */ -function give_recurring_multilevel_classes( $classes, $form_id, $level ) { - - $level_id = isset( $level['_give_id']['level_id'] ) ? $level['_give_id']['level_id'] : ''; - - if ( empty( $level_id ) ) { - return $classes; - } - - $recurring = isset( $level['_give_recurring'] ) && $level['_give_recurring'] == 'yes' ? true : false; - - if ( $recurring ) { - $classes .= ' give-recurring-level'; - } - - return apply_filters( 'give_recurring_multilevel_classes', $classes, $form_id, $level_id ); - -} - -add_filter( 'give_form_level_classes', 'give_recurring_multilevel_classes', 10, 3 ); - - -/** - * Gets Times Billed for a subscription - * - * @param Give_Subscription $subscription - * - * @return string - */ -function get_times_billed_text( $subscription ) { - - // Bill times will show infinite symbol if 0 == bill times - $bill_times = ( $subscription->bill_times == 0 ) ? __( 'Ongoing', 'give-recurring' ) : $subscription->bill_times; - $total_payments = $subscription->get_total_payments(); - $times_billed = $total_payments . ' / ' . $bill_times; - - return apply_filters( 'give_recurring_times_billed_text', $times_billed, $bill_times, $total_payments, $subscription ); -} - -/** - * This function will be used to add renewal notice for donation receipt. - * - * @param mixed $notices Notice. - * @param int $id Post ID. - * @param string $status Payment Status. - * - * @since 1.8.2 - * - * @return string - */ -function give_recurring_add_renewal_notice( $notices, $id, $status ) { - - if ( 'give_subscription' === $status ) { - return Give()->notices->print_frontend_notice( - __( 'Renewal Payment Complete: Thank you for donation!', 'give-recurring' ), - false, - 'success' - ); - } - - return $notices; -} - -add_filter( 'give_receipt_status_notice', 'give_recurring_add_renewal_notice', 10, 3 ); - -/** - * This function is used to fetch the HTML markup of Manage Subscriptions Link. - * - * @since 1.8.2 - * - * @return void - */ -function give_recurring_get_manage_subscriptions_link() { - - // Link to the subscriptions page if set and exists. - $donation_id = give_clean( filter_input( INPUT_GET, 'donation_id' ) ); - - if ( - give_can_view_receipt( $donation_id ) || - is_user_logged_in() - ) { - echo sprintf( - '%2$s', - esc_url( give_get_subscriptions_page_uri() ), - esc_html__( 'Manage Subscriptions', 'give-recurring' ) . ' »' - ); - } -} diff --git a/src/Subscriptions/Models/LegacySubscriber.php b/src/Subscriptions/Models/LegacySubscriber.php index f7e197c964..3960df6820 100644 --- a/src/Subscriptions/Models/LegacySubscriber.php +++ b/src/Subscriptions/Models/LegacySubscriber.php @@ -13,12 +13,8 @@ * * @unreleased */ -if (class_exists('Give_Recurring_Subscriber')){ - class LegacySubscriber extends Give_Recurring_Subscriber { +class LegacySubscriber extends Give_Recurring_Subscriber +{ + // +} - } -} else { - class LegacySubscriber { - - } -} \ No newline at end of file From 7eaf616fd519bc20b07794085433d049b21e21c7 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 10 Jan 2022 16:58:19 -0500 Subject: [PATCH 04/15] revert: move back ajax and gateway parent --- src/LegacySubscriptions/ServiceProvider.php | 2 - .../includes/give-recurring-ajax.php | 151 ------------------ .../give-recurring-gateway-factory.php | 84 ---------- 3 files changed, 237 deletions(-) delete mode 100644 src/LegacySubscriptions/includes/give-recurring-ajax.php delete mode 100644 src/LegacySubscriptions/includes/give-recurring-gateway-factory.php diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index 78dc03c366..56d7046cdd 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -48,8 +48,6 @@ private function includeLegacyFiles() require_once __DIR__ . '/includes/give-recurring-renewals.php'; require_once __DIR__ . '/includes/give-recurring-expirations.php'; require_once __DIR__ . '/includes/give-recurring-cron.php'; - require_once __DIR__ . '/includes/give-recurring-gateway-factory.php'; - require_once __DIR__ . '/includes/give-recurring-ajax.php'; } /** diff --git a/src/LegacySubscriptions/includes/give-recurring-ajax.php b/src/LegacySubscriptions/includes/give-recurring-ajax.php deleted file mode 100644 index 404a563ce0..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-ajax.php +++ /dev/null @@ -1,151 +0,0 @@ -hide_errors(); - } - } - - /** - * Send headers for Give Recurring Ajax Requests - */ - private static function give_recurring_ajax_headers() { - send_origin_headers(); - @header( 'Content-Type: text/html; charset=' . get_option( 'blog_charset' ) ); - @header( 'X-Robots-Tag: noindex' ); - send_nosniff_header(); - nocache_headers(); - status_header( 200 ); - } - - /** - * Check for Give Recurring Ajax request and fire action. - */ - public static function do_give_recurring_ajax() { - global $wp_query; - - if ( ! empty( $_GET['give-recurring-ajax'] ) ) { - $wp_query->set( 'give-recurring-ajax', sanitize_text_field( $_GET['give-recurring-ajax'] ) ); - } - - if ( $action = $wp_query->get( 'give-recurring-ajax' ) ) { - self::give_recurring_ajax_headers(); - do_action( 'give_recurring_ajax_' . sanitize_text_field( $action ) ); - die(); - } - } - - /** - * Hook in methods - uses WordPress ajax handlers (admin-ajax). - */ - public static function add_ajax_events() { - $ajax_events = array( - 'sync_subscription_details' => false, - 'sync_subscription_transactions' => false, - ); - - foreach ( $ajax_events as $ajax_event => $nopriv ) { - add_action( 'wp_ajax_give_recurring_' . $ajax_event, array( __CLASS__, $ajax_event ) ); - - if ( $nopriv ) { - add_action( 'wp_ajax_nopriv_give_recurring_' . $ajax_event, array( __CLASS__, $ajax_event ) ); - - // Give Recurring AJAX can be used for frontend ajax requests. - add_action( 'give_recurring_ajax_' . $ajax_event, array( __CLASS__, $ajax_event ) ); - } - } - } - - /** - * Sync subscription details. - */ - public static function sync_subscription_details() { - - check_ajax_referer( 'sync-subscription-details', 'security' ); - - $user_can_sync = current_user_can( 'update_plugins' ); - if ( !apply_filters('give_recurring_user_can_sync_transactions', $user_can_sync) ) { - die( -1 ); - } - - $subscription_id = absint( $_POST['subscription_id'] ); - $log_id = isset( $_POST['log_id'] ) ? absint( $_POST['log_id'] ) : 0; - - if ( $log_id ) { - Give_Recurring()->synchronizer->log_id = $log_id; - } - - $output = Give_Recurring()->synchronizer->sync_subscription_details( $subscription_id ); - - wp_send_json( $output ); - } - - /** - * Sync subscription transactions. - */ - public static function sync_subscription_transactions() { - - check_ajax_referer( 'sync-subscription-transactions', 'security' ); - - $user_can_sync = current_user_can( 'update_plugins' ); - if ( !apply_filters('give_recurring_user_can_sync_transactions', $user_can_sync) ) { - die( -1 ); - } - - $subscription_id = absint( $_POST['subscription_id'] ); - $log_id = isset( $_POST['log_id'] ) ? absint( $_POST['log_id'] ) : 0; - - if ( $log_id ) { - Give_Recurring()->synchronizer->log_id = $log_id; - } - - $output = Give_Recurring()->synchronizer->sync_subscription_transactions( $subscription_id ); - wp_send_json( $output ); - } -} - -Give_Recurring_AJAX::init(); diff --git a/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php b/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php deleted file mode 100644 index 49973795bd..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-gateway-factory.php +++ /dev/null @@ -1,84 +0,0 @@ -gateway; - - } elseif ( is_numeric( $subscription ) ) { - - $subscription = new Give_Subscription( $subscription ); - $gateway_id = $subscription->gateway; - - } - - return $this->get_gateway( $gateway_id, $subscription ); - } - - /** - * Get gateway object based on gateway_id - * - * @param string $gateway_id - * @param \Give_Subscription $subscription - * - * @return Give_Recurring_Gateway|boolean - */ - public function get_gateway( $gateway_id, $subscription ) { - $class_name = 'Give_Recurring_' . ucfirst( $gateway_id ); - - if ( class_exists( $class_name ) ) { - $ret = new $class_name(); - } else { - $ret = false; - } - - return apply_filters( 'give_recurring_gateway_factory_get_gateway', $ret, $gateway_id, $subscription ); - } -} - - -/** - * Main function for returning gateway from subscription, uses the Give_Recurring_Gateway_Factory class - * - * @param Give_Subscription|int $subscription subscription id or Give_Subscription object - * - * @return Give_Recurring_Gateway - */ -function give_recurring_get_gateway_from_subscription( $subscription ) { - return Give_Recurring()->gateway_factory->get_gateway_from_subscription( $subscription ); -} - -/** - * Main function for returning gateway, uses the Give_Recurring_Gateway_Factory class - * - * @param string $gateway_id - * @param $subscription - * - * @return Give_Recurring_Gateway - */ -function give_recurring_get_gateway( $gateway_id, $subscription ) { - return Give_Recurring()->gateway_factory->get_gateway( $gateway_id, $subscription ); -} From 793073a3b9e1f2934452d0ead6a0c18fc8473398 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 10 Jan 2022 17:25:39 -0500 Subject: [PATCH 05/15] revert: move back recurring plugin specific files --- src/LegacySubscriptions/ServiceProvider.php | 3 - .../includes/give-recurring-emails.php | 463 ------------------ .../includes/give-recurring-expirations.php | 359 -------------- .../includes/give-recurring-renewals.php | 311 ------------ 4 files changed, 1136 deletions(-) delete mode 100644 src/LegacySubscriptions/includes/give-recurring-emails.php delete mode 100644 src/LegacySubscriptions/includes/give-recurring-expirations.php delete mode 100644 src/LegacySubscriptions/includes/give-recurring-renewals.php diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index 56d7046cdd..538d8a9bd9 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -44,9 +44,6 @@ private function includeLegacyFiles() require_once __DIR__ . '/includes/give-subscriptions-api.php'; require_once __DIR__ . '/includes/give-recurring-subscriber.php'; require_once __DIR__ . '/includes/give-recurring-helpers.php'; - require_once __DIR__ . '/includes/give-recurring-emails.php'; - require_once __DIR__ . '/includes/give-recurring-renewals.php'; - require_once __DIR__ . '/includes/give-recurring-expirations.php'; require_once __DIR__ . '/includes/give-recurring-cron.php'; } diff --git a/src/LegacySubscriptions/includes/give-recurring-emails.php b/src/LegacySubscriptions/includes/give-recurring-emails.php deleted file mode 100644 index 8a3e45aa53..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-emails.php +++ /dev/null @@ -1,463 +0,0 @@ -init(); - } - - /** - * Initialize Give_Recurring_Emails - */ - public function init() { - - add_action( 'give_email_tags', array( $this, 'setup_email_tags' ) ); - } - - /** - * Send Reminder. - * - * Responsible for sending both `renewal` and `expiration` notices. - * - * @param string $reminder_type required - values of `expiration` or `renewal`. - * @param int $subscription_id required - * @param int $notice_id - */ - public function send_reminder( $reminder_type, $subscription_id = 0, $notice_id = 0 ) { - - $stored_notices = get_option( 'give_recurring_reminder_notices', array() ); - $content_type = $stored_notices[ $notice_id ]['content_type']; - - // Sanity check: Do we have the required subscription ID? - if ( empty( $subscription_id ) || empty( $reminder_type ) ) { - return; - } - - // Get subscription. - $this->subscription = new Give_Subscription( $subscription_id ); - - // Sanity check: Check for it - if ( empty( $this->subscription ) ) { - return; - } - - // What type of reminder email is this? (renewal or expiration) - $reminder = $reminder_type == 'renewal' - ? Give_Recurring_Renewal_Reminders::get_instance() - : Give_Recurring_Expiration_Reminders::get_instance(); - - // Sanity check: Are these reminder emails activated? - if ( ! $reminder->reminders_allowed() ) { - return; - } - - $user = get_user_by( 'id', $this->subscription->donor->user_id ); - $send = (bool) apply_filters( 'give_recurring_send_' . $reminder_type . '_reminder', true, $subscription_id, $notice_id, $user ); - - // Do not send email if revoked. - if( ! $send ) { - return; - } - - $email_to = $this->subscription->donor->email; - - // Form appropriate email depending on reminder type. - if ( $reminder_type == 'renewal' ) { - // Renewing. - $notice = $reminder->get_renewal_notice( $notice_id ); - $message = ! empty( $notice['message'] ) ? $notice['message'] : __( "Hello {name},\n\nYour subscription for {subscription_name} will renew on {expiration}.", 'give-recurring' ); - $subject = ! empty( $notice['subject'] ) ? $notice['subject'] : __( 'Your Subscription is About to Renew', 'give-recurring' ); - - } else { - // Expiring. - $notice = $reminder->get_expiration_notice( $notice_id ); - $message = ! empty( $notice['message'] ) ? $notice['message'] : __( "Hello {name},\n\nYour subscription for {subscription_name} will expire on {expiration}.", 'give-recurring' ); - $subject = ! empty( $notice['subject'] ) ? $notice['subject'] : __( 'Your Subscription is About to Expire', 'give-recurring' ); - } - - // Filter template tags. - Give()->emails->__set( 'heading', give_do_email_tags( $notice['header'], $this->subscription->parent_payment_id ) ); - $subject = $this->filter_template_tags( $subject, $this->subscription ); - $message = $this->filter_template_tags( $message, $this->subscription ); - $message = ( 'text/plain' === $content_type ) ? wp_strip_all_tags( $message ) : $message; - - $sent = Give()->emails->send( $email_to, $subject, $message ); - - // Log the email if it indeed sent. - if ( $sent ) { - $this->log_recurring_email( $reminder_type, $this->subscription, $subject, $notice ); - } - - } - - /** - * Log recurring email. - * - * When an email is sent by the plugin, log it with Give. - * - * @since 1.12.2 switch to new Log facade - * - * @param string $email_type - * @param Give_Subscription $subscription - * @param $subject string - * @param int $notice_id - * @param $notice array of the email including subj, send period, etc. Used for reminder emails - */ - public static function log_recurring_email( $email_type, $subscription, $subject, $notice_id = 0, $notice = array() ) { - // Dynamic log title based on $email_type - $log_title = __( 'LOG - Subscription ' . ucfirst( $email_type ) . ' Email Sent', 'give-recurring' ); - - Log::notice($log_title, [ - 'category' => 'Recurring Donations', - 'source' => 'Email Logs', - 'Customer ID' => $subscription->donor_id, - 'Subscription ID' => $subscription->id , - 'Email Subject' => $subject - ]); - - // Is there a notice ID for this email? - if ( $notice_id > 0 && ! empty( $notice ) ) { - // Prevent reminder notices from being sent more than once - add_user_meta( $subscription->donor->user_id, sanitize_key( '_give_recurring_' . $email_type . '_' . $subscription->id . '_sent_' . $notice['send_period'] ), time() ); - } - } - - /** - * Email reminder template tag. - * - * @deprecated Use $this->filter_email_tags() - * - * @param string $content - * @param Give_Subscription $subscription - * - * @return mixed|string - */ - public function filter_template_tags( $content = '', $subscription ) { - - $payment_id = $subscription->parent_payment_id; - $payment_meta = give_get_payment_meta( $payment_id ); - $expiration_timestamp = strtotime( $subscription->expiration ); - $interval = ! empty( $subscription->frequency ) ? $subscription->frequency : 1; - - if ( isset( $this->tags ) && ! is_null( $this->tags ) && ! empty( $this->tags ) ) { - - foreach ( $this->tags as $email_tag ) { - - switch ( $email_tag ) : - case 'renewal_link': - $content = str_replace( '{renewal_link}', ' ' . $payment_meta['form_title'] . '', $content ); - break; - case 'completion_date': - $content = str_replace( '{completion_date}', date_i18n( give_date_format(), $expiration_timestamp ), $content ); - break; - case 'subscription_frequency': - $times = (int) $subscription->bill_times; - $content = str_replace( '{subscription_frequency}', give_recurring_pretty_subscription_frequency( $subscription->period, $times, false, $interval - ), $content ); - break; - case 'subscriptions_completed': - $content = str_replace( '{subscriptions_completed}', $subscription->get_subscription_progress(), $content ); - break; - case 'cancellation_date': - $content = str_replace( '{cancellation_date}', date_i18n( give_date_format(), current_time( 'timestamp' ) ), $content ); - break; - endswitch; - - } - } - - // Filter email content through Give core as well. - $content = give_do_email_tags( $content, $payment_id ); - - return apply_filters( 'give_recurring_filter_template_tags', $content ); - - } - - /** - * filter the email tag content. - * - * @access public - * - * @param array $tag_args - * @param string $email_tag - * - * @return string - */ - public static function filter_email_tags( $tag_args, $email_tag ) { - - $subscription_id = 0; - if ( ! empty( $tag_args['subscription_id'] ) ) { - $subscription_id = $tag_args['subscription_id']; - } elseif ( ! empty( $tag_args['payment_id'] ) ) { - $subscription_id = give_recurring_get_subscription_by( 'payment', $tag_args['payment_id'] ); - } - - // Return "n/a" for one-time (non-recurring) donations for all email tags besides frequency which will return "One Time" text. - if ( empty( $subscription_id ) && 'subscription_frequency' !== $email_tag ) { - return apply_filters( 'give_recurring_one_time_filter_template_tags', __( 'n/a', 'give-recurring' ) ); - } - - /* @var Give_Subscription $subscription */ - $subscription = new Give_Subscription( $subscription_id ); - $payment_meta = give_get_payment_meta( $subscription->parent_payment_id ); - $expiration_timestamp = strtotime( $subscription->expiration ); - $interval = ! empty( $subscription->frequency ) ? $subscription->frequency : 1; - $content = ''; - - // Replace template tags with actual content. - switch ( $email_tag ) : - case 'renewal_link': - $content = str_replace( - '%2$s', - get_permalink( $payment_meta['form_id'] ), - $payment_meta['form_title'] - ); - break; - - case 'completion_date': - $content = date_i18n( give_date_format(), $expiration_timestamp ); - break; - - case 'subscription_frequency': - $times = (int) $subscription->bill_times; - $content = give_recurring_pretty_subscription_frequency( $subscription->period, $times, false, $interval ); - break; - - case 'subscriptions_completed': - $content = $subscription->get_subscription_progress(); - break; - - case 'cancellation_date': - $content = date_i18n( give_date_format(), current_time( 'timestamp' ) ); - break; - - case 'renewal_date': - case 'expiration_date': - $content = date( give_date_format(), strtotime( $subscription->expiration ) ); - break; - endswitch; - - return apply_filters( 'give_recurring_filter_template_tags', $content, $tag_args, $email_tag ); - } - - /** - * This function is used to setup new email tags for recurring add-on. - * - * @param array $email_tags List of email tags. - * - * @since 1.8.5 - * @access public - * - * @return array - */ - public function setup_email_tags( $email_tags ) { - - $email_tags[] = array( - 'tag' => 'subscriptions_link', - 'desc' => esc_html__( 'The donor\'s email access link for subscription history.', 'give-recurring' ), - 'func' => array( $this, 'email_tag_subscription_history_link' ), - 'context' => 'donor', - ); - - $email_tags[] = array( - 'tag' => 'next_payment_attempt', - 'desc' => esc_html__( 'The date and time when the next payment attempt will be made.', 'give-recurring' ), - 'func' => array( $this, 'email_tag_next_payment_attempt_date' ), - 'context' => 'donor', - ); - - $email_tags[] = array( - 'tag' => 'update_payment_method_link', - 'desc' => esc_html__( 'The link to update the payment method of the subscription.', 'give-recurring' ), - 'func' => array( $this, 'email_tag_update_payment_method_link' ), - 'context' => 'donor', - ); - - return $email_tags; - } - - /** - * Email template tag: {subscriptions_link} - * - * @since 1.8.5 - * @access public - * - * @param array $tag_args Email Tag Arguments. - * - * @return string - */ - public function email_tag_subscription_history_link( $tag_args ) { - - $donor_id = 0; - $donor = array(); - $link = ''; - - // Backward compatibility. - $tag_args = __give_20_bc_str_type_email_tag_param( $tag_args ); - - switch ( true ) { - - case ! empty( $tag_args['payment_id'] ): - $donor_id = Give()->payment_meta->get_meta( $tag_args['payment_id'], '_give_payment_donor_id', true ); - $donor = Give()->donors->get_by( 'id', $donor_id ); - break; - - case ! empty( $tag_args['donor_id'] ): - $donor_id = $tag_args['donor_id']; - $donor = Give()->donors->get_by( 'id', $tag_args['donor_id'] ); - break; - - case ! empty( $tag_args['user_id'] ): - $donor = Give()->donors->get_by( 'user_id', $tag_args['user_id'] ); - $donor_id = $donor->id; - break; - } - - // Set email access link if donor exist. - if ( $donor_id ) { - $verify_key = wp_generate_password( 20, false ); - - // Generate a new verify key. - Give()->email_access->set_verify_key( $donor_id, $donor->email, $verify_key ); - - // update verify key in email tags. - $tag_args['verify_key'] = $verify_key; - - // update donor id in email tags. - $tag_args['donor_id'] = $donor_id; - - $access_url = add_query_arg( - array( - 'give_nl' => $verify_key, - ), - give_get_subscriptions_page_uri() - ); - - // Add donation id to email access url, if it exists. - $donation_id = give_clean( filter_input( INPUT_GET, 'donation_id' ) ); - if ( ! empty( $donation_id ) ) { - $access_url = add_query_arg( - array( - 'donation_id' => $donation_id, - ), - $access_url - ); - } - - if ( empty( $tag_args['email_content_type'] ) || 'text/html' === $tag_args['email_content_type'] ) { - $link = sprintf( - '%2$s', - esc_url( $access_url ), - __( 'View your subscription history »', 'give-recurring' ) - ); - - } else { - - $link = sprintf( - '%1$s: %2$s', - __( 'View your subscription history', 'give-recurring' ), - esc_url( $access_url ) - ); - } - } // End if(). - - /** - * Filter the {subscriptions_link} email template tag output. - * - * @since 1.8.5 - * - * @param string $receipt_link_url - * @param array $tag_args - */ - return apply_filters( - 'give_recurring_email_tag_subscription_history_link', - $link, - $tag_args - ); - } - - /** - * Email tag for next payment attempt. - * - * @param array $tag_args List of Email Tag arguments. - * - * @since 1.9.0 - * @access public - * - * @return string - */ - public function email_tag_next_payment_attempt_date( $tag_args ) { - - $date_format = get_option( 'date_format' ); - $time_format = get_option( 'time_format' ); - $date_time_format = "{$date_format} {$time_format}"; - $next_payment_attempt = ! empty( $tag_args['next_payment_attempt'] ) ? date_i18n( $date_time_format, $tag_args['next_payment_attempt'] ) : false; - - /** - * Filter for next payment attempt date. - * - * @param string $next_payment_attempt Next Payment Attempt Date. - * - * @since 1.9.0 - */ - return apply_filters( 'give_recurring_email_tag_next_payment_attempt_date', $next_payment_attempt ); - } - - /** - * Email tag containing the link to update the payment method of an active subscription. - * - * @param array $tag_args List of email tag arguments. - * - * @since 1.9.0 - * @access public - * - * @return mixed - */ - public function email_tag_update_payment_method_link( $tag_args ) { - - $subscription_id = ! empty( $tag_args['subscription_id'] ) ? $tag_args['subscription_id'] : 0; - - return sprintf( - '%2$s', - add_query_arg( - array( - 'action' => 'update', - 'subscription_id' => $subscription_id, - ), - give_get_subscriptions_page_uri() - ), - __( 'Update Payment Method', 'give-recurring' ) - ); - } -} diff --git a/src/LegacySubscriptions/includes/give-recurring-expirations.php b/src/LegacySubscriptions/includes/give-recurring-expirations.php deleted file mode 100644 index c8c93f2930..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-expirations.php +++ /dev/null @@ -1,359 +0,0 @@ -setup(); - } - - return self::$instance; - } - - - /** - * Setup - * - * @since 1.7 - * @access private - */ - private function setup(){ - add_action( 'give_daily_scheduled_events', array( $this, 'scheduled_expiration_reminders' ) ); - } - - /** - * Returns if expirations are enabled - * - * @return bool True if enabled, false if not - */ - public function reminders_allowed() { - - $expiration_reminder = give_get_option('recurring_send_expiration_reminders'); - - return ( 'enabled' === $expiration_reminder ) ? true : false; - } - - /** - * Retrieve expiration notices - * - * @return array Renewal notice periods - */ - public function get_expiration_notice_periods() { - $periods = array( - '+1day' => __( 'One day before expiration', 'give-recurring' ), - '+2days' => __( 'Two days before expiration', 'give-recurring' ), - '+3days' => __( 'Three days before expiration', 'give-recurring' ), - '+1week' => __( 'One week before expiration', 'give-recurring' ), - '+2weeks' => __( 'Two weeks before expiration', 'give-recurring' ), - '+1month' => __( 'One month before expiration', 'give-recurring' ), - '+2months' => __( 'Two months before expiration', 'give-recurring' ), - '+3months' => __( 'Three months before expiration', 'give-recurring' ), - 'expired' => __( 'At the time of expiration', 'give-recurring' ), - '-1day' => __( 'One day after expiration', 'give-recurring' ), - '-2days' => __( 'Two days after expiration', 'give-recurring' ), - '-3days' => __( 'Three days after expiration', 'give-recurring' ), - '-1week' => __( 'One week after expiration', 'give-recurring' ), - '-2weeks' => __( 'Two weeks after expiration', 'give-recurring' ), - '-1month' => __( 'One month after expiration', 'give-recurring' ), - '-2months' => __( 'Two months after expiration', 'give-recurring' ), - '-3months' => __( 'Three months after expiration', 'give-recurring' ), - ); - - return apply_filters( 'get_expiration_notice_periods', $periods ); - } - - /** - * Retrieve the expiration label for a notice - * - * @param int $notice_id - * - * @return string - */ - public function get_expiration_notice_period_label( $notice_id = 0 ) { - - $notice = $this->get_expiration_notice( $notice_id ); - $periods = $this->get_expiration_notice_periods(); - $label = $periods[ $notice['send_period'] ]; - - return apply_filters( 'get_expiration_notice_period_label', $label, $notice_id ); - } - - /** - * Retrieve a expiration notice - * - * @param int $notice_id - * - * @return array|mixed|void Renewal notice details - */ - public function get_expiration_notice( $notice_id = 0 ) { - - $notices = $this->get_expiration_notices(); - - $defaults = array( - 'subject' => __( 'Your Subscription is About to Expire', 'give-recurring' ), - 'send_period' => '+1day', - 'message' => 'Hello {name}, - - Your subscription for {subscription_name} will expire on {expiration}. - - Click here to renew: {renewal_link}' - - ); - - $notice = isset( $notices[ $notice_id ] ) ? $notices[ $notice_id ] : $notices[0]; - - $notice = wp_parse_args( $notice, $defaults ); - - return apply_filters( 'give_recurring_expiration_notice', $notice, $notice_id ); - - } - - /** - * Retrieve expiration notice periods - * - * @return array Renewal notices defined in settings - */ - public function get_expiration_notices() { - $notices = get_option( 'give_recurring_reminder_notices', array() ); - - if ( empty( $notices ) ) { - - $message = 'Hello {name}, - - Your subscription for {subscription_name} will expire on {expiration}. - - Click here to renew: {renewal_link}'; - - $notices[0] = array( - 'send_period' => '+1day', - 'subject' => __( 'Your Subscription is About to Expire', 'give-recurring' ), - 'message' => $message - ); - - } - - return apply_filters( 'get_expiration_notices', $notices ); - } - - - /** - * This is the actual process that takes place when the CRON job - * schedules renewal reminders. - * - * @param array $notices The email notices array. - * @param Give_Recurring_Emails $give_recurring_emails Give_Recurring_Email object. - * - * @since 1.6 - * - * @return void - */ - public function reminder_process( $notices, $give_recurring_emails ) { - - /** - * This loop will loop through all the notices, both - * renewal and expiration. - */ - foreach ( $notices as $notice_id => $notice ) { - - /** - * If notice email is disabled, then continue. - */ - if ( 'disabled' === $notice['status'] ) { - continue; - } - - - /** - * This file is responsible for sending out emails for expirations, - * so we skip if the 'notice_type' is set to 'renewal'. - */ - if ( 'renewal' === $notice['notice_type'] ) { - continue; - } - - - /** - * Get all the subscriptions which will be renewed in the next - * `$notice['send_period']` time. - * - * This can be -1day, +1day, -1month, +1month, +2month, etc. - */ - $subscriptions = $this->get_expiring_subscriptions( $notice['send_period'] ); - - - /** - * If there are no such subscriptions, then check for the next - * notice. - */ - if ( ! $subscriptions ) { - continue; - } - - - foreach ( $subscriptions as $subscription ) { - - /** - * Get the payment ID of the parent payment. - */ - $parent_payment_id = $subscription->parent_payment_id; - - - /** - * Get the gateway of the payment. - */ - $gateway = give_get_payment_meta( $parent_payment_id, '_give_payment_gateway' ); - - - /** - * Don't send the email if the gateway is found - * in the exclusion list. - */ - if ( ! empty( $notice['gateway'] ) && in_array( $gateway, $notice['gateway'], true ) ) { - continue; - } - - - /* Translate each subscription into a user_id and utilize - * the usermeta to store last renewal sent. - */ - $give_subscription = new Give_Subscription( $subscription->id ); - - $sent_time = get_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_expiration_' . $subscription->id . '_sent_' . $notice['send_period'] ), true ); - - if ( $sent_time ) { - - $renew_date = strtotime( $notice['send_period'], $sent_time ); - - if ( time() < $renew_date ) { - continue; - } - - delete_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_expiration_' . $subscription->id . '_sent_' . $notice['send_period'] ) ); - - } - - $give_recurring_emails->send_reminder( 'expiration', $subscription->id, $notice_id ); - } - } - } - - - /** - * Send reminder emails - * - * @return void - */ - public function scheduled_expiration_reminders() { - - if ( ! $this->reminders_allowed() ) { - return; - } - - - /** - * This will be used to setup the sending of the email. - */ - $give_recurring_emails = new Give_Recurring_Emails; - - - /** - * Gets all the recurring email notices. - * This includes email notices for both - * renewal and expiration. - */ - $notices = $this->get_expiration_notices(); - - - /** - * This handles sending out emails to donors. - */ - $this->reminder_process( $notices, $give_recurring_emails ); - } - - - /** - * Retrieve expiration notice periods - * - * @param string $period - * - * @return array|bool|mixed|null|object Subscribers whose subscriptions are expiring within the defined period - */ - public function get_expiring_subscriptions( $period = '+1month' ) { - - $subs_db = new Give_Subscriptions_DB(); - $subscriptions = $subs_db->get_expiring_subscriptions( $period ); - - if ( ! empty( $subscriptions ) ) { - return $subscriptions; - } - - return false; - } - - /** - * Retrieve renewal notice periods - * - * @return array Renewal notices defined in settings - */ - public function get_renewal_notices() { - $notices = get_option( 'give_recurring_reminder_notices', array() ); - - if ( empty( $notices ) ) { - - $message = 'Hello {name}, - - Your subscription for {subscription_name} will renew on {expiration}.'; - - $notices[0] = array( - 'send_period' => '+1day', - 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), - 'message' => $message, - ); - - } - - return apply_filters( 'get_renewal_notices', $notices ); - } -} - -Give_Recurring_Expiration_Reminders::get_instance(); \ No newline at end of file diff --git a/src/LegacySubscriptions/includes/give-recurring-renewals.php b/src/LegacySubscriptions/includes/give-recurring-renewals.php deleted file mode 100644 index e8da2e64ea..0000000000 --- a/src/LegacySubscriptions/includes/give-recurring-renewals.php +++ /dev/null @@ -1,311 +0,0 @@ -setup(); - } - - return self::$instance; - } - - /** - * Setup - * - * @since 1.7 - * @access private - */ - private function setup(){ - add_action( 'give_daily_scheduled_events', array( $this, 'scheduled_renewal_reminders' ) ); - } - - /** - * Returns if renewals are enabled - * - * @return bool True if enabled, false if not - */ - public function reminders_allowed() { - - $renewal_reminder = give_get_option( 'recurring_send_renewal_reminders' ); - - return ( 'enabled' === $renewal_reminder ) ? true : false; - } - - /** - * Retrieve renewal notices - * - * @return array Renewal notice periods - */ - public function get_renewal_notice_periods() { - $periods = array( - '+1day' => __( 'One day before renewal', 'give-recurring' ), - '+2days' => __( 'Two days before renewal', 'give-recurring' ), - '+3days' => __( 'Three days before renewal', 'give-recurring' ), - '+1week' => __( 'One week before renewal', 'give-recurring' ), - '+2weeks' => __( 'Two weeks before renewal', 'give-recurring' ), - '+1month' => __( 'One month before renewal', 'give-recurring' ), - '+2months' => __( 'Two months before renewal', 'give-recurring' ), - '+3months' => __( 'Three months before renewal', 'give-recurring' ), - ); - - return apply_filters( 'get_renewal_notice_periods', $periods ); - } - - /** - * Retrieve the renewal label for a notice - * - * @param int $notice_id - * - * @return string - */ - public function get_renewal_notice_period_label( $notice_id = 0 ) { - - $notice = $this->get_renewal_notice( $notice_id ); - $periods = $this->get_renewal_notice_periods(); - $label = $periods[ $notice['send_period'] ]; - - return apply_filters( 'get_renewal_notice_period_label', $label, $notice_id ); - } - - /** - * Retrieve a renewal notice - * - * @param int $notice_id - * - * @return array Renewal notice details. - */ - public function get_renewal_notice( $notice_id = 0 ) { - - $notices = $this->get_renewal_notices(); - - $defaults = array( - 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), - 'send_period' => '+1day', - 'message' => 'Hello {name}, - - Your subscription for {subscription_name} will renew on {expiration}.', - - ); - - $notice = isset( $notices[ $notice_id ] ) ? $notices[ $notice_id ] : $notices[0]; - - $notice = wp_parse_args( $notice, $defaults ); - - return apply_filters( 'give_recurring_renewal_notice', $notice, $notice_id ); - - } - - /** - * Retrieve renewal notice periods - * - * @return array Renewal notices defined in settings - */ - public function get_renewal_notices() { - $notices = get_option( 'give_recurring_reminder_notices', array() ); - - if ( empty( $notices ) ) { - - $message = 'Hello {name}, - - Your subscription for {subscription_name} will renew on {expiration}.'; - - $notices[0] = array( - 'send_period' => '+1day', - 'subject' => __( 'Your Subscription is About to Renew', 'give-recurring' ), - 'message' => $message, - ); - - } - - return apply_filters( 'get_renewal_notices', $notices ); - } - - - /** - * This is the actual process that takes place when the CRON job - * schedules renewal reminders. - * - * @param array $notices The email notices array. - * @param Give_Recurring_Emails $give_recurring_emails Give_Recurring_Email object. - * - * @since 1.6 - * - * @return void - */ - public function reminder_process( $notices, $give_recurring_emails ) { - - /** - * This loop will loop through all the notices, both - * renewal and expiration. - */ - foreach ( $notices as $notice_id => $notice ) { - - /** - * If notice email is disabled, then continue. - */ - if ( 'disabled' === $notice['status'] ) { - continue; - } - - - /** - * This file is responsible for sending out emails for renewals, so we - * skip if the 'notice_type' is set to 'expiration'. - */ - if ( 'expiration' === $notice['notice_type'] ) { - continue; - } - - - /** - * Get all the subscriptions which will be renewed in the next - * `$notice['send_period']` time. - * - * This can be +1day, +1month, +2month, etc. - */ - $subscriptions = $this->get_renewing_subscriptions( $notice['send_period'] ); - - - /** - * If there are no such subscriptions, then check for the next - * notice. - */ - if ( ! $subscriptions ) { - continue; - } - - - foreach ( $subscriptions as $subscription ) { - - /** - * Get the payment ID of the parent payment. - */ - $parent_payment_id = $subscription->parent_payment_id; - - - /** - * Get the gateway of the payment. - */ - $gateway = give_get_payment_meta( $parent_payment_id, '_give_payment_gateway' ); - - - /** - * Don't send the email if the gateway is found - * in the exclusion list. - */ - if ( ! empty( $notice['gateway'] ) && in_array( $gateway, $notice['gateway'], true ) ) { - continue; - } - - - /* Translate each subscription into a user_id and utilize - * the usermeta to store last renewal sent. - */ - $give_subscription = new Give_Subscription( $subscription->id ); - - $sent_time = get_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_renewal_' . $subscription->id . '_sent_' . $notice['send_period'] ), true ); - - if ( $sent_time ) { - - $renew_date = strtotime( $notice['send_period'], $sent_time ); - - if ( time() < $renew_date ) { - continue; - } - - delete_user_meta( $give_subscription->donor->user_id, sanitize_key( '_give_recurring_renewal_' . $subscription->id . '_sent_' . $notice['send_period'] ) ); - - } - - $give_recurring_emails->send_reminder( 'renewal', $subscription->id, $notice_id ); - } - } - } - - /** - * Send reminder emails - * - * @return void - */ - public function scheduled_renewal_reminders() { - - if ( ! $this->reminders_allowed() ) { - return; - } - - - /** - * This will be used to setup the sending of the email. - */ - $give_recurring_emails = new Give_Recurring_Emails; - - - /** - * Gets all the recurring email notices. - * This includes email notices for both - * renewal and expiration. - */ - $notices = $this->get_renewal_notices(); - - - /** - * This handles sending out emails to donors. - */ - $this->reminder_process( $notices, $give_recurring_emails ); - } - - - /** - * Retrieve renewal notice periods - * - * @param string $period - * - * @return array|bool|mixed|null|object Subscribers whose subscriptions are renewing within the defined period - */ - public function get_renewing_subscriptions( $period = '+1month' ) { - - $subs_db = new Give_Subscriptions_DB(); - $subscriptions = $subs_db->get_renewing_subscriptions( $period ); - - if ( ! empty( $subscriptions ) ) { - return $subscriptions; - } - - return false; - } -} - -Give_Recurring_Renewal_Reminders::get_instance(); \ No newline at end of file From 181517a078e9c07cf0b2c1a209ddd23e62e17443 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 10 Jan 2022 17:49:39 -0500 Subject: [PATCH 06/15] refactor: cleanup unused helpers --- .../includes/give-recurring-helpers.php | 368 ------------------ 1 file changed, 368 deletions(-) diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index b65aa2565a..2753e6ea5f 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -140,257 +140,6 @@ function give_recurring_is_recurring($form_id, $level_id = 0) return $is_recurring; } -/** - * Set up the time period IDs and labels - * - * @param int $number - * @param string $period - * - * @return array - * @since 1.6.0 Update Periods label. - * @static - * - * @since 1.0 - */ -function give_recurring_periods($number = 1, $period = '') -{ - $periods = apply_filters( - 'give_recurring_periods', - [ - // translators: placeholder is number of days. (e.g. "Bill this every day / 4 days") - 'day' => sprintf( - _nx( - 'day', - '%s days', - $number, - 'Recurring billing period.', - 'give-recurring' - ), - $number - ), - // translators: placeholder is number of weeks. (e.g. "Bill this every week / 4 weeks") - 'week' => sprintf( - _nx( - 'week', - '%s weeks', - $number, - 'Recurring billing period.', - 'give-recurring' - ), - $number - ), - // translators: placeholder is number of months. (e.g. "Bill this every month / 4 months") - 'month' => sprintf( - _nx( - 'month', - '%s months', - $number, - 'Recurring billing period.', - 'give-recurring' - ), - $number - ), - // translators: placeholder is number of quarters. (e.g. "Bill this every quarter / 4 times in a year") - 'quarter' => sprintf( - _nx( - 'quarter', - '%s quarters', - $number, - 'Recurring billing period.', - 'give-recurring' - ), - $number - ), - // translators: placeholder is number of years. (e.g. "Bill this every year / 4 years") - 'year' => sprintf( - _nx( - 'year', - '%s years', - $number, - 'Recurring billing period.', - 'give-recurring' - ), - $number - ), - ], - $number - ); - - return !empty($periods[$period]) ? $periods[$period] : $periods; -} - -/** - * Get billing times. - * - * @param string $billing_period - * - * @return array - * @since 1.6.0 - * - */ -function give_recurring_times($billing_period = '') -{ - $periods = give_recurring_ranges(); - - $periods = apply_filters('give_recurring_times', $periods); - - if (!empty($billing_period)) { - return $periods[$billing_period]; - } - - return $periods; -} - -/** - * Returns an array of Recurring lengths. - * - * PayPal Standard Allowable Ranges - * D – for days; allowable range is 1 to 90 - * W – for weeks; allowable range is 1 to 52 - * M – for months; allowable range is 1 to 24 - * Y – for years; allowable range is 1 to 5 - * - * @since 1.6.0 - */ -function give_recurring_ranges() -{ - $periods = array_keys(give_recurring_periods()); - - foreach ($periods as $period) { - $subscription_lengths = [ - _x('Ongoing', 'Subscription length', 'give-recurring'), - ]; - - switch ($period) { - case 'day': - $subscription_lengths[] = _x( - '1 day', - 'Subscription lengths. e.g. "For 1 day..."', - 'give-recurring' - ); - $subscription_range = range(2, 90); - break; - case 'week': - $subscription_lengths[] = _x( - '1 week', - 'Subscription lengths. e.g. "For 1 week..."', - 'give-recurring' - ); - $subscription_range = range(2, 52); - break; - case 'month': - $subscription_lengths[] = _x( - '1 month', - 'Subscription lengths. e.g. "For 1 month..."', - 'give-recurring' - ); - $subscription_range = range(2, 24); - break; - case 'quarter': - $subscription_lengths[] = _x( - '1 quarter', - 'Subscription lengths. e.g. "For 1 quarter..."', - 'give-recurring' - ); - $subscription_range = range(2, 12); - break; - case 'year': - $subscription_lengths[] = _x( - '1 year', - 'Subscription lengths. e.g. "For 1 year..."', - 'give-recurring' - ); - $subscription_range = range(2, 5); - break; - } - - foreach ($subscription_range as $number) { - $subscription_range[$number] = give_recurring_periods($number, $period); - } - - // Add the possible range to all time range - $subscription_lengths += $subscription_range; - - $subscription_ranges[$period] = $subscription_lengths; - } - - return $subscription_ranges; -} - -/** - * Set up the interval label. - * - * @param string (optional) An interval in the range 1-6 - * - * @return mixed - * @since 1.6.0 - * Return an i18n'ified associative array of all possible subscription periods. - * - */ -function give_recurring_interval($interval = '') -{ - $intervals = [1 => _x('every', 'period interval (eg "$10 _every_ 2 weeks")', 'give-recurring')]; - - foreach (range(2, 6) as $i) { - // translators: period interval, placeholder is ordinal (eg "$10 every _2nd/3rd/4th_", etc) - $intervals[$i] = sprintf( - _x( - 'every %s', - 'period interval with ordinal number (e.g. "every 2nd"', - 'give-recurring' - ), - give_recurring_append_numeral_suffix($i) - ); - } - - $intervals = apply_filters('give_recurring_interval', $intervals); - - if (empty($interval)) { - return $intervals; - } - - return $intervals[$interval]; -} - -/** - * Takes a number and returns the number with its relevant suffix appended, eg. for 2, the function returns 2nd - * - * @param int $number - * - * @return string - * @since 1.6.0 - * - */ -function give_recurring_append_numeral_suffix($number) -{ - // Handle teens: if the tens digit of a number is 1, then write "th" after the number. For example: 11th, 13th, 19th, 112th, 9311th. http://en.wikipedia.org/wiki/English_numerals - if (strlen($number) > 1 && 1 == substr($number, -2, 1)) { - // translators: placeholder is a number, this is for the teens - $number_string = sprintf(__('%sth', 'give-recurring'), $number); - } else { // Append relevant suffix - switch (substr($number, -1)) { - case 1: - // translators: placeholder is a number, numbers ending in 1 - $number_string = sprintf(__('%sst', 'give-recurring'), $number); - break; - case 2: - // translators: placeholder is a number, numbers ending in 2 - $number_string = sprintf(__('%snd', 'give-recurring'), $number); - break; - case 3: - // translators: placeholder is a number, numbers ending in 3 - $number_string = sprintf(__('%srd', 'give-recurring'), $number); - break; - default: - // translators: placeholder is a number, numbers ending in 4-9, 0 - $number_string = sprintf(__('%sth', 'give-recurring'), $number); - break; - } - } - - return apply_filters('give_recurring_numeral_suffix', $number_string, $number); -} - /** * Get Period. * @@ -444,120 +193,3 @@ function give_recurring_get_period($form_id, $price_id = 0) return false; } - -/** - * Get Interval. - * - * Get the period interval for a variable priced donation. - * - * @param $form_id - * @param $price_id - * - * @return bool|string - * @since 1.6.0 - * @access public - * @static - * - */ -function give_recurring_get_interval($form_id, $price_id = 0) -{ - $recurring_option = give_get_meta($form_id, '_give_recurring', true); - - // Is this a variable price form & admin's choice? - if (give_has_variable_prices($form_id) && 'yes_admin' === $recurring_option) { - if ('custom' === $price_id) { - return give_get_meta($form_id, '_give_recurring_custom_amount_interval', true, '1'); - } else { - $levels = give_get_meta($form_id, '_give_donation_levels', true); - - foreach ($levels as $price) { - // Check that this indeed the recurring price. - if ($price_id == $price['_give_id']['level_id'] - && isset($price['_give_recurring']) - && 'yes' === $price['_give_recurring'] - && isset($price['_give_period']) - ) { - return isset($price['_give_period_interval']) ? $price['_give_period_interval'] : 1; - } - } - } - } else { - // This is either a Donor's Choice multi-level or set donation form. - $period = give_get_meta($form_id, '_give_period_interval', true, 1); - - if ($period) { - return $period; - } - } - - return false; -} - -/** - * Get Times. - * - * Get the number of times a price ID recurs. - * - * @param $form_id - * @param $price_id - * - * @return int - * @since 1.0 - * @access public - * @static - * - */ -function give_recurring_get_times($form_id, $price_id = 0) -{ - $recurring_option = give_get_meta($form_id, '_give_recurring', true); - - // is this a single or multi-level form? - if (give_has_variable_prices($form_id) && 'yes_admin' === $recurring_option) { - if ('custom' === $price_id) { - return give_get_meta($form_id, '_give_recurring_custom_amount_times', true, 0); - } else { - $levels = maybe_unserialize(give_get_meta($form_id, '_give_donation_levels', true)); - - foreach ($levels as $price) { - // Check that this indeed the recurring price. - if ( - $price_id == $price['_give_id']['level_id'] && - isset($price['_give_recurring']) && - 'yes' === $price['_give_recurring'] && - isset($price['_give_times']) - ) { - return isset($price['_give_times']) ? intval($price['_give_times']) : 0; - } - } - } - } else { - $times = give_get_meta($form_id, '_give_times', true, 0); - - if ($times) { - return $times; - } - } - - return 0; -} - -/** - * Get the number of times a single-price donation form recurs. - * - * @param $form_id - * - * @return int|mixed - * @since 1.0 - * @static - * - */ -function give_recurring_get_times_single($form_id) -{ - $times = give_get_meta($form_id, '_give_times', true); - - if ($times) { - return $times; - } - - return 0; -} From 7feec473b96431a57f3713d7e335c7da9b146eac Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 10:29:42 -0500 Subject: [PATCH 07/15] refactor: remove Subscriber in favor of LegacySubscriber --- .../Actions/CreateSubscriptionAction.php | 4 ++-- src/Subscriptions/Models/LegacySubscriber.php | 3 +-- src/Subscriptions/Models/Subscriber.php | 12 ------------ 3 files changed, 3 insertions(+), 16 deletions(-) delete mode 100644 src/Subscriptions/Models/Subscriber.php diff --git a/src/PaymentGateways/Actions/CreateSubscriptionAction.php b/src/PaymentGateways/Actions/CreateSubscriptionAction.php index 42a33112f6..8dda7eaf5e 100644 --- a/src/PaymentGateways/Actions/CreateSubscriptionAction.php +++ b/src/PaymentGateways/Actions/CreateSubscriptionAction.php @@ -5,7 +5,7 @@ use Give\PaymentGateways\DataTransferObjects\FormData; use Give\PaymentGateways\DataTransferObjects\SubscriptionData; use Give\Subscriptions\DataTransferObjects\SubscriptionArgs; -use Give\Subscriptions\Models\Subscriber; +use Give\Subscriptions\Models\LegacySubscriber; use Give\ValueObjects\DonorInfo; use Give_Donor; @@ -110,7 +110,7 @@ private function createSubscription($donationId, $donorId, $subscriptionArgs) give_update_meta($donationId, '_give_subscription_payment', true); // Now create the subscription record. - $subscriber = new Subscriber($donorId); + $subscriber = new LegacySubscriber($donorId); $args = [ 'form_id' => $subscriptionArgs->formId, diff --git a/src/Subscriptions/Models/LegacySubscriber.php b/src/Subscriptions/Models/LegacySubscriber.php index 3960df6820..ef31016ecf 100644 --- a/src/Subscriptions/Models/LegacySubscriber.php +++ b/src/Subscriptions/Models/LegacySubscriber.php @@ -8,8 +8,7 @@ * Class LegacySubscriber * * This is a temporary class that extends a give-recurring concept of Give_Recurring_Subscriber. - * To avoid any issue with someone trying to use this without having give-recurring installed, - * there is a conditional to make sure the extended class exists. + * This will eventually be replaced with a core model. * * @unreleased */ diff --git a/src/Subscriptions/Models/Subscriber.php b/src/Subscriptions/Models/Subscriber.php deleted file mode 100644 index 81e63c14b7..0000000000 --- a/src/Subscriptions/Models/Subscriber.php +++ /dev/null @@ -1,12 +0,0 @@ - Date: Tue, 11 Jan 2022 10:29:53 -0500 Subject: [PATCH 08/15] docs: update since tags --- src/LegacySubscriptions/ServiceProvider.php | 6 ++++-- src/LegacySubscriptions/includes/give-recurring-cache.php | 5 ++++- src/LegacySubscriptions/includes/give-recurring-cron.php | 2 ++ .../includes/give-recurring-db-subscription-meta.php | 4 ++-- src/LegacySubscriptions/includes/give-recurring-helpers.php | 4 ++-- .../includes/give-recurring-subscriber.php | 1 + src/LegacySubscriptions/includes/give-subscription.php | 1 + src/LegacySubscriptions/includes/give-subscriptions-api.php | 3 ++- src/LegacySubscriptions/includes/give-subscriptions-db.php | 1 + 9 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index 538d8a9bd9..5314f02dd1 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -6,11 +6,13 @@ use Give\ServiceProviders\ServiceProvider as ServiceProviderInterface; /** - * Class LegacyServiceProvider + * Class ServiceProvider - LegacySubscriptions * - * This handles the loading of all the legacy codebase included in the /includes directory. + * This handles the loading of all the legacy codebase included in the LegacySubscriptions /includes directory. * DO NOT EXTEND THIS WITH NEW CODE as it is intended to shrink over time as we migrate over * to the new ways of doing things. + * + * @unreleased */ class ServiceProvider implements ServiceProviderInterface { diff --git a/src/LegacySubscriptions/includes/give-recurring-cache.php b/src/LegacySubscriptions/includes/give-recurring-cache.php index a1be30ba10..470e6ed492 100644 --- a/src/LegacySubscriptions/includes/give-recurring-cache.php +++ b/src/LegacySubscriptions/includes/give-recurring-cache.php @@ -4,6 +4,9 @@ exit; } +/** + * @unreleased - migrated from give-recurring + */ class Give_Recurring_Cache { /** * Instance. @@ -242,4 +245,4 @@ public function flush_on_donation_delete( $donation_id ) { } } -Give_Recurring_Cache::get_instance(); \ No newline at end of file +Give_Recurring_Cache::get_instance(); diff --git a/src/LegacySubscriptions/includes/give-recurring-cron.php b/src/LegacySubscriptions/includes/give-recurring-cron.php index 2b93ae5f17..ffb10d714d 100644 --- a/src/LegacySubscriptions/includes/give-recurring-cron.php +++ b/src/LegacySubscriptions/includes/give-recurring-cron.php @@ -15,6 +15,8 @@ /** * The Recurring Reminders Class + * + * @unreleased - migrated from give-recurring */ class Give_Recurring_Cron { diff --git a/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php b/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php index 64c71f309e..e1313f6868 100644 --- a/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php +++ b/src/LegacySubscriptions/includes/give-recurring-db-subscription-meta.php @@ -2,7 +2,7 @@ /** * Subscription Meta DB class * - * @package Give-Recurring + * @package Give * @copyright Copyright (c) 2016, GiveWP * @license https://opensource.org/licenses/gpl-license GNU Public License * @since 1.8 @@ -17,7 +17,7 @@ * Class Give_Recurring_DB_Subscription_Meta * * This class is for interacting with the subscription meta database table. - * + * @unreleased - migrated from give-recurring * @since 1.8 */ class Give_Recurring_DB_Subscription_Meta extends Give_DB_Meta { diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index 2753e6ea5f..d74ba145f3 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -18,7 +18,7 @@ * @param array $payment_meta * * @return bool - * @since 1.0 + * @unreleased * @access public * */ @@ -149,7 +149,7 @@ function give_recurring_is_recurring($form_id, $level_id = 0) * @param $price_id * * @return bool|string - * @since 1.0 + * @unreleased * @access public * @static * diff --git a/src/LegacySubscriptions/includes/give-recurring-subscriber.php b/src/LegacySubscriptions/includes/give-recurring-subscriber.php index 15877a73c5..7b17685799 100644 --- a/src/LegacySubscriptions/includes/give-recurring-subscriber.php +++ b/src/LegacySubscriptions/includes/give-recurring-subscriber.php @@ -17,6 +17,7 @@ * Class Give_Recurring_Subscriber * * Includes methods for setting users as donors, setting their status, expiration, etc. + * @unreleased - migrated from give-recurring */ class Give_Recurring_Subscriber extends Give_Donor { diff --git a/src/LegacySubscriptions/includes/give-subscription.php b/src/LegacySubscriptions/includes/give-subscription.php index ad0620b037..124f2b1ccc 100644 --- a/src/LegacySubscriptions/includes/give-subscription.php +++ b/src/LegacySubscriptions/includes/give-subscription.php @@ -16,6 +16,7 @@ /** * Class Give_Subscription * + * @unreleased - migrated from give-recurring * @since 1.0 */ class Give_Subscription { diff --git a/src/LegacySubscriptions/includes/give-subscriptions-api.php b/src/LegacySubscriptions/includes/give-subscriptions-api.php index 0946f14497..4106214134 100644 --- a/src/LegacySubscriptions/includes/give-subscriptions-api.php +++ b/src/LegacySubscriptions/includes/give-subscriptions-api.php @@ -2,7 +2,7 @@ /** * Subscribers REST API * - * @package Give Recurring + * @package Give * @subpackage Subscriber API Class * @copyright Copyright (c) 2017 * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License @@ -19,6 +19,7 @@ * Extends the Give_API to make the /subscriptions endpoint * * @class Give_Subscriptions_API + * @unreleased - migrated from give-recurring * @since 1.4 */ class Give_Subscriptions_API extends Give_API { diff --git a/src/LegacySubscriptions/includes/give-subscriptions-db.php b/src/LegacySubscriptions/includes/give-subscriptions-db.php index 2c3e713287..173e58b8a5 100644 --- a/src/LegacySubscriptions/includes/give-subscriptions-db.php +++ b/src/LegacySubscriptions/includes/give-subscriptions-db.php @@ -18,6 +18,7 @@ * * The Subscriptions DB Class. * + * @unreleased - migrated from give-recurring * @since 1.0 */ class Give_Subscriptions_DB extends Give_DB From d395ac075e58ec74acaf02a9ac010025a92392a6 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 10:38:51 -0500 Subject: [PATCH 09/15] refactor: remove check for Give_Recurring --- src/DonationSummary/SummaryView.php | 9 +++------ .../Adapters/LegacyPaymentGatewayAdapter.php | 5 +---- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/DonationSummary/SummaryView.php b/src/DonationSummary/SummaryView.php index 31ee991d9a..f28c99dd5f 100644 --- a/src/DonationSummary/SummaryView.php +++ b/src/DonationSummary/SummaryView.php @@ -113,15 +113,12 @@ protected function isFeeRecoveryEnabled() } /** - * @since 2.17.0 + * @unreleased - remove check for Give_Recurring * @return bool + * @since 2.17.0 */ protected function isRecurringEnabled() { - if (class_exists('\Give_Recurring')) { - return give_recurring_is_recurring($this->formID); - } - - return false; + return give_recurring_is_recurring($this->formID); } } diff --git a/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php b/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php index 492b85ee70..a22e9518d5 100644 --- a/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php +++ b/src/LegacyPaymentGateways/Adapters/LegacyPaymentGatewayAdapter.php @@ -51,10 +51,7 @@ public function handleBeforeGateway($legacyDonationData, $registeredGateway) $gatewayPaymentData = $formData->toGatewayPaymentData($donationId); - if ( - function_exists('Give_Recurring') && - give_recurring_is_donation_recurring($formData->legacyDonationData) - ) { + if (give_recurring_is_donation_recurring($formData->legacyDonationData)) { $subscriptionData = SubscriptionData::fromRequest($legacyDonationData); $subscriptionId = $this->createSubscription($donationId, $formData, $subscriptionData); From 09de6d8793914b8e1aeb75da7cb42a982f68ba24 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 10:40:35 -0500 Subject: [PATCH 10/15] chore: remove unused --- src/Subscriptions/ServiceProvider.php | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 src/Subscriptions/ServiceProvider.php diff --git a/src/Subscriptions/ServiceProvider.php b/src/Subscriptions/ServiceProvider.php deleted file mode 100644 index 2f7ea85f84..0000000000 --- a/src/Subscriptions/ServiceProvider.php +++ /dev/null @@ -1,27 +0,0 @@ - Date: Tue, 11 Jan 2022 12:05:38 -0500 Subject: [PATCH 11/15] feature: add safe conditional for give-recurring files --- src/LegacySubscriptions/ServiceProvider.php | 28 ++++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index 5314f02dd1..b84ffbf41d 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -21,8 +21,15 @@ class ServiceProvider implements ServiceProviderInterface */ public function register() { - $this->includeLegacyFiles(); - $this->bindClasses(); + $recurringIsInstalled = defined('GIVE_RECURRING_VERSION') && GIVE_RECURRING_VERSION; + $recurringMeetsRequirements = $recurringIsInstalled && GIVE_RECURRING_VERSION > '1.14.1'; + + if ($recurringMeetsRequirements || !$recurringIsInstalled) { + $this->includeLegacyFiles(); + $this->bindClasses(); + } + + $this->includeLegacyHelpers(); } /** @@ -45,10 +52,19 @@ private function includeLegacyFiles() require_once __DIR__ . '/includes/give-subscription.php'; require_once __DIR__ . '/includes/give-subscriptions-api.php'; require_once __DIR__ . '/includes/give-recurring-subscriber.php'; - require_once __DIR__ . '/includes/give-recurring-helpers.php'; require_once __DIR__ . '/includes/give-recurring-cron.php'; } + /** + * Load all the legacy helpers + * + * @unreleased + */ + private function includeLegacyHelpers() + { + require_once __DIR__ . '/includes/give-recurring-helpers.php'; + } + /** * Binds the legacy classes to the service provider * @@ -56,7 +72,11 @@ private function includeLegacyFiles() */ private function bindClasses() { - $this->bindInstance('subscription_meta', 'Give_Recurring_DB_Subscription_Meta', 'give-recurring-db-subscription-meta.php'); + $this->bindInstance( + 'subscription_meta', + 'Give_Recurring_DB_Subscription_Meta', + 'give-recurring-db-subscription-meta.php' + ); } /** From d1f2345413c779448a4b3f281b12ad59c53bc1b3 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 21:06:00 -0500 Subject: [PATCH 12/15] docs: update since tags --- src/LegacySubscriptions/includes/give-recurring-helpers.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index d74ba145f3..c7eab8c400 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -18,7 +18,7 @@ * @param array $payment_meta * * @return bool - * @unreleased + * @unreleased - this is copied over from give_recurring()->is_donation_recurring * @access public * */ @@ -78,6 +78,7 @@ function give_recurring_is_donation_recurring($payment_meta) * @param int $level_id The multi-level ID. * * @return bool + * @unreleased - this is copied over from give_recurring()->is_recurring * @since 1.0 * @access public * @static From 5cd88b0e1817da24cdf57f7fdc69e6f5b4b6dda6 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 21:06:31 -0500 Subject: [PATCH 13/15] docs: update since tags --- src/LegacySubscriptions/includes/give-recurring-helpers.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LegacySubscriptions/includes/give-recurring-helpers.php b/src/LegacySubscriptions/includes/give-recurring-helpers.php index c7eab8c400..985d8e1cb9 100644 --- a/src/LegacySubscriptions/includes/give-recurring-helpers.php +++ b/src/LegacySubscriptions/includes/give-recurring-helpers.php @@ -150,7 +150,7 @@ function give_recurring_is_recurring($form_id, $level_id = 0) * @param $price_id * * @return bool|string - * @unreleased + * @unreleased - this is copied over from give_recurring()->get_period * @access public * @static * From 770cd0f1bc46f40854782747b3ccd9b2b859fb92 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Tue, 11 Jan 2022 21:10:09 -0500 Subject: [PATCH 14/15] refactor: use version_compare --- src/LegacySubscriptions/ServiceProvider.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/LegacySubscriptions/ServiceProvider.php b/src/LegacySubscriptions/ServiceProvider.php index b84ffbf41d..443eb22c25 100644 --- a/src/LegacySubscriptions/ServiceProvider.php +++ b/src/LegacySubscriptions/ServiceProvider.php @@ -22,7 +22,7 @@ class ServiceProvider implements ServiceProviderInterface public function register() { $recurringIsInstalled = defined('GIVE_RECURRING_VERSION') && GIVE_RECURRING_VERSION; - $recurringMeetsRequirements = $recurringIsInstalled && GIVE_RECURRING_VERSION > '1.14.1'; + $recurringMeetsRequirements = $recurringIsInstalled && version_compare(GIVE_RECURRING_VERSION, '1.14.1', '>'); if ($recurringMeetsRequirements || !$recurringIsInstalled) { $this->includeLegacyFiles(); From 8f4b92fda90666b8e40f49ffa1ce11a650adbae7 Mon Sep 17 00:00:00 2001 From: Jon Waldstein Date: Mon, 17 Jan 2022 16:14:56 -0500 Subject: [PATCH 15/15] docs: update give version to 2.18.0 --- give.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/give.php b/give.php index 60dcb49065..7c267af42b 100644 --- a/give.php +++ b/give.php @@ -5,7 +5,7 @@ * Description: The most robust, flexible, and intuitive way to accept donations on WordPress. * Author: GiveWP * Author URI: https://givewp.com/ - * Version: 2.17.2 + * Version: 2.18.0 * Requires at least: 4.9 * Requires PHP: 5.6 * Text Domain: give @@ -285,7 +285,7 @@ private function setup_constants() { // Plugin version. if ( ! defined('GIVE_VERSION')) { - define('GIVE_VERSION', '2.17.2'); + define('GIVE_VERSION', '2.18.0'); } // Plugin Root File.