/** * Add a dependency check to this add-on: It can only be enabled when the * parent Add-on "Media" is also enabled. * * Filter: 'ms_model_addon_is_enabled_addon_mediafiles' * * @since 1.0.0 * @internal * * @param bool $enabled State of this add-on * (without considering the parent add-on) * @return bool The actual state of this add-on. */ public function is_enabled($enabled) { if ($enabled) { $enabled = MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEDIA); } return $enabled; }
/** * Checks if the current Add-on is enabled * * @since 1.0.0 * @return bool */ public static function is_active() { if (!self::buddypress_active() && MS_Model_Addon::is_enabled(self::ID)) { $model = MS_Factory::load('MS_Model_Addon'); $model->disable(self::ID); } return MS_Model_Addon::is_enabled(self::ID); }
/** * Get list table columns. * * @since 1.0.0 * * @return array { * Returns array of $id => $title. * * @type string $id The list table column id. * @type string $title The list table column title. * } */ public function get_columns() { $columns = array('cb' => '<input type="checkbox" />', 'username' => __('Username', MS_TEXT_DOMAIN), 'email' => __('E-mail', MS_TEXT_DOMAIN), 'membership' => __('Membership', MS_TEXT_DOMAIN), 'infos' => ' '); if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL)) { unset($columns['trial']); } return apply_filters('ms_helper_listtable_member_get_columns', $columns); }
/** * Prepares fields for the edit form. * * @since 1.0.1.0 * @return array */ protected function get_fields() { $args = array('include_guest' => false); $memberships = MS_Model_Membership::get_memberships($args); $membership = $this->data['membership']; $action = MS_Controller_Membership::AJAX_ACTION_UPDATE_MEMBERSHIP; $nonce = wp_create_nonce($action); $fields = array(); /* * The value of "allow_val" is negated, because the radio-slider is * reversed. So allow_val == false means that upgrading is allowed. * * This is just a UI tweak, the function ->update_allowed() returns true * when upgrading is allowed. */ $list = array(); $list['guest'] = array('allow' => __('Users without Membership can subscribe', 'membership2'), 'allow_val' => !$membership->update_allowed('guest')); foreach ($memberships as $item) { if ($item->id == $membership->id) { continue; } $list[$item->id] = array('allow' => sprintf(__('Members of %s can subscribe', 'membership2'), $item->get_name_tag()), 'allow_val' => !$membership->update_allowed($item->id)); if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS)) { $list[$item->id]['replace'] = sprintf(__('Cancel %s on subscription', 'membership2'), $item->get_name_tag()); $list[$item->id]['replace_val'] = $membership->update_replaces($item->id); } } foreach ($list as $id => $data) { $fields[] = array('id' => 'deny_update[' . $id . ']', 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER, 'title' => $data['allow'], 'value' => $data['allow_val'], 'before' => __('Allow', 'membership2'), 'after' => __('Deny', 'membership2'), 'class' => 'reverse', 'wrapper_class' => 'ms-block inline-label ms-allow', 'ajax_data' => array(1)); if (!empty($data['replace'])) { if (MS_Addon_Prorate::is_active()) { $after_label = __('Cancel and Pro-Rate', 'membership2'); } else { $after_label = __('Cancel', 'membership2'); } $fields[] = array('id' => 'replace_update[' . $id . ']', 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER, 'title' => $data['replace'], 'value' => $data['replace_val'], 'before' => __('Keep', 'membership2'), 'after' => $after_label, 'class' => 'reverse', 'wrapper_class' => 'ms-block inline-label ms-update-replace', 'ajax_data' => array(1)); } $fields[] = array('type' => MS_Helper_Html::TYPE_HTML_SEPARATOR); } foreach ($fields as $key => $field) { if (!empty($field['ajax_data'])) { if (!empty($field['ajax_data']['action'])) { continue; } if (!isset($fields[$key]['ajax_data']['field'])) { $fields[$key]['ajax_data']['field'] = $fields[$key]['id']; } $fields[$key]['ajax_data']['_wpnonce'] = $nonce; $fields[$key]['ajax_data']['action'] = $action; $fields[$key]['ajax_data']['membership_id'] = $membership->id; } } return $fields; }
/** * Set initial protection. * * Add [ms-protect-content] shortcode to protect membership content inside post. * * @since 1.0.0 */ public function protect_content() { parent::protect_content(); self::$membership_ids[] = $this->membership_id; add_shortcode(self::PROTECT_CONTENT_SHORTCODE, array(__CLASS__, 'protect_content_shortcode')); if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_SHORTCODE)) { global $shortcode_tags; $exclude = MS_Helper_Shortcode::get_membership_shortcodes(); foreach ($shortcode_tags as $shortcode => $callback_funciton) { if (in_array($shortcode, $exclude)) { continue; } if (!parent::has_access($shortcode)) { $shortcode_tags[$shortcode] = array(&$this, 'do_protected_shortcode'); } } } }
/** * Returns the contens of the dialog * * @since 1.0.0 * * @return object */ public function get_contents($data) { $member = $data['model']; $currency = MS_Plugin::instance()->settings->currency; $show_trial = MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL); $all_subscriptions = MS_Model_Relationship::get_subscriptions(array('user_id' => $member->id, 'status' => 'all', 'meta_key' => 'expire_date', 'orderby' => 'meta_value', 'order' => 'DESC')); // Prepare the form fields. $inp_dialog = array('type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'name' => 'dialog', 'value' => 'View_Member_Dialog'); $inp_id = array('type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'name' => 'member_id', 'value' => $member->id); $inp_nonce = array('type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'name' => '_wpnonce', 'value' => wp_create_nonce(self::ACTION_SAVE)); $inp_action = array('type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'name' => 'dialog_action', 'value' => self::ACTION_SAVE); $inp_save = array('type' => MS_Helper_Html::INPUT_TYPE_SUBMIT, 'value' => __('Save', 'membership2'), 'class' => 'ms-submit-form', 'data' => array('form' => 'ms-edit-member')); $inp_cancel = array('type' => MS_Helper_Html::INPUT_TYPE_BUTTON, 'value' => __('Close', 'membership2'), 'class' => 'close'); ob_start(); ?> <div> <form class="ms-form wpmui-ajax-update ms-edit-member" data-wpmui-ajax="<?php echo esc_attr('save'); ?> "> <div class="ms-form wpmui-form wpmui-grid-8"> <table class="widefat"> <thead> <tr> <th class="column-membership"> <?php _e('Membership', 'membership2'); ?> </th> <th class="column-status"> <?php _e('Status', 'membership2'); ?> </th> <th class="column-start"> <?php _e('Subscribed on', 'membership2'); ?> </th> <th class="column-expire"> <?php _e('Expires on', 'membership2'); ?> </th> <?php if ($show_trial) { ?> <th class="column-trialexpire"> <?php _e('Trial until', 'membership2'); ?> </th> <?php } ?> <th class="column-payments"> <?php _e('Payments', 'membership2'); ?> </th> </tr> </thead> <tbody> <?php foreach ($all_subscriptions as $subscription) { $membership = $subscription->get_membership(); $payments = $subscription->get_payments(); $num_payments = count($payments); $amount_payments = 0; foreach ($payments as $payment) { $amount_payments += $payment['amount']; } $subscription_info = array('subscription_id' => $subscription->id); $update_info = array('subscription_id' => $subscription->id, 'statuscheck' => 'yes'); ?> <tr> <td class="column-membership"> <?php $membership->name_tag(); ?> </td> <td class="column-status"> <?php printf('<a href="#" data-ms-dialog="View_Member_Subscription" data-ms-data="%2$s">%1$s</a> <a href="#" data-ms-dialog="View_Member_Subscription" data-ms-data="%3$s" title="%5$s">%4$s</a>', $subscription->status, esc_attr(json_encode($subscription_info)), esc_attr(json_encode($update_info)), '<i class="dashicons dashicons-update"></i>', __('Check and update subscription status', 'membership2')); ?> </td> <td class="column-start"> <?php echo $subscription->start_date; ?> </td> <td class="column-expire"> <?php echo $subscription->expire_date; ?> </td> <?php if ($show_trial) { ?> <td class="column-trialexpire"> <?php if ($subscription->start_date == $subscription->trial_expire_date) { echo '-'; } else { echo $subscription->trial_expire_date; } ?> </td> <?php } ?> <td class="column-payments"> <?php $total = sprintf('<b>%1$s</b> (%3$s %2$s)', $num_payments, MS_Helper_Billing::format_price($amount_payments), $currency); printf('<a href="#" data-ms-dialog="View_Member_Payment" data-ms-data="%1$s">%2$s</a>', esc_attr(json_encode($subscription_info)), $total); ?> </td> </tr> <?php } ?> </tbody> </table> </div> <?php MS_Helper_Html::html_element($inp_id); MS_Helper_Html::html_element($inp_dialog); MS_Helper_Html::html_element($inp_nonce); MS_Helper_Html::html_element($inp_action); ?> </form> <div class="buttons"> <?php MS_Helper_Html::html_element($inp_cancel); // MS_Helper_Html::html_element( $inp_save ); ?> </div> </div> <?php $html = ob_get_clean(); return apply_filters('ms_view_member_dialog_to_html', $html); }
/** * Add rewrite rules. * * @since 1.0.0 */ public function add_rewrite_rules() { $settings = MS_Factory::load('MS_Model_Settings'); // Gateway return - IPN. add_rewrite_rule('ms-payment-return/(.+)/?', 'index.php?paymentgateway=$matches[1]', 'top'); // Alternative payment return URL: Membership if (MS_Model_Import_Membership::did_import()) { add_rewrite_rule('paymentreturn/(.+)/?', 'index.php?paymentgateway=$matches[1]', 'top'); } // Media / download $mmask = $settings->downloads['masked_url']; $mtype = $settings->downloads['protection_type']; if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEDIA) && $mmask) { if (MS_Rule_Media_Model::PROTECTION_TYPE_HYBRID == $mtype) { add_rewrite_rule(sprintf('^%1$s/?$', $mmask), 'index.php?protectedfile=0', 'top'); } else { add_rewrite_rule(sprintf('^%1$s/([^/]+)', $mmask), 'index.php?protectedfile=$matches[1]', 'top'); } } // End: Media / download do_action('ms_plugin_add_rewrite_rules', $this); }
/** * Checks if the current page is a special page and if the special page is * protected by this rule. * * @since 1.0.0 * * @return bool */ public function has_rule_for_current_page() { if (null === $this->_has_rule) { if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_SPECIAL_PAGES)) { $this->_has_rule = false; } else { $base = $this->get_membership()->get_base(); $base_rule = $base->get_rule($this->rule_type); $this->_has_rule = $this->check_current_page($base_rule->rule_value); } } return $this->_has_rule; }
/** * Determine whether Membership access can be changed or is read-only. * * @since 1.0.0 * @param string $post_type The post type of the post. * @return bool */ public function is_read_only($post_type) { if ('post' == $post_type && !MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_POST_BY_POST)) { $read_only = true; } elseif ('attachment' == $post_type) { $read_only = true; } else { $read_only = false; } return apply_filters('ms_controller_membership_metabox_is_read_only', $read_only, $post_type, $this); }
/** * Membership signup callback function. * * @since 1.0.0 * * @param mixed[] $atts Shortcode attributes. */ public function membership_signup($atts) { MS_Helper_Shortcode::did_shortcode(MS_Helper_Shortcode::SCODE_SIGNUP); $data = apply_filters('ms_controller_shortcode_membership_signup_atts', shortcode_atts(array(MS_Helper_Membership::MEMBERSHIP_ACTION_SIGNUP . '_text' => __('Signup', 'membership2'), MS_Helper_Membership::MEMBERSHIP_ACTION_MOVE . '_text' => __('Change', 'membership2'), MS_Helper_Membership::MEMBERSHIP_ACTION_CANCEL . '_text' => __('Cancel', 'membership2'), MS_Helper_Membership::MEMBERSHIP_ACTION_RENEW . '_text' => __('Renew', 'membership2'), MS_Helper_Membership::MEMBERSHIP_ACTION_PAY . '_text' => __('Complete Payment', 'membership2')), $atts)); $member = MS_Model_Member::get_current_member(); $data['member'] = $member; $data['subscriptions'] = array(); $exclude = array(); if ($member->is_valid()) { // Get member's memberships, including pending relationships. $data['subscriptions'] = MS_Model_Relationship::get_subscriptions(array('user_id' => $data['member']->id, 'status' => 'valid')); foreach ($data['subscriptions'] as $key => $subscription) { $exclude[] = $subscription->membership_id; if (!$member->can_subscribe_to($subscription->membership_id)) { unset($data['subscriptions'][$key]); } } } $memberships = MS_Model_Membership::get_signup_membership_list(null, $exclude); $data['memberships'] = $memberships; $move_from_ids = array(); // When Multiple memberships is not enabled, a member should move to another membership. if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS)) { // Membership Relationship status which can move to another one $valid_status = array(MS_Model_Relationship::STATUS_TRIAL, MS_Model_Relationship::STATUS_ACTIVE, MS_Model_Relationship::STATUS_EXPIRED); foreach ($data['member']->subscriptions as $subscription) { if ($subscription->is_system()) { continue; } if (in_array($subscription->status, $valid_status)) { $move_from_ids[] = $subscription->membership_id; } } foreach ($data['memberships'] as $key => $membership) { $data['memberships'][$key]->_move_from = $move_from_ids; } } else { foreach ($data['memberships'] as $key => $membership) { $move_from_ids = $member->cancel_ids_on_subscription($membership->id); $data['memberships'][$key]->_move_from = $move_from_ids; } } $data['action'] = MS_Helper_Membership::MEMBERSHIP_ACTION_SIGNUP; $data['step'] = MS_Controller_Frontend::STEP_PAYMENT_TABLE; $view = MS_Factory::create('MS_View_Shortcode_MembershipSignup'); $view->data = apply_filters('ms_view_shortcode_membershipsignup_data', $data, $this); return $view->to_html(); }
/** * Initializes the Add-on. Always executed. * * @since 1.0.1.0 */ public function init() { MS_Model_Addon::disable(self::ID); }
/** * Returns the active flag for a specific rule. * State depends on Add-on * * @since 1.0.0 * @return bool */ public static function is_active() { return MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_POST_BY_POST); }
/** * Returns the active flag for a specific rule. * State depends on Add-on * * @since 1.0.0 * @return bool */ public static function is_active() { $def = MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEMBERCAPS); $adv = MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEMBERCAPS_ADV); return $def && !$adv; }
/** * Verify access to the current content. * * @since 1.0.0 * * @param string $id The content id to verify access. * @return bool|null True if has access, false otherwise. * Null means: Rule not relevant for current page. */ public function has_access($id, $admin_has_access = true) { $has_access = null; // Only verify permission if ruled by cpt post by post. if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_CPT_POST_BY_POST)) { if (empty($id)) { $id = $this->get_current_post_id(); } if (!empty($id)) { $post_type = get_post_type($id); $mspt = MS_Rule_CptGroup_Model::get_ms_post_types(); $cpt = MS_Rule_CptGroup_Model::get_custom_post_types(); if (in_array($post_type, $mspt)) { // Always allow access to Membership2 pages. $has_access = true; } elseif (in_array($post_type, $cpt)) { // Custom post type $has_access = parent::has_access($id, $admin_has_access); } else { // WordPress core pages are ignored by this rule. $has_access = null; } } } return apply_filters('ms_rule_custom_post_type_has_access', $has_access, $id, $this); }
/** * Checks if the current user can access the specified attachment. * * @since 1.0.0 * @param int $attachment_id * @return bool */ public function can_access_file($attachment_id) { $access = false; if (MS_Model_Member::is_normal_admin()) { return true; } if (!MS_Model_Addon::is_enabled(MS_Addon_Mediafiles::ID)) { /* * Default protection mode: * Protect Attachments based on the parent post. */ $parent_id = get_post_field('post_parent', $attachment_id); if (!$parent_id) { $access = true; } else { $member = MS_Model_Member::get_current_member(); foreach ($member->subscriptions as $subscription) { $membership = $subscription->get_membership(); $access = $membership->has_access_to_post($parent_id); if ($access) { break; } } } } else { /* * Advanced protection mode (via Add-on): * Each Attachment can be protected individually. */ $member = MS_Model_Member::get_current_member(); foreach ($member->subscriptions as $subscription) { $rule = $subscription->get_membership()->get_rule(MS_Rule_Media::RULE_ID); $access = $rule->has_access($attachment_id); if ($access) { break; } } } return apply_filters('ms_rule_media_can_access_file', $access, $attachment_id); }
/** * Input fields displayed in the "Edit Member" screen. * * @since 1.0.1.0 * @return array */ public function prepare_fields_edit() { $action_update = MS_Controller_Member::ACTION_UPDATE_MEMBER; $action_modify = MS_Controller_Member::ACTION_MODIFY_SUBSCRIPTIONS; $user_id = $this->data['user_id']; $user = MS_Factory::load('MS_Model_Member', $user_id); $unused_memberships = array(); $temp_memberships = MS_Model_Membership::get_memberships(array('include_guest' => 0)); foreach ($temp_memberships as $membership) { $unused_memberships[$membership->id] = $membership; } $fields = array(); $fields['editor'] = array('title' => array('type' => MS_Helper_Html::TYPE_HTML_TEXT, 'class' => 'group-title', 'value' => __('Basic Profile details', MS_TEXT_DOMAIN)), 'username' => array('id' => 'username', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('Username', MS_TEXT_DOMAIN), 'value' => $user->username, 'class' => 'ms-text-medium', 'config' => array('disabled' => 'disabled')), 'email' => array('id' => 'email', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('Email', MS_TEXT_DOMAIN), 'value' => $user->email, 'class' => 'ms-text-medium'), 'first_name' => array('id' => 'first_name', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('First Name', MS_TEXT_DOMAIN), 'value' => $user->first_name, 'class' => 'ms-text-medium'), 'last_name' => array('id' => 'last_name', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('Last Name', MS_TEXT_DOMAIN), 'value' => $user->last_name, 'class' => 'ms-text-medium'), 'displayname' => array('id' => 'displayname', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => __('Display Name', MS_TEXT_DOMAIN), 'value' => $user->get_user()->display_name, 'class' => 'ms-text-medium'), 'sep' => array('type' => MS_Helper_Html::TYPE_HTML_SEPARATOR), 'user_id' => array('id' => 'user_id', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => $user->id), 'button' => array('id' => 'btn_save', 'type' => MS_Helper_Html::INPUT_TYPE_SUBMIT, 'value' => __('Save', MS_TEXT_DOMAIN)), 'profile' => array('id' => 'user_profile', 'type' => MS_Helper_Html::TYPE_HTML_LINK, 'value' => __('Full User Profile', MS_TEXT_DOMAIN) . ' »', 'url' => admin_url('user-edit.php?user_id=' . $user->id), 'class' => 'button wpmui-field-input'), 'action' => array('id' => 'action', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => $action_update), '_wpnonce' => array('id' => '_wpnonce', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => wp_create_nonce($action_update))); $fields['subscriptions'] = array(); // Section: Edit existing subscriptions. $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_TEXT, 'class' => 'group-title', 'value' => __('Manage Subscriptions', MS_TEXT_DOMAIN)); if ($user->subscriptions) { $gateways = MS_Model_Gateway::get_gateway_names(false, true); foreach ($user->subscriptions as $subscription) { if (MS_Model_Relationship::STATUS_DEACTIVATED == $subscription->status) { continue; } $the_membership = $subscription->get_membership(); unset($unused_memberships[$the_membership->id]); $status_options = array(MS_Model_Relationship::STATUS_PENDING => __('Pending (activate on next payment)', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_WAITING => __('Waiting (activate on start date)', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_TRIAL => __('Trial Active', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_ACTIVE => __('Active', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_CANCELED => __('Cancelled (deactivate on expire date)', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_TRIAL_EXPIRED => __('Trial Expired (activate on next payment)', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_EXPIRED => __('Expired (no access) ', MS_TEXT_DOMAIN), MS_Model_Relationship::STATUS_DEACTIVATED => __('Deactivated (no access)', MS_TEXT_DOMAIN)); if (!$the_membership->has_trial()) { unset($status_options[MS_Model_Relationship::STATUS_TRIAL]); unset($status_options[MS_Model_Relationship::STATUS_TRIAL_EXPIRED]); } if (isset($gateways[$subscription->gateway_id])) { $gateway_name = $gateways[$subscription->gateway_id]; } elseif (empty($subscription->gateway_id)) { $gateway_name = __('- No Gateway -', MS_TEXT_DOMAIN); } else { $gateway_name = '(' . $subscription->gateway_id . ')'; } $field_start = array('name' => 'mem_' . $the_membership->id . '[start]', 'type' => MS_Helper_Html::INPUT_TYPE_DATEPICKER, 'value' => $subscription->start_date); $field_expire = array('name' => 'mem_' . $the_membership->id . '[expire]', 'type' => MS_Helper_Html::INPUT_TYPE_DATEPICKER, 'value' => $subscription->expire_date); $field_status = array('name' => 'mem_' . $the_membership->id . '[status]', 'type' => MS_Helper_Html::INPUT_TYPE_SELECT, 'value' => $subscription->status, 'field_options' => $status_options); $fields['subscriptions'][] = array('name' => 'memberships[]', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => $the_membership->id); $fields['subscriptions'][] = array('title' => $the_membership->get_name_tag(), 'type' => MS_Helper_Html::TYPE_HTML_TABLE, 'value' => array(array(__('Subscription ID', MS_TEXT_DOMAIN), $subscription->id), array(__('Payment Gateway', MS_TEXT_DOMAIN), $gateway_name), array(__('Payment Type', MS_TEXT_DOMAIN), $subscription->get_payment_description(null, true)), array(__('Start Date', MS_TEXT_DOMAIN) . ' <sup>*)</sup>', MS_Helper_Html::html_element($field_start, true)), array(__('Expire Date', MS_TEXT_DOMAIN) . ' <sup>*)</sup>', MS_Helper_Html::html_element($field_expire, true)), array(__('Status', MS_TEXT_DOMAIN) . ' <sup>*)</sup>', MS_Helper_Html::html_element($field_status, true))), 'field_options' => array('head_col' => true)); } } else { $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_TEXT, 'value' => __('This user does not have any subscriptions yet.', MS_TEXT_DOMAIN)); } // Section: Add new subscription. if (count($unused_memberships)) { $options = array(); if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS)) { $field_type = MS_Helper_Html::INPUT_TYPE_CHECKBOX; $group_title = __('Add Subscriptions', MS_TEXT_DOMAIN); } else { $field_type = MS_Helper_Html::INPUT_TYPE_RADIO; $group_title = __('Set Subscription', MS_TEXT_DOMAIN); } $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_SEPARATOR); $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_TEXT, 'class' => 'group-title', 'value' => $group_title); foreach ($unused_memberships as $the_membership) { $options[$the_membership->id] = $the_membership->get_name_tag(); } $fields['subscriptions'][] = array('id' => 'subscribe', 'type' => $field_type, 'field_options' => $options); $fields['subscriptions'][] = array('id' => 'user_id', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => $user->id); } if ($user->subscriptions) { $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_SEPARATOR); $fields['subscriptions'][] = array('type' => MS_Helper_Html::TYPE_HTML_TEXT, 'value' => '<sup>*)</sup> ' . __('Subscription Dates and Status are validated when saved and might result in a different value then the one specified above.', MS_TEXT_DOMAIN), 'class' => 'info-field'); } $fields['subscriptions'][] = array('id' => 'btn_modify', 'type' => MS_Helper_Html::INPUT_TYPE_SUBMIT, 'value' => __('Save Changes', MS_TEXT_DOMAIN)); $fields['subscriptions'][] = array('id' => 'history', 'type' => MS_Helper_Html::TYPE_HTML_LINK, 'value' => '<i class="dashicons dashicons-id"></i>' . __('History and logs', MS_TEXT_DOMAIN), 'url' => '#history', 'class' => 'button wpmui-field-input', 'config' => array('data-ms-dialog' => 'View_Member_Dialog', 'data-ms-data' => array('member_id' => $user->id))); $fields['subscriptions'][] = array('id' => 'action', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => $action_modify); $fields['subscriptions'][] = array('id' => '_wpnonce', 'type' => MS_Helper_Html::INPUT_TYPE_HIDDEN, 'value' => wp_create_nonce($action_modify)); return apply_filters('ms_view_member_editor_fields_edit', $fields); }
/** * Verify if a post/custom post type has protection rules. * * @since 1.0.0 * * @return boolean True if has access, false otherwise. */ public function has_rule_for_post($post_id) { $has_rules = false; if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_URL_GROUPS)) { $url = get_permalink($post_id); if ($this->check_url_expression_match($url, $this->get_protected_urls())) { $has_rules = true; } } return apply_filters('ms_rule_url_model_has_rule_for_post', $has_rules, $this); }
/** * Checks the /app/addon directory for a list of all addons and loads these * files. * * @since 1.0.0 */ protected static function load_core_addons() { $model = MS_Factory::load('MS_Model_Addon'); $root_path = trailingslashit(dirname(dirname(MS_Plugin::instance()->dir))); $plugin_dir = substr(MS_Plugin::instance()->dir, strlen($root_path)); $addon_dir = $plugin_dir . 'app/addon/'; if (empty($model->addon_files) || self::$_reload_files) { // In Admin dashboard we always refresh the addon-list... self::$_reload_files = false; $mask = $root_path . $addon_dir . '*/class-ms-addon-*.php'; $addons = glob($mask); $model->addon_files = array(); foreach ($addons as $file) { $model->addon_files[] = substr($file, strlen($root_path)); } /** * Allow other plugins/themes to register custom addons * * @since 1.0.0 * * @var array */ $model->addon_files = apply_filters('ms_model_addon_files', $model->addon_files); $model->save(); } // Loop all recignized Add-ons and initialize them. foreach ($model->addon_files as $file) { $addon = $root_path . $file; // Get class-name from file-name $class = basename($file); $class = str_replace('.php', '', $class); $class = implode('_', array_map('ucfirst', explode('-', $class))); $class = substr($class, 6); // remove 'Class_' prefix if (file_exists($addon)) { if (!class_exists($class)) { try { include_once $addon; } catch (Exception $ex) { } } if (class_exists($class)) { MS_Factory::load($class); } } } /** * Allow custom addon-initialization code to run * * @since 1.0.0 */ do_action('ms_model_addon_load'); }
/** * Returns the active flag for a specific rule. * State depends on Add-on * * @since 1.0.0 * @return bool */ public static function is_active() { return MS_Model_Addon::is_enabled(MS_Addon_Category::ID); }
/** * Returns true if this membership is eligable for trial period. * * @since 1.0.1.0 * @return bool */ public function has_trial() { $result = $this->trial_period_enabled; if ($result) { if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL)) { $result = false; } } return $result; }
/** * Handle protected media access. * * Search for masked file and show the proper content, or no access image if don't have access. * * Realted Action Hooks: * - parse_request * * @since 1.0.0 * * @param WP_Query $query The WP_Query object to filter. */ public function handle_download_protection($query) { do_action('ms_rule_media_model_handle_download_protection_before', $query, $this); $the_file = false; $requested_item = false; $download_settings = MS_Plugin::instance()->settings->downloads; $protection_type = $download_settings['protection_type']; if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEDIA)) { return; } if (!empty($query->query_vars['protectedfile'])) { $requested_item = explode('/', $query->query_vars['protectedfile']); $requested_item = array_pop($requested_item); } elseif (!empty($_GET['ms_file']) && self::PROTECTION_TYPE_HYBRID == $protection_type) { $requested_item = $_GET['ms_file']; } if (!empty($requested_item)) { // At this point we know that the requested post is an attachment. $f_info = $this->extract_file_info($requested_item); switch ($protection_type) { case self::PROTECTION_TYPE_COMPLETE: case self::PROTECTION_TYPE_HYBRID: // Work out the post_id again $attachment_id = preg_replace('/^' . self::FILE_PROTECTION_PREFIX . '/', '', $f_info->filename); $attachment_id -= (int) self::FILE_PROTECTION_INCREMENT; $the_file = $this->restore_filename($attachment_id, $f_info->size_extension); break; default: case self::PROTECTION_TYPE_BASIC: $home = untrailingslashit(get_option('home')); $attachment_id = $this->get_attachment_id($home . $f_info->filename); $the_file = $this->restore_filename($attachment_id, $f_info->size_extension); break; } if (!empty($the_file) && !empty($attachment_id) && is_numeric($attachment_id)) { if ($this->can_access_file($attachment_id)) { $upload_dir = wp_upload_dir(); $file = trailingslashit($upload_dir['basedir']) . $the_file; $this->output_file($file); } else { $this->show_no_access_image(); } } } do_action('ms_rule_media_model_handle_download_protection_after', $query, $this); }
/** * Verify access to the current content. * * @since 1.0.0 * * @param string $id The content id to verify access. * @return bool|null True if has access, false otherwise. * Null means: Rule not relevant for current page. */ public function has_access($id, $admin_has_access = true) { $has_access = null; // Only verify permission if NOT ruled by cpt post by post. if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_CPT_POST_BY_POST)) { return $has_access; } if (!empty($id)) { $post = get_post($id); } else { $post = get_queried_object(); } $post_type = !empty($post->post_type) ? $post->post_type : ''; if (empty($post_type) && !empty($post->query_var)) { $post_type = $post->query_var; } if (in_array($post_type, self::get_ms_post_types())) { // Always allow access to Membership2 pages. $has_access = true; } elseif (in_array($post_type, self::get_custom_post_types())) { // Custom post type $has_access = parent::has_access($post_type, $admin_has_access); } else { // WordPress core pages are ignored by this rule. $has_access = null; } return apply_filters('ms_rule_cptgroup_model_has_access', $has_access, $id, $this); }
/** * Prepares fields for the edit form. * * @since 1.0.1.0 * @return array */ protected function get_fields() { $membership = $this->data['membership']; $action = MS_Controller_Membership::AJAX_ACTION_UPDATE_MEMBERSHIP; $nonce = wp_create_nonce($action); $fields = array(); // Prepare the form fields. $fields['name'] = array('id' => 'name', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT, 'title' => apply_filters('ms_translation_flag', __('Name:', MS_TEXT_DOMAIN), 'membership-name'), 'value' => $membership->name, 'ajax_data' => array(1)); $fields['description'] = array('id' => 'description', 'type' => MS_Helper_Html::INPUT_TYPE_TEXT_AREA, 'title' => apply_filters('ms_translation_flag', __('Description:', MS_TEXT_DOMAIN), 'membership-name'), 'value' => $membership->description, 'ajax_data' => array(1)); $fields['active'] = array('id' => 'active', 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER, 'title' => __('This membership is active', MS_TEXT_DOMAIN), 'before' => __('No', MS_TEXT_DOMAIN), 'after' => __('Yes', MS_TEXT_DOMAIN), 'class' => 'ms-active', 'value' => $membership->active, 'ajax_data' => array(1)); $fields['public'] = array('id' => 'public', 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER, 'title' => __('This membership is public', MS_TEXT_DOMAIN), 'desc' => __('Users can see it listed on your site and can register for it', MS_TEXT_DOMAIN), 'before' => __('No', MS_TEXT_DOMAIN), 'after' => __('Yes', MS_TEXT_DOMAIN), 'class' => 'ms-public', 'value' => $membership->public, 'ajax_data' => array(1)); $fields['paid'] = array('id' => 'is_paid', 'type' => MS_Helper_Html::INPUT_TYPE_RADIO_SLIDER, 'title' => __('This is a paid membership', MS_TEXT_DOMAIN), 'before' => __('No', MS_TEXT_DOMAIN), 'after' => __('Yes', MS_TEXT_DOMAIN), 'class' => 'ms-paid', 'value' => $membership->is_paid, 'ajax_data' => array(1)); $priority_list = array(); $args = array('include_guest' => 0); $count = MS_Model_Membership::get_membership_count($args); for ($i = 1; $i <= $count; $i += 1) { $priority_list[$i] = $i; } $priority_list[$membership->priority] = $membership->priority; $fields['priority'] = array('id' => 'priority', 'type' => MS_Helper_Html::INPUT_TYPE_SELECT, 'title' => __('Membership order', MS_TEXT_DOMAIN), 'desc' => __('This defines the display order on the Membership Page.', MS_TEXT_DOMAIN), 'class' => 'ms-priority', 'before' => __('Order', MS_TEXT_DOMAIN), 'value' => $membership->priority, 'field_options' => $priority_list, 'ajax_data' => array(1)); if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MULTI_MEMBERSHIPS)) { $fields['priority']['desc'] .= '<br>' . __('It also controlls which Protection Message is used in case a member has multiple memberships (the lowest value wins)', MS_TEXT_DOMAIN); } foreach ($fields as $key => $field) { if (!empty($field['ajax_data'])) { if (!empty($field['ajax_data']['action'])) { continue; } if (!isset($fields[$key]['ajax_data']['field'])) { $fields[$key]['ajax_data']['field'] = $fields[$key]['id']; } $fields[$key]['ajax_data']['_wpnonce'] = $nonce; $fields[$key]['ajax_data']['action'] = $action; $fields[$key]['ajax_data']['membership_id'] = $membership->id; } } return $fields; }
/** * Returns the active flag for a specific rule. * State depends on Add-on * * @since 1.0.0 * @return bool */ public static function is_active() { return MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_ADMINSIDE); }
/** * Load all the Add-ons. * * Related Action Hooks: * - ms_load_member * * @since 1.0.0 */ public function load_addons() { do_action('ms_load_addons', $this); // Initialize all Add-ons MS_Model_Addon::get_addons(); }
/** * Get available tabs for Membership2 page. * * @since 1.0.0 * * @return array The tabs configuration. */ public function get_available_tabs() { static $Tabs = null; if (null === $Tabs) { $membership = $this->load_membership(); $membership_id = $membership->id; $is_base = $membership->is_base(); $settings = MS_Factory::load('MS_Model_Settings'); // First create a list including all possible tabs. $tabs = array(MS_Rule_Page::RULE_ID => true, MS_Rule_Post::RULE_ID => true, MS_Rule_Category::RULE_ID => true, MS_Rule_Content::RULE_ID => true, MS_Rule_Media::RULE_ID => true, MS_Rule_MenuItem::RULE_ID => true, MS_Rule_ReplaceMenu::RULE_ID => true, MS_Rule_ReplaceLocation::RULE_ID => true, MS_Rule_Shortcode::RULE_ID => true, MS_Rule_Url::RULE_ID => true, MS_Rule_Special::RULE_ID => true, MS_Rule_MemberCaps::RULE_ID => true, MS_Rule_MemberRoles::RULE_ID => true); // Now remove items from the list that are not available. // Optionally show "Posts" if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_POST_BY_POST)) { $tabs[MS_Rule_Post::RULE_ID] = false; } // Optionally show "Category" if (!MS_Model_Addon::is_enabled(MS_Addon_Category::ID)) { $tabs[MS_Rule_Category::RULE_ID] = false; } // Optionally show "Media" if (!MS_Model_Addon::is_enabled(MS_Addon_Mediafiles::ID)) { $tabs[MS_Rule_Media::RULE_ID] = false; } // Either "Menu Item" or "Menus" or "Menu Location" switch ($settings->menu_protection) { case 'menu': $tabs[MS_Rule_MenuItem::RULE_ID] = false; $tabs[MS_Rule_ReplaceLocation::RULE_ID] = false; break; case 'location': $tabs[MS_Rule_MenuItem::RULE_ID] = false; $tabs[MS_Rule_ReplaceMenu::RULE_ID] = false; break; case 'item': default: $tabs[MS_Rule_ReplaceMenu::RULE_ID] = false; $tabs[MS_Rule_ReplaceLocation::RULE_ID] = false; break; } // Maybe "Special Pages". if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_SPECIAL_PAGES)) { $tabs[MS_Rule_Special::RULE_ID] = false; } // Maybe "URLs" if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_URL_GROUPS)) { $tabs[MS_Rule_Url::RULE_ID] = false; } // Maybe "Shortcodes" if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_SHORTCODE)) { $tabs[MS_Rule_Shortcode::RULE_ID] = false; } // Maybe "Membercaps" if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEMBERCAPS)) { if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_MEMBERCAPS_ADV)) { $tabs[MS_Rule_MemberRoles::RULE_ID] = false; } else { $tabs[MS_Rule_MemberCaps::RULE_ID] = false; } } else { $tabs[MS_Rule_MemberRoles::RULE_ID] = false; $tabs[MS_Rule_MemberCaps::RULE_ID] = false; } lib2()->array->equip($_GET, 'page'); // Allow Add-ons to add or remove rule tabs $tabs = apply_filters('ms_controller_protection_tabs', $tabs, $membership_id); $page = sanitize_html_class($_GET['page'], MS_Controller_Plugin::MENU_SLUG . '-memberships'); $rule_titles = MS_Model_Rule::get_rule_type_titles(); $result = array(); foreach ($tabs as $rule_type => $state) { if (!$state) { continue; } $url = sprintf('%s?page=%s&tab=%s', admin_url('admin.php'), $page, $rule_type); // Try to keep the selected Membership and Status filter. if (!empty($_REQUEST['membership_id'])) { $url = esc_url_raw(add_query_arg(array('membership_id' => $_REQUEST['membership_id']), $url)); } if (!empty($_REQUEST['status'])) { $url = esc_url_raw(add_query_arg(array('status' => $_REQUEST['status']), $url)); } $result[$rule_type] = array('title' => $rule_titles[$rule_type], 'url' => $url); } $Tabs = apply_filters('ms_controller_protection_get_available_tabs', $result, $membership_id, $this); } return $Tabs; }
/** * Checks if the current Add-on is enabled * * @since 1.0.0 * @return bool */ public static function is_active() { return MS_Model_Addon::is_enabled(self::ID); }
/** * This list has no views. * * @since 1.0.2.0 * * @return array */ public function get_views() { $views = array(); $args = array(); $count = 0; $views['label'] = array('label' => __('Subscription Status:', 'membership2')); if (empty($_REQUEST['membership_id'])) { // All users $url = esc_url_raw(add_query_arg('status', 'all')); $views['all'] = array('url' => $url, 'label' => __('All users', 'membership2')); } else { $args['membership_id'] = $_REQUEST['membership_id']; } // Active, Trial, Cancelled $url = esc_url_raw(remove_query_arg('status')); $args['subscription_status'] = MS_Model_Relationship::STATUS_ACTIVE; $count = MS_Model_Member::get_members_count($args); $views['active'] = array('url' => $url, 'label' => __('Active subscription', 'membership2'), 'count' => $count); // Cancelled $url = esc_url_raw(add_query_arg('status', MS_Model_Relationship::STATUS_CANCELED)); $args['subscription_status'] = MS_Model_Relationship::STATUS_CANCELED; $count = MS_Model_Member::get_members_count($args); $views['cancelled'] = array('url' => $url, 'label' => __('Cancelled', 'membership2'), 'count' => $count); // Trial if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL)) { $url = esc_url_raw(add_query_arg('status', MS_Model_Relationship::STATUS_TRIAL)); $args['subscription_status'] = MS_Model_Relationship::STATUS_TRIAL; $count = MS_Model_Member::get_members_count($args); $views['trial'] = array('url' => $url, 'label' => __('Trial', 'membership2'), 'count' => $count); } // Expired, Trial-Expired $url = esc_url_raw(add_query_arg('status', 'expired')); $args['subscription_status'] = 'expired'; $count = MS_Model_Member::get_members_count($args); $views['expired'] = array('url' => $url, 'label' => __('Expired', 'membership2'), 'count' => $count); return $views; }
/** * Returns a specific property. * * @since 1.0.0 * * @param string $property The name of a property. * @return mixed $value The value of a property. */ public function __get($property) { $value = null; switch ($property) { case 'menu_protection': if (!MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_ADV_MENUS)) { $value = 'item'; } else { $value = $this->menu_protection; } break; default: if (property_exists($this, $property)) { $value = $this->{$property}; } else { switch ($property) { case 'currency_symbol': // Same translation table in: // -> ms-view-membership-setup-payment.js $symbol = $this->currency; switch ($symbol) { case 'USD': $symbol = '$'; break; case 'EUR': $symbol = '€'; break; case 'JPY': $symbol = '¥'; break; } $value = $symbol; } } } return apply_filters('ms_model_settings__get', $value, $property, $this); }
/** * Check membership status. * * Execute actions when time/period condition are met. * E.g. change membership status, add communication to queue, create invoices. * * This check is called via a cron job. * * @since 1.0.0 * @internal Used by Cron * @see MS_Model_Plugin::check_membership_status() */ public function check_membership_status() { do_action('ms_model_relationship_check_membership_status_before', $this); /** * Use `define( 'MS_LOCK_SUBSCRIPTIONS', true );` in wp-config.php to prevent * Membership2 from sending *any* emails to users. * Also any currently enqueued message is removed from the queue * * @since 1.0.0 */ if (MS_Plugin::get_modifier('MS_LOCK_SUBSCRIPTIONS')) { return false; } $membership = $this->get_membership(); $remaining_days = $this->get_remaining_period(); $remaining_trial_days = $this->get_remaining_trial_period(); $comms = MS_Model_Communication::get_communications($membership); $invoice_before_days = 5; //@todo create a setting to configure this period. $deactivate_expired_after_days = 30; //@todo create a setting to configure this period. $deactivate_pending_after_days = 30; //@todo create a setting to configure this period. $deactivate_trial_expired_after_days = 5; //@todo create a setting to configure this period. //@todo: Add a flag to subscriptions with sent communications. Then improve the conditions below to prevent multiple emails. do_action('ms_check_membership_status-' . $this->status, $this, $remaining_days, $remaining_trial_days); // Update the Subscription status. $next_status = $this->calculate_status(null); switch ($next_status) { case self::STATUS_TRIAL: if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL) && MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_AUTO_MSGS_PLUS)) { // Send trial end communication. $comm = $comms[MS_Model_Communication::COMM_TYPE_BEFORE_TRIAL_FINISHES]; if ($comm->enabled) { $days = MS_Helper_Period::get_period_in_days($comm->period['period_unit'], $comm->period['period_type']); //@todo: This will send out the reminder multiple times on the reminder-day (4 times or more often) if ($days == $remaining_trial_days) { $comm->add_to_queue($this->id); MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_BEFORE_TRIAL_FINISHES, $this); } } } // Check for card expiration $gateway = $this->get_gateway(); $gateway->check_card_expiration($this); break; case self::STATUS_TRIAL_EXPIRED: if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL)) { // Mark the trial period as completed. $this->save() is below. $this->trial_period_completed = true; // Request payment to the gateway (for gateways that allows it). $gateway = $this->get_gateway(); /* * The subscription will be either automatically activated * or set to pending. * * Important: Set trial_period_completed=true before calling * request_payment()! */ if ($gateway->request_payment($this)) { $next_status = self::STATUS_ACTIVE; $this->status = $next_status; $this->config_period(); // Needed because of status change. } // Check for card expiration $gateway->check_card_expiration($this); // Deactivate expired memberships after a period of time. if ($deactivate_trial_expired_after_days < -$remaining_trial_days) { $this->deactivate_membership(); } } break; case self::STATUS_ACTIVE: case self::STATUS_EXPIRED: case self::STATUS_CANCELED: /* * Make sure the expire date has a correct value, in case the user * changed the payment_type of the parent membership after this * subscription was created. */ if ($this->payment_type != $membership->payment_type) { $this->payment_type = $membership->payment_type; switch ($this->payment_type) { case MS_Model_Membership::PAYMENT_TYPE_PERMANENT: $this->expire_date = false; break; default: // Either keep the current expire date (if valid) or // calculate a new expire date, based on current date. if (!$this->expire_date) { $this->expire_date = $this->calc_expire_date(MS_Helper_Period::current_date()); } break; } // Recalculate the days until the subscription expires. $remaining_days = $this->get_remaining_period(); // Recalculate the new Subscription status. $next_status = $this->calculate_status(); } /* * Only "Recurring" memberships will ever try to automatically * renew the subscription. All other types will expire when the * end date is reached. */ $auto_renew = $membership->payment_type == MS_Model_Membership::PAYMENT_TYPE_RECURRING; $deactivate = false; $invoice = null; if ($auto_renew && $membership->pay_cycle_repetitions > 0) { /* * The membership has a payment-repetition limit. * When this limit is reached then we do not auto-renew the * subscription but expire it. */ $payments = $this->get_payments(); if (count($payments) >= $membership->pay_cycle_repetitions) { $auto_renew = false; } } if ($auto_renew) { if ($remaining_days < $invoice_before_days) { // Create a new invoice. $invoice = $this->get_next_invoice(); } else { $invoice = $this->get_current_invoice(); } } else { $invoice = $this->get_current_invoice(); } // Advanced communications Add-on. if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_AUTO_MSGS_PLUS)) { // Before finishes communication. $comm = $comms[MS_Model_Communication::COMM_TYPE_BEFORE_FINISHES]; $days = MS_Helper_Period::get_period_in_days($comm->period['period_unit'], $comm->period['period_type']); if ($days == $remaining_days) { $comm->add_to_queue($this->id); MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_BEFORE_FINISHES, $this); } // After finishes communication. $comm = $comms[MS_Model_Communication::COMM_TYPE_AFTER_FINISHES]; $days = MS_Helper_Period::get_period_in_days($comm->period['period_unit'], $comm->period['period_type']); if ($remaining_days < 0 && $days == abs($remaining_days)) { $comm->add_to_queue($this->id); MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_AFTER_FINISHES, $this); } // Before payment due. $comm = $comms[MS_Model_Communication::COMM_TYPE_BEFORE_PAYMENT_DUE]; $days = MS_Helper_Period::get_period_in_days($comm->period['period_unit'], $comm->period['period_type']); $invoice_days = MS_Helper_Period::subtract_dates($invoice->due_date, MS_Helper_Period::current_date()); if (MS_Model_Invoice::STATUS_BILLED == $invoice->status && $days == $invoice_days) { $comm->add_to_queue($this->id); MS_Model_Event::save_event(MS_Model_Event::TYPE_PAYMENT_BEFORE_DUE, $this); } // After payment due event $comm = $comms[MS_Model_Communication::COMM_TYPE_AFTER_PAYMENT_DUE]; $days = MS_Helper_Period::get_period_in_days($comm->period['period_unit'], $comm->period['period_type']); $invoice_days = MS_Helper_Period::subtract_dates($invoice->due_date, MS_Helper_Period::current_date()); if (MS_Model_Invoice::STATUS_BILLED == $invoice->status && $days == $invoice_days) { $comm->add_to_queue($this->id); MS_Model_Event::save_event(MS_Model_Event::TYPE_PAYMENT_AFTER_DUE, $this); } } // -- End of advanced communications Add-on // Subscription ended. See if we can renew it. if ($remaining_days <= 0) { if ($auto_renew) { /* * The membership can be renewed. Try to renew it * automatically by requesting the next payment from the * payment gateway (only works if gateway supports this) */ $gateway = $this->get_gateway(); $gateway->check_card_expiration($this); $gateway->request_payment($this); // Check if the payment was successful. $remaining_days = $this->get_remaining_period(); } /* * User did not renew the membership. Give him some time to * react before restricting his access. */ if ($deactivate_expired_after_days < -$remaining_days) { $deactivate = true; } } $next_status = $this->calculate_status(null); /* * When the subscription expires the first time then create a * new event that triggers the "Expired" email. */ if (self::STATUS_EXPIRED == $next_status && $next_status != $this->status) { MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_EXPIRED, $this); } elseif ($deactivate) { $this->deactivate_membership(); $next_status = $this->status; // Move membership to configured membership. $membership = $this->get_membership(); $new_membership = MS_Factory::load('MS_Model_Membership', $membership->on_end_membership_id); if ($new_membership->is_valid()) { $member = MS_Factory::load('MS_Model_Member', $this->user_id); $new_subscription = $member->add_membership($membership->on_end_membership_id, $this->gateway_id); MS_Model_Event::save_event(MS_Model_Event::TYPE_MS_MOVED, $new_subscription); /* * If the new membership is paid we want that the user * confirms the payment in his account. So we set it * to "Pending" first. */ if (!$new_membership->is_free()) { $new_subscription->status = self::STATUS_PENDING; } } } break; case self::STATUS_DEACTIVATED: /* * A subscription was finally deactivated. * Lets check if the member has any other active subscriptions, * or (if not) his account should be deactivated. * * First get a list of all subscriptions that do not have status * Pending / Deactivated. */ $subscriptions = self::get_subscriptions(array('user_id' => $this->user_id)); // Check if there is a subscription that keeps the user active. $deactivate = true; foreach ($subscriptions as $item) { if ($item->id == $this->id) { continue; } $deactivate = false; } if ($deactivate) { $member = $this->get_member(); $member->is_member = false; $member->save(); } break; case self::STATUS_PENDING: default: // Do nothing. break; } // Save the new status. $this->status = $next_status; $this->save(); // Save the changed email queue. foreach ($comms as $comm) { $comm->save(); } do_action('ms_model_relationship_check_membership_status_after', $this); }