public function process_shortcode($args = array(), $content = '')
 {
     global $current_user, $appointments;
     extract(wp_parse_args($args, $this->_defaults_to_args()));
     // Force service
     if ($service) {
         // Check if such a service exists
         if (!$appointments->get_service($service)) {
             return;
         }
         $_REQUEST["app_service_id"] = $service;
     }
     $appointments->get_lsw();
     // This should come after Force service
     // Force worker or pick up the single worker
     if ($worker) {
         // Check if such a worker exists
         if (!appointments_is_worker($worker)) {
             return;
         }
         $_REQUEST["app_provider_id"] = $worker;
     } else {
         if ($single_worker = $appointments->is_single_worker($appointments->service)) {
             // Select the only provider if that is the case
             $_REQUEST["app_provider_id"] = $single_worker;
             $worker = $single_worker;
         }
     }
     // Force a date
     if ($date && !isset($_GET["wcalendar"])) {
         $time = $appointments->first_of_month(strtotime($date, $appointments->local_time), $add);
         $_GET["wcalendar"] = $time;
     } else {
         if (!empty($_GET['wcalendar_human'])) {
             $_GET['wcalendar'] = strtotime($_GET['wcalendar_human']);
         }
         if (isset($_GET["wcalendar"]) && (int) $_GET['wcalendar']) {
             $time = $appointments->first_of_month((int) $_GET["wcalendar"], $add);
         } else {
             $time = $appointments->first_of_month($appointments->local_time, $add);
         }
     }
     $year = date("Y", $time);
     $month = date("m", $time);
     if (!empty($title)) {
         $replacements = array(date_i18n("F Y", strtotime("{$year}-{$month}-01")), $appointments->get_worker_name(!empty($_REQUEST['app_provider_id']) ? $_REQUEST['app_provider_id'] : null), $appointments->get_service_name(!empty($_REQUEST['app_service_id']) ? $_REQUEST['app_service_id'] : null));
         $title = str_replace(array("START", "WORKER", "SERVICE"), $replacements, $title);
     } else {
         $title = '';
     }
     $has_worker = !empty($appointments->worker) || !empty($worker);
     $c = '';
     $c .= '<div class="appointments-wrapper">';
     if (!$has_worker && !empty($require_provider)) {
         $c .= !empty($required_message) ? $required_message : __('Please, select a service provider.', 'appointments');
     } else {
         $c .= apply_filters('app-shortcodes-monthly_schedule-title', $title, $args);
         if (is_user_logged_in() || 'yes' != $appointments->options["login_required"]) {
             $c .= $logged ? "<div class='appointments-instructions'>{$logged}</div>" : '';
         } else {
             $codec = new App_Macro_GeneralCodec();
             if (!@$appointments->options["accept_api_logins"]) {
                 //$c .= str_replace( 'LOGIN_PAGE', '<a class="appointments-login_show_login" href="'.site_url( 'wp-login.php').'">'. __('Login','appointments'). '</a>', $notlogged );
                 $c .= $codec->expand($notlogged, App_Macro_GeneralCodec::FILTER_BODY);
             } else {
                 $c .= '<div class="appointments-login">';
                 //$c .= str_replace( 'LOGIN_PAGE', '<a class="appointments-login_show_login" href="javascript:void(0)">'. __('Login','appointments'). '</a>', $notlogged );
                 $c .= $codec->expand($notlogged, App_Macro_GeneralCodec::FILTER_BODY);
                 $c .= '<div class="appointments-login_inner">';
                 $c .= '</div>';
                 $c .= '</div>';
             }
         }
         $c .= '<div class="appointments-list">';
         $c .= $appointments->get_monthly_calendar($time, $class, $long, $widget);
         $c .= '</div>';
     }
     $c .= '</div>';
     // .appointments-wrapper
     $script = '';
     $appointments->add2footer($script);
     return $c;
 }
    public function process_shortcode($args = array(), $content = '')
    {
        extract(wp_parse_args($args, $this->_defaults_to_args()));
        global $wpdb, $current_user, $bp, $appointments;
        $statuses = explode(',', $status);
        if (!is_array($statuses) || empty($statuses)) {
            return '';
        }
        if (!trim($order_by)) {
            $order_by = 'ID';
        }
        $stat = '';
        foreach ($statuses as $s) {
            // Allow only defined stats
            if (array_key_exists(trim($s), App_Template::get_status_names())) {
                $stat .= " status='" . trim($s) . "' OR ";
            }
        }
        $stat = rtrim($stat, "OR ");
        // If this is a client shortcode
        if (!$provider) {
            if (isset($_COOKIE["wpmudev_appointments"])) {
                $apps = unserialize(stripslashes($_COOKIE["wpmudev_appointments"]));
            } else {
                $apps = array();
            }
            if (!is_array($apps)) {
                return '';
            }
            $provider_or_client = __('Provider', 'appointments');
            $q = '';
            if ($strict) {
                // Strict matching
                if (is_user_logged_in()) {
                    $q = "user={$current_user->ID}";
                    // If the user is logged in, show just those apps
                } else {
                    // Otherwise, deal with the cookie-cached ones
                    $apps = array_values(array_filter(array_map('intval', $apps)));
                    if (!empty($apps)) {
                        $q = "ID IN(" . join(',', $apps) . ")";
                    }
                }
            } else {
                // Non-strict matching
                foreach ($apps as $app_id) {
                    if (is_numeric($app_id)) {
                        $q .= " ID=" . $app_id . " OR ";
                    }
                }
                $q = rtrim($q, "OR ");
                // But he may as well has appointments added manually (requires being registered user)
                if (is_user_logged_in()) {
                    $q .= " OR user="******" OR");
                }
            }
            if ($q && $stat) {
                $results = $wpdb->get_results("SELECT * FROM " . $appointments->app_table . " WHERE (" . $q . ") AND (" . $stat . ") ORDER BY " . $appointments->sanitize_order_by($order_by));
            } else {
                $results = false;
            }
        } else {
            $provider_or_client = __('Client', 'appointments');
            // If no id is given, get current user
            if (!$provider_id) {
                $provider_id = $current_user->ID;
            }
            // Special case: If this is a single provider website, show staff appointments in his schedule too
            $workers = $appointments->get_workers();
            if (App_Roles::current_user_can('manage_options', App_Roles::CTX_STAFF) && ($workers && count($workers) == 1 || !$workers)) {
                $provider_id .= ' OR worker=0';
            }
            $results = $wpdb->get_results("SELECT * FROM " . $appointments->app_table . " WHERE (worker=" . $provider_id . ") AND (" . $stat . ") ORDER BY " . $order_by . " ");
        }
        // Can worker confirm pending appointments?
        if ($_allow_confirm && appointments_is_worker($current_user->ID) && isset($appointments->options['allow_worker_confirm']) && 'yes' == $appointments->options['allow_worker_confirm']) {
            $allow_confirm = true;
        } else {
            $allow_confirm = false;
        }
        // Can client cancel appointments?
        if ($allow_cancel && !$provider && isset($appointments->options['allow_cancel']) && 'yes' == $appointments->options['allow_cancel']) {
            $a_cancel = true;
        } else {
            $a_cancel = false;
        }
        $ret = '';
        $ret .= '<div class="appointments-my-appointments">';
        // Make this a form for BP if confirmation is allowed, but not on admin side user profile page
        if ($this->_can_display_editable($allow_confirm)) {
            $ret .= '<form method="post">';
        }
        $ret .= $title;
        $ret = apply_filters('app_my_appointments_before_table', $ret);
        $ret .= '<table class="my-appointments tablesorter"><thead>';
        $ret .= apply_filters('app_my_appointments_column_name', '<th class="my-appointments-service">' . __('Service', 'appointments') . '</th><th class="my-appointments-worker">' . $provider_or_client . '</th><th class="my-appointments-date">' . __('Date/time', 'appointments') . '</th><th class="my-appointments-status">' . __('Status', 'appointments') . '</th>');
        $colspan = 4;
        if ($allow_confirm) {
            $ret .= '<th class="my-appointments-confirm">' . __('Confirm', 'appointments') . '</th>';
            $colspan++;
        }
        if ($a_cancel) {
            $ret .= '<th class="my-appointments-cancel">' . _x('Cancel', 'Discard existing info', 'appointments') . '</th>';
            $colspan++;
        }
        if ($gcal && 'yes' == $appointments->options['gcal']) {
            $ret .= '<th class="my-appointments-gcal">&nbsp;</th>';
            $colspan++;
        }
        $ret .= '</thead><tbody>';
        if ($results) {
            foreach ($results as $r) {
                $ret .= '<tr><td>';
                $ret .= $appointments->get_service_name($r->service) . '</td>';
                $ret .= apply_filters('app-shortcode-my_appointments-after_service', '', $r);
                $ret .= '<td>';
                if (!$provider) {
                    $ret .= $appointments->get_worker_name($r->worker) . '</td>';
                } else {
                    $ret .= $appointments->get_client_name($r->ID) . '</td>';
                }
                $ret .= apply_filters('app-shortcode-my_appointments-after_worker', '', $r);
                $ret .= '<td>';
                $ret .= date_i18n($appointments->datetime_format, strtotime($r->start)) . '</td>';
                $ret .= apply_filters('app-shortcode-my_appointments-after_date', '', $r);
                $ret .= '<td>';
                $ret .= App_Template::get_status_name($r->status);
                $ret .= '</td>';
                $ret .= apply_filters('app-shortcode-my_appointments-after_status', '', $r);
                // If allowed so, a worker can confirm an appointment himself
                if ($allow_confirm) {
                    if ('pending' == $r->status) {
                        $is_readonly = '';
                    } else {
                        $is_readonly = ' readonly="readonly"';
                    }
                    $ret .= '<td><input class="app-my-appointments-confirm" type="checkbox" name="app_confirm[' . $r->ID . ']" ' . $is_readonly . ' /></td>';
                }
                // If allowed so, a client can cancel an appointment
                if ($a_cancel) {
                    // We don't want completed appointments to be cancelled
                    $stat = $r->status;
                    $in_allowed_stat = apply_filters('app_cancel_allowed_status', 'pending' == $stat || 'confirmed' == $stat || 'paid' == $stat, $stat, $r->ID);
                    if ($in_allowed_stat) {
                        $is_readonly = '';
                    } else {
                        $is_readonly = ' readonly="readonly"';
                    }
                    $ret .= '<td><input class="app-my-appointments-cancel" type="checkbox" name="app_cancel[' . $r->ID . ']" ' . $is_readonly . ' /></td>';
                }
                if ($gcal && 'yes' == $appointments->options['gcal']) {
                    if (isset($appointments->options["gcal_same_window"]) && $appointments->options["gcal_same_window"]) {
                        $target = '_self';
                    } else {
                        $target = '_blank';
                    }
                    $ret .= '<td><a title="' . __('Click to submit this appointment to your Google Calendar account', 'appointments') . '" href="' . $appointments->gcal($r->service, strtotime($r->start, $appointments->local_time), strtotime($r->end, $appointments->local_time), true, $r->address, $r->city) . '" target="' . $target . '">' . $appointments->gcal_image . '</a></td>';
                }
                $ret .= apply_filters('app_my_appointments_add_cell', '', $r);
                $ret .= '</tr>';
            }
        } else {
            $ret .= '<tr><td colspan="' . $colspan . '">' . __('No appointments', 'appointments') . '</td></tr>';
        }
        $ret .= '</tbody></table>';
        $ret = apply_filters('app_my_appointments_after_table', $ret, $results);
        if ($this->_can_display_editable($allow_confirm)) {
            $ret .= '<div class="submit">' . '<input type="submit" name="app_bp_settings_submit" value="' . esc_attr(__('Submit Confirm', 'appointments')) . '" class="auto">' . '<input type="hidden" name="app_bp_settings_user" value="' . esc_attr($bp->displayed_user->id) . '">' . wp_nonce_field('app_bp_settings_submit', 'app_bp_settings_submit', true, false) . '</div>';
            $ret .= '</form>';
        }
        $ret .= '</div>';
        $sorter = 'usLongDate';
        $dateformat = 'us';
        // Search for formats where day is at the beginning
        if (stripos(str_replace(array('/', '-'), '', $appointments->date_format), 'dmY') !== false) {
            $sorter = 'shortDate';
            $dateformat = 'uk';
        }
        // Sort table from front end
        if ($_tablesorter && file_exists($appointments->plugin_dir . '/js/jquery.tablesorter.min.js')) {
            $appointments->add2footer('
				$(".my-appointments").tablesorter({
					dateFormat: "' . $dateformat . '",
					headers: {
						2: {
							sorter:"' . $sorter . '"
						}
					}
				});
				$("th.my-appointments-gcal,th.my-appointments-confirm,th.my-appointments-cancel").removeClass("header");

				$(".app-my-appointments-cancel").change( function() {
					if ( $(this).is(":checked") ) {
						var cancel_box = $(this);
						if ( !confirm("' . esc_js(__("Are you sure you want to cancel the selected appointment?", "appointments")) . '") ) {
							cancel_box.attr("checked", false);
							return false;
						}
						else{
							var cancel_id = $(this).attr("name").replace("app_cancel[","").replace("]","");
							if (cancel_id) {
								var cancel_data = {action: "cancel_app", app_id: cancel_id, cancel_nonce: "' . wp_create_nonce() . '"};
								$.post(_appointments_data.ajax_url, cancel_data, function(response) {
									if (response && response.error ) {
										cancel_box.attr("disabled",true);
										alert(response.error);
									}
									else if (response && response.success) {
										alert("' . esc_js(__("Selected appointment cancelled.", "appointments")) . '");
										cancel_box.closest("tr").css("opacity","0.3");
										cancel_box.attr("disabled",true);
									}
									else {
										cancel_box.attr("disabled",true);
										alert("' . esc_js(__("A connection error occurred.", "appointments")) . '");
									}
								}, "json");
							}
						}
					}

				});');
        }
        return $ret;
    }
    /**
     * Displays appointment schedule on the user profile
     */
    function show_profile($profileuser)
    {
        global $current_user, $appointments;
        // Only user or admin can see his data
        if ($current_user->ID != $profileuser->ID && !App_Roles::current_user_can('list_users', CTX_STAFF)) {
            return;
        }
        // For other than user himself, display data as readonly
        if ($current_user->ID != $profileuser->ID) {
            $is_readonly = ' readonly="readonly"';
        } else {
            $is_readonly = '';
        }
        $is_readonly = apply_filters('app_show_profile_readonly', $is_readonly, $profileuser);
        if (isset($appointments->options["gcal"]) && 'yes' == $appointments->options["gcal"]) {
            $gcal = '';
        } else {
            $gcal = ' gcal="0"';
        }
        ?>
		<h3><?php 
        _e("Appointments+", 'appointments');
        ?>
</h3>

		<table class="form-table">
			<tr>
				<th><label><?php 
        _e("My Name", 'appointments');
        ?>
</label></th>
				<td>
					<input type="text" style="width:25em" name="app_name" value="<?php 
        echo get_user_meta($profileuser->ID, 'app_name', true);
        ?>
" <?php 
        echo $is_readonly;
        ?>
 />
				</td>
			</tr>

			<tr>
				<th><label><?php 
        _e("My email for A+", 'appointments');
        ?>
</label></th>
				<td>
					<input type="text" style="width:25em" name="app_email" value="<?php 
        echo get_user_meta($profileuser->ID, 'app_email', true);
        ?>
" <?php 
        echo $is_readonly;
        ?>
 />
				</td>
			</tr>

			<tr>
				<th><label><?php 
        _e("My Phone", 'appointments');
        ?>
</label></th>
				<td>
					<input type="text" style="width:25em" name="app_phone" value="<?php 
        echo get_user_meta($profileuser->ID, 'app_phone', true);
        ?>
"<?php 
        echo $is_readonly;
        ?>
 />
				</td>
			</tr>

			<tr>
				<th><label><?php 
        _e("My Address", 'appointments');
        ?>
</label></th>
				<td>
					<input type="text" style="width:50em" name="app_address" value="<?php 
        echo get_user_meta($profileuser->ID, 'app_address', true);
        ?>
" <?php 
        echo $is_readonly;
        ?>
 />
				</td>
			</tr>

			<tr>
				<th><label><?php 
        _e("My City", 'appointments');
        ?>
</label></th>
				<td>
					<input type="text" style="width:25em" name="app_city" value="<?php 
        echo get_user_meta($profileuser->ID, 'app_city', true);
        ?>
" <?php 
        echo $is_readonly;
        ?>
 />
				</td>
			</tr>

			<?php 
        if (!appointments_is_worker($profileuser->ID)) {
            ?>
				<tr>
					<th><label><?php 
            _e("My Appointments", 'appointments');
            ?>
</label></th>
					<td>
						<?php 
            echo do_shortcode("[app_my_appointments allow_cancel=1 client_id=" . $profileuser->ID . " " . $gcal . "]");
            ?>
					</td>
				</tr>
			<?php 
            if (isset($appointments->options['allow_cancel']) && 'yes' == $appointments->options['allow_cancel']) {
                ?>
				<script type='text/javascript'>
					jQuery(document).ready(function($){
						$('#your-profile').submit(function() {
							if ( $('.app-my-appointments-cancel').is(':checked') ) {
								if ( !confirm('<?php 
                echo esc_js(__("Are you sure to cancel the selected appointment(s)?", "appointments"));
                ?>
') )
								{return false;}
							}
						});
					});
				</script>
			<?php 
            }
        } else {
            ?>
				<tr>
					<th><label><?php 
            _e("My Appointments as Provider", 'appointments');
            ?>
</label></th>
					<td>
						<?php 
            echo do_shortcode("[app_my_appointments status='pending,confirmed,paid' _allow_confirm=1 provider_id=" . $profileuser->ID . "  provider=1 " . $gcal . "]");
            ?>
					</td>
				</tr>
			<?php 
            if (isset($appointments->options['allow_worker_confirm']) && 'yes' == $appointments->options['allow_worker_confirm']) {
                ?>
				<script type='text/javascript'>
					jQuery(document).ready(function($){
						$('#your-profile').submit(function() {
							if ( $('.app-my-appointments-confirm').is(':checked') ) {
								if ( !confirm('<?php 
                echo esc_js(__("Are you sure to confirm the selected appointment(s)?", "appointments"));
                ?>
') )
								{return false;}
							}
						});
					});
				</script>
			<?php 
            }
            if (isset($appointments->options["allow_worker_wh"]) && 'yes' == $appointments->options["allow_worker_wh"]) {
                ?>
			<?php 
                // A little trick to pass correct lsw variables to the related function
                $_REQUEST["app_location_id"] = 0;
                $_REQUEST["app_provider_id"] = $profileuser->ID;
                $appointments->get_lsw();
                $result = array();
                $result_open = $appointments->get_exception($appointments->location, $appointments->worker, 'open');
                if ($result_open) {
                    $result["open"] = $result_open->days;
                } else {
                    $result["open"] = null;
                }
                $result_closed = $appointments->get_exception($appointments->location, $appointments->worker, 'closed');
                if ($result_closed) {
                    $result["closed"] = $result_closed->days;
                } else {
                    $result["closed"] = null;
                }
                ?>
				<tr>
					<th><label><?php 
                _e("My Working Hours", 'appointments');
                ?>
</label></th>
					<td>
						<?php 
                echo $appointments->working_hour_form('open');
                ?>
					</td>
				</tr>
				<tr>
					<th><label><?php 
                _e("My Break Hours", 'appointments');
                ?>
</label></th>
					<td>
						<?php 
                echo $appointments->working_hour_form('closed');
                ?>
					</td>
				</tr>
				<tr>
					<th><label><?php 
                _e("My Exceptional Working Days", 'appointments');
                ?>
</label></th>
					<td>
						<input class="datepick" id="open_datepick" type="text" style="width:100%" name="open[exceptional_days]" value="<?php 
                if (isset($result["open"])) {
                    echo $result["open"];
                }
                ?>
" />
					</td>
				</tr>
				<tr>
					<th><label><?php 
                _e("My Holidays", 'appointments');
                ?>
</label></th>
					<td>
						<input class="datepick" id="closed_datepick" type="text" style="width:100%" name="closed[exceptional_days]" value="<?php 
                if (isset($result["closed"])) {
                    echo $result["closed"];
                }
                ?>
" />
					</td>
				</tr>
				<script type="text/javascript">
					jQuery(document).ready(function($){
						$("#open_datepick").datepick({dateFormat: 'yyyy-mm-dd',multiSelect: 999, monthsToShow: 2});
						$("#closed_datepick").datepick({dateFormat: 'yyyy-mm-dd',multiSelect: 999, monthsToShow: 2});
					});
				</script>
			<?php 
            }
            ?>
			<?php 
        }
        ?>
			<?php 
        if (isset($appointments->options["gcal_api_allow_worker"]) && 'yes' == $appointments->options["gcal_api_allow_worker"] && appointments_is_worker($profileuser->ID)) {
            ?>
				<tr>
					<th><label><?php 
            _e("Appointments+ Google Calendar API", 'appointments');
            ?>
</label></th>
					<td>
					</td>
				</tr>
				<tr>
					<td colspan="2">
						<?php 
            if (is_object($appointments->gcal_api)) {
                $appointments->gcal_api->display_nag($profileuser->ID);
            }
            ?>
					</td>
				</tr>
				<?php 
            if (is_object($appointments->gcal_api)) {
                $appointments->gcal_api->display_settings($profileuser->ID);
            }
        }
        ?>
		</table>
		<?php 
    }
 /**
  * Add text inside a custom user column
  * @since V1.2.7.1
  */
 function users_custom_column($text, $column_name, $user_id)
 {
     // Nothing to do if providers are not allowed to set GCal API
     if ('yes' != @$this->options['gcal_api_allow_worker'] || 'gcal_mode' != $column_name) {
         return $text;
     }
     global $appointments;
     if (!appointments_is_worker($user_id)) {
         return ' - ';
     }
     $mode = $this->get_api_mode($user_id);
     switch ($mode) {
         case 'none':
             return __('None', 'appointments');
             break;
         case 'gcal2app':
             return __('A+<-GCal', 'appointments');
             break;
         case 'app2gcal':
             return __('A+->GCal', 'appointments');
             break;
         case 'sync':
             return __('A+<->GCal', 'appointments');
             break;
         default:
             return ' - ';
             break;
     }
 }
 /**
  * Find worker name given his ID
  * @return string
  */
 function get_worker_name($worker = 0, $php = true)
 {
     global $current_user;
     $user_name = '';
     if (0 == $worker) {
         // Show different text to authorized people
         if (is_admin() || App_Roles::current_user_can('manage_options', App_Roles::CTX_STAFF) || appointments_is_worker($current_user->ID)) {
             $user_name = __('Our staff', 'my-plugin');
         } else {
             $user_name = __('A specialist', 'my-plugin');
         }
     } else {
         $userdata = get_userdata($worker);
         if (is_object($userdata) && !empty($userdata->app_name)) {
             $user_name = $userdata->app_name;
         }
         if (empty($user_name)) {
             if (!$php) {
                 $user_name = $userdata->user_login;
             } else {
                 $user_name = $userdata->display_name;
             }
             if (!$user_name) {
                 $first_name = get_user_meta($worker, 'first_name', true);
                 $last_name = get_user_meta($worker, 'last_name', true);
                 $user_name = $first_name . " " . $last_name;
             }
             if ("" == trim($user_name)) {
                 $user_name = $userdata->user_login;
             }
         }
     }
     return apply_filters('app_get_worker_name', $user_name, $worker);
 }