/**
  * 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;
     }
     /*
      * 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;
             }
         }
     }
     return apply_filters('ms_rule_media_can_access_file', $access, $attachment_id);
 }
 /**
  * Get a simple array of capabilties (e.g. for display in select lists)
  *
  * @since  1.0.0
  * @global array $menu
  *
  * @return array {
  *      @type string $id The id.
  *      @type string $name The name.
  * }
  */
 public function get_capabilities($args = null)
 {
     if (null === $this->_content_array) {
         $this->_content_array = array();
         $member = MS_Model_Member::get_current_member();
         $capslist = $member->wp_user->allcaps;
         $ignored_caps = array('level_10' => 1, 'level_9' => 1, 'level_8' => 1, 'level_7' => 1, 'level_6' => 1, 'level_5' => 1, 'level_4' => 1, 'level_3' => 1, 'level_2' => 1, 'level_1' => 1, 'level_0' => 1, 'administrator' => 1);
         $capslist = array_diff_assoc($capslist, $ignored_caps);
         $capslist = array_keys($capslist);
         /**
          * Exclude certain capabilities for security reasons.
          *
          * @since  1.0.0
          * @var array
          */
         $exclude = apply_filters('ms_rule_membercaps_model_exclude', array(MS_Plugin::instance()->controller->capability, 'edit_plugins', 'delete_plugins', 'edit_files', 'edit_users', 'delete_users', 'remove_users', 'promote_users', 'list_users'));
         $capslist = array_diff($capslist, $exclude);
         $this->_content_array = array_combine($capslist, $capslist);
         // Make sure the rule_value only contains valid items.
         $rule_value = array_intersect_key($this->rule_value, $this->_content_array);
         $this->rule_value = lib2()->array->get($rule_value);
         // If not visitor membership, just show Membership2
         if (!$this->get_membership()->is_base()) {
             $this->_content_array = array_intersect_key($this->_content_array, $this->rule_value);
         }
         $this->_content_array = apply_filters('ms_rule_membercaps_model_get_content_array', $this->_content_array, $this);
     }
     $contents = $this->_content_array;
     // Search the shortcode-tag...
     if (!empty($args['s'])) {
         foreach ($contents as $key => $name) {
             if (false === stripos($name, $args['s'])) {
                 unset($contents[$key]);
             }
         }
     }
     $filter = self::get_exclude_include($args);
     if (is_array($filter->include)) {
         $contents = array_intersect($contents, $filter->include);
     } elseif (is_array($filter->exclude)) {
         $contents = array_diff($contents, $filter->exclude);
     }
     // Pagination
     if (!empty($args['posts_per_page'])) {
         $total = $args['posts_per_page'];
         $offset = !empty($args['offset']) ? $args['offset'] : 0;
         $contents = array_slice($contents, $offset, $total);
     }
     return $contents;
 }
 /**
  * Returns a URL to trigger the specified membership action.
  *
  * The URL can be used in a link or a form with only a submit button.
  *
  * @since  1.0.0
  * @param  string $action
  * @return string The URL.
  */
 protected function get_action_url($membership, $action, $step)
 {
     if (empty($this->data['member'])) {
         $member = MS_Model_Member::get_current_member();
     } else {
         $member = $this->data['member'];
     }
     if (is_numeric($membership)) {
         $membership = MS_Factory::load('MS_Model_Membership', $membership);
     }
     $membership->_move_from = $member->cancel_ids_on_subscription($membership->id);
     $fields = $this->prepare_fields($membership->id, $action, $step, $membership->_move_from);
     if (is_user_logged_in()) {
         $current = MS_Model_Pages::MS_PAGE_MEMBERSHIPS;
     } else {
         $current = MS_Model_Pages::MS_PAGE_REGISTER;
     }
     $url = MS_Model_Pages::get_page_url($current);
     if ($action == MS_Helper_Membership::MEMBERSHIP_ACTION_SIGNUP) {
         // Only add the membership_id to the URL.
         $url = esc_url_raw(add_query_arg('membership_id', $membership->id, $url));
     } else {
         $url = esc_url_raw(add_query_arg('_wpnonce', wp_create_nonce($action), $url));
         foreach ($fields as $field) {
             $url = esc_url_raw(add_query_arg($field['id'], $field['value'], $url));
         }
     }
     return apply_filters('ms_view_shortcode_membershipsignup_action_url', $url, $action, $membership, $this);
 }
 /**
  * Get membership eligible to signup.
  *
  * This function also checks for membership permissions and only display
  * memberships that are available for the current member.
  *
  * @since  1.0.0
  * @internal
  *
  * @param $args The query post args
  *     @see @link http://codex.wordpress.org/Class_Reference/WP_Query
  * @param int[] $exclude_ids Optional. The membership ids to exclude.
  * @param bool $only_names Optional. Return only array {
  *     @type int $membership_id The membership ID.
  *     @type string $membership_name The membership name.
  * }
  * @param bool $include_private If private memberships should be listed
  *     This param is only recognized in the admin section so admins can
  *     manually assign a private membership to a user.
  * @return array Returns sorted array of memberships. Sorted by priority.
  */
 public static function get_signup_membership_list($args = null, $exclude_ids = null, $only_names = false, $include_private = false)
 {
     $not_in = array();
     if (is_array($exclude_ids)) {
         $not_in = $exclude_ids;
     }
     $args['post__not_in'] = array_unique($not_in);
     $member = MS_Model_Member::get_current_member();
     if (!is_admin()) {
         $include_private = false;
     }
     // List of private memberships (they are grouped in own array).
     $private = array();
     // Retrieve memberships user is not part of, using selected args
     $memberships = self::get_memberships($args);
     // Check the upgrade-paths settings
     foreach ($memberships as $key => $ms) {
         if ($ms->is_system()) {
             unset($memberships[$key]);
         } elseif (!$member->can_subscribe_to($ms->id)) {
             unset($memberships[$key]);
         }
     }
     // Filter memberships based on status.
     $order = array();
     foreach ($memberships as $key => $membership) {
         // Remove if not active.
         if (!$membership->active) {
             unset($memberships[$key]);
             continue;
         }
         if ($membership->private) {
             if ($include_private) {
                 // Move the private memberships to a option-group.
                 $private[$key] = $memberships[$key];
             }
             unset($memberships[$key]);
             continue;
         }
     }
     if ($only_names) {
         $ms_names = array();
         foreach ($memberships as $ms) {
             $ms_names[$ms->id] = $ms->name;
         }
         if (!empty($private)) {
             $priv_key = __('Private Memberships', 'membership2');
             $ms_names[$priv_key] = array();
             foreach ($private as $ms) {
                 $ms_names[$priv_key][$ms->id] = $ms->name;
             }
         }
         $memberships = $ms_names;
     } else {
         $memberships = array_merge($memberships, $private);
     }
     // Sort memberships by priority.
     usort($memberships, array(__CLASS__, 'sort_by_priority'));
     return apply_filters('ms_model_membership_get_signup_membership_list', $memberships, $exclude_ids, $only_names);
 }
 /**
  * Returns HTML partial that contains the logout form
  *
  * @since  1.0.0
  *
  * @return string
  */
 private function logout_form()
 {
     if (!MS_Model_Member::is_logged_in()) {
         return '';
     }
     $member = MS_Model_Member::get_current_member();
     extract($this->data);
     if (empty($redirect_logout)) {
         $redirect_logout = MS_Helper_Utility::home_url('/');
     }
     $yourname = sprintf(__('You are logged in as %s.', 'membership2'), ucfirst($member->name));
     $yourname = apply_filters('ms_shortcode_logout_message', $yourname, $member);
     $logout_text = apply_filters('ms_shortcode_logout_link_text', __('Logout', 'membership2'), $member);
     $redirect_logout = apply_filters('ms_shortcode_logout_redirect', $redirect_logout, $member);
     $html = sprintf('%1$s <a class="login_button" href="%2$s">%3$s</a>', $yourname, wp_logout_url($redirect_logout), $logout_text);
     if (!empty($holder)) {
         $html = sprintf('<%1$s class="%2$s">%3$s</%1$s>', esc_attr($holder), esc_attr($holderclass), $html);
     }
     return $html;
 }
 /**
  * Determines the users country based on his IP address.
  *
  * @since  1.0.0
  * @internal
  *
  * @param string $mode [declared|vat|card|auto] Either the country from user
  *        settings or the auto-detected country.
  */
 protected static function fetch_country($mode = 'declared')
 {
     $member = MS_Model_Member::get_current_member();
     $country = false;
     $store_it = false;
     $non_auto_countries = array('declared', 'vat', 'card');
     if (!in_array($mode, $non_auto_countries)) {
         $mode = 'auto';
     }
     $auto_detect = 'auto' == $mode;
     $key = 'tax_' . $mode . '_country';
     // If no country is stored use the API to determine it.
     if ($auto_detect) {
         try {
             $ip_info = lib3()->net->current_ip();
             $data = (object) (array) self::taxamo()->locateGivenIP($ip_info->ip);
             $country = (object) array('code' => $data->country_code);
             // Store result in Session, not in DB.
             $store_it = true;
             $member = null;
         } catch (Exception $ex) {
             MS_Helper_Debug::log('Taxamo error: ' . $ex->getMessage());
         }
     } else {
         // Try to get the stored country from user-meta or session (for guest)
         $country = self::get_tax_profile_value($member, $key);
     }
     // API did not return a valid resonse, use a dummy value.
     if (!$country) {
         $country = (object) array('code' => '');
     }
     // Store result in user-deta or session.
     if ($store_it && self::set_tax_profile_value($member, $key, $country)) {
         $member->save();
     }
     $country_names = self::get_country_codes('name');
     if ($country->code && isset($country_names[$country->code])) {
         $country->name = $country_names[$country->code];
     } else {
         $country->name = $country_names['XX'];
     }
     return $country;
 }
 /**
  * Save data from the REQUEST collection to the XProfile fields.
  *
  * This action is called in two cases:
  * 1. After a new user was created in the Database.
  * 2. When the user saves his profile in M2 frontend.
  *
  * @since  1.0.1.0
  */
 public function save_xprofile()
 {
     $fields = false;
     $user = false;
     if (!isset($_REQUEST['email'])) {
         // Seems like the user was not created by M2. Not our call.
         return;
     }
     if (isset($_REQUEST['signup_profile_field_ids'])) {
         // A new user was created in the database. Great job!
         $user = get_user_by('email', $_REQUEST['email']);
         $fields = explode(',', $_REQUEST['signup_profile_field_ids']);
     } elseif (isset($_REQUEST['xprofile_field_ids'])) {
         // A new user was created in the database. Great job!
         $user = MS_Model_Member::get_current_member()->get_user();
         $fields = explode(',', $_REQUEST['xprofile_field_ids']);
     }
     if ($fields && $user) {
         foreach ($fields as $field_id) {
             if (!isset($_REQUEST['field_' . $field_id])) {
                 continue;
             }
             xprofile_set_field_data($field_id, $user->ID, $_REQUEST['field_' . $field_id]);
         }
     }
 }
 /**
  * Returns the Member object of the current user.
  *
  * @since  1.0.0
  * @api
  *
  * @return MS_Model_Member The Member model.
  */
 public function get_current_member()
 {
     $member = MS_Model_Member::get_current_member();
     return $member;
 }
 /**
  * Returns HTML partial that contains the logout form
  *
  * @since  1.0.0
  *
  * @return string
  */
 private function logout_form()
 {
     if (!MS_Model_Member::is_logged_in()) {
         return '';
     }
     $member = MS_Model_Member::get_current_member();
     extract($this->data);
     if (empty($redirect_logout)) {
         $redirect_logout = home_url();
     }
     $yourname = sprintf(__('You are logged in as %s.', MS_TEXT_DOMAIN), ucfirst($member->username));
     $html = sprintf('%1$s <a class="login_button" href="%2$s">%3$s</a>', $yourname, wp_logout_url($redirect_logout), __('Logout', MS_TEXT_DOMAIN));
     if (!empty($holder)) {
         $html = sprintf('<%1$s class="%2$s">%3$s</%1$s>', esc_attr($holder), esc_attr($holderclass), $html);
     }
     return $html;
 }
 /**
  * Initialise current member.
  *
  * Get current member and membership relationships.
  * If user is not logged in (visitor), assign a visitor membership.
  * If user is logged in but has not any memberships, assign a default membership.
  * Deactivated users (active == false) get visitor membership assigned.
  *
  * @since  1.0.0
  */
 public function init_member()
 {
     do_action('ms_load_member', $this);
     $this->member = MS_Model_Member::get_current_member();
     if (MS_Plugin::is_enabled()) {
         if (!is_user_logged_in()) {
             // If a Guest-Membership exists we also assign it to the user.
             $ms_guest = MS_Model_Membership::get_guest();
             if ($ms_guest->is_valid() && $ms_guest->active) {
                 $this->member->add_membership($ms_guest->id);
             }
         } elseif (!$this->member->has_membership()) {
             // Apply User-Membership to logged-in users without subscriptions.
             $ms_user = MS_Model_Membership::get_user();
             if ($ms_user->is_valid() && $ms_user->active) {
                 $this->member->add_membership($ms_user->id);
             }
         } elseif (!$this->member->is_member) {
             $this->member->subscriptions = array();
         }
         // No subscription: Assign the base membership, which only denies access.
         if (!$this->member->has_membership()) {
             $this->member->add_membership(MS_Model_Membership::get_base()->id);
         }
     }
     /**
      * At this point the plugin is initialized and we are here:
      *   - All Add-Ons are registered
      *   - All Rules are registered
      *   - Know the current User
      *     - All Subscriptions/Memberships of the user are loaded
      *     - System memberships are already assigned (guest/base)
      *   - Payment gateways are registered
      *   - Communication settings are loaded
      *
      * Next we tell everybody that we are ready to get serious!
      *
      * What happens next:
      *   1. All Membership-Rules are initialized/merged
      *   2. Front-End Protection is applied
      *   3. Admin-Side Protection is applied
      */
     do_action('ms_init_done', $this);
 }
 /**
  * Membership account page shortcode callback function.
  *
  * @since  1.0.0
  *
  * @param mixed[] $atts Shortcode attributes.
  */
 public function membership_account($atts)
 {
     MS_Helper_Shortcode::did_shortcode(MS_Helper_Shortcode::SCODE_MS_ACCOUNT);
     $data = apply_filters('ms_controller_shortcode_membership_account_atts', shortcode_atts(array('show_membership' => true, 'show_membership_change' => true, 'membership_title' => __('Your Membership', 'membership2'), 'membership_change_label' => __('Change', 'membership2'), 'show_profile' => true, 'show_profile_change' => true, 'profile_title' => __('Personal details', 'membership2'), 'profile_change_label' => __('Edit', 'membership2'), 'show_invoices' => true, 'limit_invoices' => 10, 'show_all_invoices' => true, 'invoices_title' => __('Invoices', 'membership2'), 'invoices_details_label' => __('View all', 'membership2'), 'show_activity' => true, 'limit_activities' => 10, 'show_all_activities' => true, 'activity_title' => __('Activities', 'membership2'), 'activity_details_label' => __('View all', 'membership2')), $atts));
     $data['show_membership'] = lib3()->is_true($data['show_membership']);
     $data['show_membership_change'] = lib3()->is_true($data['show_membership_change']);
     $data['show_profile'] = lib3()->is_true($data['show_profile']);
     $data['show_profile_change'] = lib3()->is_true($data['show_profile_change']);
     $data['show_invoices'] = lib3()->is_true($data['show_invoices']);
     $data['show_all_invoices'] = lib3()->is_true($data['show_all_invoices']);
     $data['show_activity'] = lib3()->is_true($data['show_activity']);
     $data['show_all_activities'] = lib3()->is_true($data['show_all_activities']);
     $data['limit_invoices'] = absint($data['limit_invoices']);
     $data['limit_activities'] = absint($data['limit_activities']);
     $data['member'] = MS_Model_Member::get_current_member();
     $data['membership'] = array();
     $subscriptions = MS_Model_Relationship::get_subscriptions(array('user_id' => $data['member']->id, 'status' => 'all'));
     if (is_array($subscriptions)) {
         foreach ($subscriptions as $subscription) {
             // Do not display system-memberships in Account
             if ($subscription->is_system()) {
                 continue;
             }
             // Do not display deactivated memberships in Account
             if ($subscription->get_status() == MS_Model_Relationship::STATUS_DEACTIVATED) {
                 continue;
             }
             $data['subscription'][] = $subscription;
         }
     }
     $data['invoices'] = MS_Model_Invoice::get_public_invoices($data['member']->id, $data['limit_invoices']);
     $data['events'] = MS_Model_Event::get_events(array('author' => $data['member']->id, 'posts_per_page' => $data['limit_activities']));
     $view = MS_Factory::create('MS_View_Shortcode_Account');
     $view->data = apply_filters('ms_view_shortcode_account_data', $data, $this);
     return $view->to_html();
 }
 /**
  * Handle update credit card information in gateway.
  *
  * Used to change credit card info in account's page.
  *
  * Related action hooks:
  * - template_redirect
  *
  * @since  1.0.0
  */
 public function update_card()
 {
     if (!empty($_POST['gateway'])) {
         $gateway = MS_Model_Gateway::factory($_POST['gateway']);
         $member = MS_Model_Member::get_current_member();
         switch ($gateway->id) {
             case MS_Gateway_Stripe::ID:
                 if (!empty($_POST['stripeToken']) && $this->verify_nonce()) {
                     lib2()->array->strip_slashes($_POST, 'stripeToken');
                     $gateway->add_card($member, $_POST['stripeToken']);
                     if (!empty($_POST['ms_relationship_id'])) {
                         $ms_relationship = MS_Factory::load('MS_Model_Relationship', $_POST['ms_relationship_id']);
                         MS_Model_Event::save_event(MS_Model_Event::TYPE_UPDATED_INFO, $ms_relationship);
                     }
                     wp_safe_redirect(esc_url_raw(add_query_arg(array('msg' => 1))));
                     exit;
                 }
                 break;
             case MS_Gateway_Authorize::ID:
                 if ($this->verify_nonce()) {
                     do_action('ms_controller_frontend_signup_gateway_form', $this);
                 } elseif (!empty($_POST['ms_relationship_id']) && $this->verify_nonce($_POST['gateway'] . '_' . $_POST['ms_relationship_id'])) {
                     $gateway->update_cim_profile($member);
                     $gateway->save_card_info($member);
                     if (!empty($_POST['ms_relationship_id'])) {
                         $ms_relationship = MS_Factory::load('MS_Model_Relationship', $_POST['ms_relationship_id']);
                         MS_Model_Event::save_event(MS_Model_Event::TYPE_UPDATED_INFO, $ms_relationship);
                     }
                     wp_safe_redirect(esc_url_raw(add_query_arg(array('msg' => 1))));
                     exit;
                 }
                 break;
             default:
                 break;
         }
     }
     do_action('ms_controller_gateway_update_card', $this);
 }
    public function to_html()
    {
        $fields = $this->prepare_fields();
        $subscription = $this->data['ms_relationship'];
        $invoice = $subscription->get_current_invoice();
        $member = MS_Model_Member::get_current_member();
        $gateway = $this->data['gateway'];
        // Stripe is using Ajax, so the URL is empty.
        $action_url = apply_filters('ms_gateway_stripeplan_view_button_form_action_url', '');
        $row_class = 'gateway_' . $gateway->id;
        if (!$gateway->is_live_mode()) {
            $row_class .= ' sandbox-mode';
        }
        $stripe_data = array('name' => get_bloginfo('name'), 'description' => strip_tags($invoice->short_description), 'label' => $gateway->pay_button_url);
        /**
         * Users can change details (like the title or description) of the
         * stripe checkout popup.
         *
         * @since  1.0.2.4
         * @var array
         */
        $stripe_data = apply_filters('ms_gateway_stripe_form_details', $stripe_data, $invoice);
        $stripe_data['email'] = $member->email;
        $stripe_data['key'] = $gateway->get_publishable_key();
        $stripe_data['currency'] = $invoice->currency;
        $stripe_data['amount'] = ceil(abs($invoice->total * 100));
        // Amount in cents.
        ob_start();
        ?>
		<form action="<?php 
        echo esc_url($action_url);
        ?>
" method="post">
			<?php 
        foreach ($fields as $field) {
            MS_Helper_Html::html_element($field);
        }
        ?>
			<script
				src="https://checkout.stripe.com/checkout.js" class="stripe-button"
				<?php 
        foreach ($stripe_data as $key => $value) {
            printf('data-%s="%s" ', esc_attr($key), esc_attr($value));
        }
        ?>
			></script>
		</form>
		<?php 
        $payment_form = apply_filters('ms_gateway_form', ob_get_clean(), $gateway, $invoice, $this);
        ob_start();
        ?>
		<tr class="<?php 
        echo esc_attr($row_class);
        ?>
">
			<td class="ms-buy-now-column" colspan="2">
				<?php 
        echo $payment_form;
        ?>
			</td>
		</tr>
		<?php 
        $html = ob_get_clean();
        $html = apply_filters('ms_gateway_button-' . $gateway->id, $html, $this);
        return $html;
    }
    public function to_html()
    {
        global $post;
        /**
         * Provide a customized account page.
         *
         * @since  1.0.0
         */
        $html = apply_filters('ms_shortcode_custom_account', '', $this->data);
        if (!empty($html)) {
            return $html;
        } else {
            $html = '';
        }
        $member = MS_Model_Member::get_current_member();
        $fields = $this->prepare_fields();
        // Extract shortcode options.
        extract($this->data);
        ob_start();
        ?>
		<div class="ms-account-wrapper">
			<?php 
        if (MS_Model_Member::is_logged_in()) {
            ?>

				<?php 
            // ================================================= MEMBERSHIPS
            if ($show_membership) {
                ?>
				<div id="account-membership">
				<h2>
					<?php 
                echo $membership_title;
                if ($show_membership_change) {
                    $signup_url = MS_Model_Pages::get_page_url(MS_Model_Pages::MS_PAGE_REGISTER);
                    printf('<a href="%s" class="ms-edit-profile">%s</a>', $signup_url, $membership_change_label);
                }
                ?>
				</h2>
				<?php 
                /**
                 * Add custom content right before the memberships list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_memberships_top', $member, $this);
                if (MS_Model_Member::is_admin_user()) {
                    _e('You are an admin user and have access to all memberships', 'membership2');
                } else {
                    if (!empty($this->data['subscription'])) {
                        ?>
						<table>
							<tr>
								<th class="ms-col-membership"><?php 
                        _e('Membership name', 'membership2');
                        ?>
</th>
								<th class="ms-col-status"><?php 
                        _e('Status', 'membership2');
                        ?>
</th>
								<th class="ms-col-expire-date"><?php 
                        _e('Expire date', 'membership2');
                        ?>
</th>
							</tr>
							<?php 
                        $empty = true;
                        // These subscriptions have no expire date
                        $no_expire_list = array(MS_Model_Relationship::STATUS_PENDING, MS_Model_Relationship::STATUS_WAITING, MS_Model_Relationship::STATUS_DEACTIVATED);
                        // These subscriptions display the trial-expire date
                        $trial_expire_list = array(MS_Model_Relationship::STATUS_TRIAL, MS_Model_Relationship::STATUS_TRIAL_EXPIRED);
                        foreach ($this->data['subscription'] as $subscription) {
                            $empty = false;
                            $membership = $subscription->get_membership();
                            $subs_classes = array('ms-subscription-' . $subscription->id, 'ms-status-' . $subscription->status, 'ms-type-' . $membership->type, 'ms-payment-' . $membership->payment_type, 'ms-gateway-' . $subscription->gateway_id, 'ms-membership-' . $subscription->membership_id, $subscription->has_trial() ? 'ms-with-trial' : 'ms-no-trial');
                            ?>
								<tr class="<?php 
                            echo esc_attr(implode(' ', $subs_classes));
                            ?>
">
									<td class="ms-col-membership"><?php 
                            echo esc_html($membership->name);
                            ?>
</td>
									<td class="ms-col-status">
									<?php 
                            if (MS_Model_Relationship::STATUS_PENDING == $subscription->status) {
                                // Display a "Purchase" link when status is Pending
                                $code = sprintf('[%s id="%s" label="%s"]', MS_Helper_Shortcode::SCODE_MS_BUY, $membership->id, __('Pending', 'membership2'));
                                echo do_shortcode($code);
                            } else {
                                echo esc_html($subscription->status_text());
                            }
                            ?>
									</td>
									<td class="ms-col-expire-date"><?php 
                            if (in_array($subscription->status, $no_expire_list)) {
                                echo '&nbsp;';
                            } elseif (in_array($subscription->status, $trial_expire_list)) {
                                echo esc_html(MS_Helper_Period::format_date($subscription->trial_expire_date));
                            } elseif ($subscription->expire_date) {
                                echo esc_html(MS_Helper_Period::format_date($subscription->expire_date));
                            } else {
                                _e('Never', 'membership2');
                            }
                            ?>
</td>
								</tr>
							<?php 
                        }
                        if ($empty) {
                            $cols = 3;
                            if (MS_Model_Addon::is_enabled(MS_Model_Addon::ADDON_TRIAL)) {
                                $cols += 1;
                            }
                            printf('<tr><td colspan="%1$s">%2$s</td></tr>', $cols, __('(No Membership)', 'membership2'));
                        }
                        ?>
						</table>
					<?php 
                    } else {
                        _e('No memberships', 'membership2');
                    }
                }
                /**
                 * Add custom content right after the memberships list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_memberships_bottom', $member, $this);
                ?>
				</div>
				<?php 
            }
            // END: if ( $show_membership )
            // =============================================================
            ?>

				<?php 
            // ===================================================== PROFILE
            if ($show_profile) {
                ?>
				<div id="account-profile">
				<h2>
					<?php 
                echo $profile_title;
                if ($show_profile_change) {
                    $edit_url = esc_url_raw(add_query_arg(array('action' => MS_Controller_Frontend::ACTION_EDIT_PROFILE)));
                    printf('<a href="%s" class="ms-edit-profile">%s</a>', $edit_url, $profile_change_label);
                }
                ?>
				</h2>
				<?php 
                /**
                 * Add custom content right before the profile overview.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_profile_top', $member, $this);
                ?>
				<table>
					<?php 
                foreach ($fields['personal_info'] as $field => $title) {
                    ?>
						<tr>
							<th class="ms-label-title"><?php 
                    echo esc_html($title);
                    ?>
: </th>
							<td class="ms-label-field"><?php 
                    echo esc_html($this->data['member']->{$field});
                    ?>
</td>
						</tr>
					<?php 
                }
                ?>
				</table>
				<?php 
                do_action('ms_view_shortcode_account_card_info', $this->data);
                /**
                 * Add custom content right after the profile overview.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_profile_bottom', $member, $this);
                ?>
				</div>
				<?php 
            }
            // END: if ( $show_profile )
            // =============================================================
            ?>

				<?php 
            // ==================================================== INVOICES
            if ($show_invoices) {
                ?>
				<div id="account-invoices">
				<h2>
					<?php 
                echo $invoices_title;
                if ($show_all_invoices) {
                    $detail_url = esc_url_raw(add_query_arg(array('action' => MS_Controller_Frontend::ACTION_VIEW_INVOICES)));
                    printf('<a href="%s" class="ms-all-invoices">%s</a>', $detail_url, $invoices_details_label);
                }
                ?>
				</h2>
				<?php 
                /**
                 * Add custom content right before the invoice overview list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_invoices_top', $member, $this);
                ?>
				<table>
					<thead>
						<tr>
							<th class="ms-col-invoice-no"><?php 
                _e('Invoice #', 'membership2');
                ?>
</th>
							<th class="ms-col-invoice-status"><?php 
                _e('Status', 'membership2');
                ?>
</th>
							<th class="ms-col-invoice-total"><?php 
                printf('%s (%s)', __('Total', 'membership2'), MS_Plugin::instance()->settings->currency);
                ?>
</th>
							<th class="ms-col-invoice-title"><?php 
                _e('Membership', 'membership2');
                ?>
</th>
							<th class="ms-col-invoice-due"><?php 
                _e('Due date', 'membership2');
                ?>
</th>
						</tr>
					</thead>
					<tbody>
					<?php 
                foreach ($this->data['invoices'] as $invoice) {
                    $inv_membership = MS_Factory::load('MS_Model_Membership', $invoice->membership_id);
                    $inv_classes = array('ms-invoice-' . $invoice->id, 'ms-subscription-' . $invoice->ms_relationship_id, 'ms-invoice-' . $invoice->status, 'ms-gateway-' . $invoice->gateway_id, 'ms-membership-' . $invoice->membership_id, 'ms-type-' . $inv_membership->type, 'ms-payment-' . $inv_membership->payment_type);
                    ?>
						<tr class="<?php 
                    echo esc_attr(implode(' ', $inv_classes));
                    ?>
">
							<td class="ms-col-invoice-no"><?php 
                    printf('<a href="%s">%s</a>', get_permalink($invoice->id), $invoice->get_invoice_number());
                    ?>
</td>
							<td class="ms-col-invoice-status"><?php 
                    echo esc_html($invoice->status_text());
                    ?>
</td>
							<td class="ms-col-invoice-total"><?php 
                    echo esc_html(MS_Helper_Billing::format_price($invoice->total));
                    ?>
</td>
							<td class="ms-col-invoice-title"><?php 
                    echo esc_html($inv_membership->name);
                    ?>
</td>
							<td class="ms-col-invoice-due"><?php 
                    echo esc_html(MS_Helper_Period::format_date($invoice->due_date, __('F j', 'membership2')));
                    ?>
</td>
						</tr>
					<?php 
                }
                ?>
					</tbody>
				</table>
				<?php 
                /**
                 * Add custom content right after the invoices overview list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_invoices_bottom', $member, $this);
                ?>
				</div>
				<?php 
            }
            // END: if ( $show_invoices )
            // =============================================================
            ?>

				<?php 
            // ==================================================== ACTIVITY
            if ($show_activity) {
                ?>
				<div id="account-activity">
				<h2>
					<?php 
                echo $activity_title;
                if ($show_all_activities) {
                    $detail_url = esc_url_raw(add_query_arg(array('action' => MS_Controller_Frontend::ACTION_VIEW_ACTIVITIES)));
                    printf('<a href="%s" class="ms-all-activities">%s</a>', $detail_url, $activity_details_label);
                }
                ?>
				</h2>
				<?php 
                /**
                 * Add custom content right before the activities overview list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_activity_top', $member, $this);
                ?>
				<table>
					<thead>
						<tr>
							<th class="ms-col-activity-date"><?php 
                _e('Date', 'membership2');
                ?>
</th>
							<th class="ms-col-activity-title"><?php 
                _e('Activity', 'membership2');
                ?>
</th>
						</tr>
					</thead>
					<tbody>
					<?php 
                foreach ($this->data['events'] as $event) {
                    $ev_classes = array('ms-activity-topic-' . $event->topic, 'ms-activity-type-' . $event->type, 'ms-membership-' . $event->membership_id);
                    ?>
						<tr class="<?php 
                    echo esc_attr(implode(' ', $ev_classes));
                    ?>
">
							<td class="ms-col-activity-date"><?php 
                    echo esc_html(MS_Helper_Period::format_date($event->post_modified));
                    ?>
</td>
							<td class="ms-col-activity-title"><?php 
                    echo esc_html($event->description);
                    ?>
</td>
						</tr>
					<?php 
                }
                ?>
					</tbody>
				</table>
				<?php 
                /**
                 * Add custom content right after the activities overview list.
                 *
                 * @since  1.0.0
                 */
                do_action('ms_view_account_activity_bottom', $member, $this);
                ?>
				</div>
				<?php 
            }
            // END: if ( $show_activity )
            // =============================================================
            ?>

			<?php 
        } else {
            $has_login_form = MS_Helper_Shortcode::has_shortcode(MS_Helper_Shortcode::SCODE_LOGIN, $post->post_content);
            if (!$has_login_form) {
                $redirect = esc_url_raw(add_query_arg(array()));
                $title = __('Your account', 'membership2');
                $scode = sprintf('[%1$s redirect="%2$s" title="%3$s"]', MS_Helper_Shortcode::SCODE_LOGIN, esc_url($redirect), esc_attr($title));
                echo do_shortcode($scode);
            }
        }
        ?>
		</div>
		<?php 
        $html = ob_get_clean();
        $html = apply_filters('ms_compact_code', $html);
        return apply_filters('ms_shortcode_account', $html, $this->data);
    }
 /**
  * Manage user account actions.
  *
  * @since  1.0.0
  * @internal
  */
 public function user_account_manager()
 {
     $action = $this->get_action();
     $member = MS_Model_Member::get_current_member();
     /**
      * These actions are always executed when any user account page loads.
      *
      * @since  1.0.1.0
      */
     do_action('ms_frontend_user_account_manager-' . $action, $this);
     do_action('ms_frontend_user_account_manager', $action, $this);
     if ($this->verify_nonce()) {
         /**
          * The following two actions are only executed when a form was
          * submitted on a user account page.
          *
          * @since  1.0.1.0
          */
         do_action('ms_frontend_user_account_manager_submit-' . $action, $this);
         do_action('ms_frontend_user_account_manager_submit', $action, $this);
     }
     switch ($action) {
         case self::ACTION_EDIT_PROFILE:
             $data = array();
             if ($this->verify_nonce()) {
                 if (is_array($_POST)) {
                     foreach ($_POST as $field => $value) {
                         $member->{$field} = $value;
                     }
                 }
                 try {
                     $member->validate_member_info();
                     $member->save();
                     wp_safe_redirect(esc_url_raw(remove_query_arg('action')));
                     exit;
                 } catch (Exception $e) {
                     $data['errors'] = $e->getMessage();
                 }
             }
             $view = MS_Factory::create('MS_View_Frontend_Profile');
             $data['member'] = $member;
             $data['action'] = $action;
             $view->data = apply_filters('ms_view_frontend_profile_data', $data, $this);
             $view->add_filter('the_content', 'to_html', 1);
             break;
         case self::ACTION_VIEW_INVOICES:
             $data['invoices'] = MS_Model_Invoice::get_public_invoices($member->id);
             $view = MS_Factory::create('MS_View_Frontend_Invoices');
             $view->data = apply_filters('ms_view_frontend_frontend_invoices', $data, $this);
             $view->add_filter('the_content', 'to_html', 1);
             break;
         case self::ACTION_VIEW_ACTIVITIES:
             $data['events'] = MS_Model_Event::get_events(array('author' => $member->id, 'posts_per_page' => -1));
             $view = MS_Factory::create('MS_View_Frontend_Activities');
             $view->data = apply_filters('ms_view_frontend_frontend_activities', $data, $this);
             $view->add_filter('the_content', 'to_html', 1);
             break;
         case self::ACTION_VIEW_RESETPASS:
             /**
              * Reset password action.
              * This action is accessed via the password-reset email
              * @see  class-ms-controller-dialog.php
              *
              * The action is targeted to the Account-page but actually calls
              * the Login-Shortcode.
              */
             $view = MS_Factory::create('MS_View_Shortcode_Login');
             $view->data = array('action' => 'resetpass');
             $view->add_filter('the_content', 'to_html', 1);
             break;
         default:
             // Do nothing...
             break;
     }
 }
 /**
  * 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);
 }
 /**
  * Tries to auto-detect the currently displayed membership-ID.
  *
  * Use this function by calling the filter `ms_detect_membership_id`
  *
  * Detection logic:
  * 1. If a valid preferred value was specified then this value is used.
  * 2. Examine REQUEST data and look for membership/subscription/invoice.
  * 3. Check currently logged in user and use the top-priority subscription.
  *
  * @since  1.0.1.0
  * @param  int $preferred The preferred ID is only used if it is a valid ID.
  * @param  bool $no_member_check If set to true the member subscriptions are
  *         not checked, which means only REQUEST data is examined.
  * @param  bool $ignore_system If set to true, then the return value will
  *         never be a system-membership-ID (no auto-assigned membership).
  * @return int A valid Membership ID or 0 if all tests fail.
  */
 public function autodetect_membership($preferred = 0, $no_member_check = false, $ignore_system = false)
 {
     $membership_id = 0;
     // Check 1: If the preferred value is correct use it.
     if ($preferred) {
         $membership = MS_Factory::load('MS_Model_Membership', $preferred);
         // Only use the membership_id if it's valid and not filtered by ignore_system.
         if ($membership->is_valid() && $membership->id == $preferred) {
             if (!$ignore_system || !$membership->is_system()) {
                 $membership_id = $membership->id;
             }
         }
     }
     // Check 2: Examine the REQUEST parameters to find a valid ID.
     if (!$membership_id) {
         if (!$membership_id) {
             if (isset($_REQUEST['membership_id'])) {
                 $membership_id = $_REQUEST['membership_id'];
             } elseif (isset($_REQUEST['subscription_id'])) {
                 $sub_id = $_REQUEST['subscription_id'];
                 $subscription = MS_Factory::load('MS_Model_Relationship', $sub_id);
                 $membership_id = $subscription->membership_id;
             } elseif (isset($_REQUEST['ms_relationship_id'])) {
                 $sub_id = $_REQUEST['ms_relationship_id'];
                 $subscription = MS_Factory::load('MS_Model_Relationship', $sub_id);
                 $membership_id = $subscription->membership_id;
             } elseif (isset($_REQUEST['invoice_id'])) {
                 $inv_id = $_REQUEST['invoice_id'];
                 $invoice = MS_Factory::load('MS_Model_Invoice', $inv_id);
                 $membership_id = $invoice->membership_id;
             }
             $membership_id = intval($membership_id);
         }
         // Reset the membership_id if it's invalid or filtered by ignore_system.
         if ($membership_id) {
             $membership = MS_Factory::load('MS_Model_Membership', $membership_id);
             if (!$membership->is_valid()) {
                 $membership_id = 0;
             } elseif ($membership->id != $membership_id) {
                 $membership_id = 0;
             } elseif ($ignore_system && $membership->is_system) {
                 $membership_id = 0;
             }
         }
     }
     // Check 3: Check subscriptions of the current user.
     if (!$no_member_check && !$membership_id && is_user_logged_in()) {
         $member = MS_Model_Member::get_current_member();
         $subscription = $member->get_subscription('priority');
         if ($subscription) {
             $membership_id = $subscription->membership_id;
         }
         // Reset the membership_id if it's invalid or filtered by ignore_system.
         if ($membership_id) {
             $membership = MS_Factory::load('MS_Model_Membership', $membership_id);
             if (!$membership->is_valid()) {
                 $membership_id = 0;
             } elseif ($membership->id != $membership_id) {
                 $membership_id = 0;
             } elseif ($ignore_system && $membership->is_system) {
                 $membership_id = 0;
             }
         }
     }
     return apply_filters('ms_controller_membership_autodetect_membership', $membership_id, $preferred, $no_member_check);
 }
    public function to_html()
    {
        $fields = $this->prepare_fields();
        $subscription = $this->data['ms_relationship'];
        $invoice = $subscription->get_current_invoice();
        $member = MS_Model_Member::get_current_member();
        $gateway = $this->data['gateway'];
        // Stripe is using Ajax, so the URL is empty.
        $action_url = apply_filters('ms_gateway_stripe_view_button_form_action_url', '');
        $row_class = 'gateway_' . $gateway->id;
        if (!$gateway->is_live_mode()) {
            $row_class .= ' sandbox-mode';
        }
        ob_start();
        ?>
		<form action="<?php 
        echo esc_url($action_url);
        ?>
" method="post">
			<?php 
        foreach ($fields as $field) {
            MS_Helper_Html::html_element($field);
        }
        ?>
			<script
				src="https://checkout.stripe.com/checkout.js" class="stripe-button"
				data-key="<?php 
        echo esc_attr($gateway->get_publishable_key());
        ?>
"
				data-amount="<?php 
        echo esc_attr(ceil(abs($invoice->total * 100)));
        //amount in cents
        ?>
"
				data-name="<?php 
        echo esc_attr(bloginfo('name'));
        ?>
"
				data-description="<?php 
        echo esc_attr(strip_tags($invoice->short_description));
        ?>
"
				data-currency="<?php 
        echo esc_attr($invoice->currency);
        ?>
"
				data-panel-label="<?php 
        echo esc_attr($gateway->pay_button_url);
        ?>
"
				data-label="<?php 
        echo esc_attr($gateway->pay_button_url);
        ?>
"
				data-email="<?php 
        echo esc_attr($member->email);
        ?>
"
				>
			</script>
		</form>
		<?php 
        $payment_form = apply_filters('ms_gateway_form', ob_get_clean(), $gateway, $invoice, $this);
        ob_start();
        ?>
		<tr class="<?php 
        echo esc_attr($row_class);
        ?>
">
			<td class="ms-buy-now-column" colspan="2">
				<?php 
        echo $payment_form;
        ?>
			</td>
		</tr>
		<?php 
        $html = ob_get_clean();
        $html = apply_filters('ms_gateway_button-' . $gateway->id, $html, $this);
        return $html;
    }
 /**
  * Save coupon application.
  *
  * Saving the application to keep track of the application in gateway return.
  * Using COUPON_REDEMPTION_TIME to expire coupon application.
  *
  * This is a non-static function, as it saves the current object!
  *
  * @since  1.0.0
  * @param MS_Model_Relationship $subscription The subscription to apply the coupon.
  */
 public function save_application($subscription)
 {
     // Don't save empty invitations.
     if (empty($this->code)) {
         return false;
     }
     $membership = $subscription->get_membership();
     $discount = $this->get_discount_value($subscription);
     $time = apply_filters('ms_addon_coupon_model_save_application_redemption_time', self::COUPON_REDEMPTION_TIME);
     // Grab the user account as we should be logged in by now.
     $user = MS_Model_Member::get_current_member();
     $key = self::get_transient_name($user->id, $membership->id);
     $transient = apply_filters('ms_addon_coupon_model_transient_value', array('id' => $this->id, 'user_id' => $user->id, 'membership_id' => $membership->id, 'discount' => $discount, 'message' => $this->coupon_message));
     MS_Factory::set_transient($key, $transient, $time);
     $this->save();
     do_action('ms_addon_coupon_model_save_application', $subscription, $this);
 }
 /**
  * Retrieves either the current user ID (if logged in)
  * or the user IP (if not logged in)
  *
  * @since  1.0.0
  */
 public function get_invitation_user_id()
 {
     $user = MS_Model_Member::get_current_member();
     $user_id = $user->id;
     if (!$user->is_member) {
         $user_id = lib3()->net->current_ip()->ip;
     }
     return $user_id;
 }