%PDF- %PDF-
Direktori : /var/www/html/itworks/wp-content/plugins/paid-memberships-pro/adminpages/reports/ |
Current File : //var/www/html/itworks/wp-content/plugins/paid-memberships-pro/adminpages/reports/memberships.php |
<?php /* PMPro Report Title: Membership Stats Slug: memberships For each report, add a line like: global $pmpro_reports; $pmpro_reports['slug'] = 'Title'; For each report, also write two functions: * pmpro_report_{slug}_widget() to show up on the report homepage. * pmpro_report_{slug}_page() to show up when users click on the report page widget. */ global $pmpro_reports; $pmpro_reports['memberships'] = __('Membership Stats', 'paid-memberships-pro' ); //queue Google Visualization JS on report page function pmpro_report_memberships_init() { if(is_admin() && isset($_REQUEST['report']) && $_REQUEST['report'] == "memberships" && isset($_REQUEST['page']) && $_REQUEST['page'] == "pmpro-reports") { wp_enqueue_script( 'corechart', plugins_url( 'js/corechart.js', plugin_dir_path( __DIR__ ) ) ); } } add_action( 'init', 'pmpro_report_memberships_init' ); //widget function pmpro_report_memberships_widget() { global $wpdb; //get levels to show stats on first 3 $pmpro_levels = pmpro_getAllLevels(true, true); $pmpro_level_order = pmpro_getOption('level_order'); if(!empty($pmpro_level_order)) { $order = explode(',',$pmpro_level_order); //reorder array $reordered_levels = array(); foreach($order as $level_id) { foreach($pmpro_levels as $key=>$level) { if($level_id == $level->id) $reordered_levels[$key] = $pmpro_levels[$key]; } } $pmpro_levels = $reordered_levels; } $pmpro_levels = apply_filters( 'pmpro_report_levels', $pmpro_levels ); ?> <span id="pmpro_report_memberships" class="pmpro_report-holder"> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th scope="col"> </th> <th scope="col"><?php _e('Signups', 'paid-memberships-pro' ); ?></th> <th scope="col"><?php _e('All Cancellations', 'paid-memberships-pro' ); ?></th> </tr> </thead> <?php $reports = array( 'today'=> __('Today', 'paid-memberships-pro' ), 'this month'=> __('This Month', 'paid-memberships-pro' ), 'this year'=> __('This Year', 'paid-memberships-pro' ), 'all time'=> __('All Time', 'paid-memberships-pro' ), ); foreach( $reports as $report_type => $report_name ) { $signups = number_format_i18n( pmpro_getSignups( $report_type ) ); $cancellations = number_format_i18n( pmpro_getCancellations( $report_type) ); ?> <tbody> <tr class="pmpro_report_tr"> <th scope="row"> <?php if ( empty( $signups ) && empty( $cancellations) ) { ?> <?php echo $report_name; ?> <?php } else { ?> <button class="pmpro_report_th pmpro_report_th_closed"> <?php echo $report_name; ?> </button> <?php } ?> </th> <td><?php echo $signups; ?></td> <td><?php echo $cancellations; ?></td> </tr> <?php //level stats $count = 0; $max_level_count = apply_filters( 'pmpro_admin_reports_included_levels', 3 ); foreach($pmpro_levels as $level) { if($count++ >= $max_level_count) break; ?> <tr class="pmpro_report_tr_sub" style="display: none;"> <th scope="row">- <?php echo $level->name;?></th> <td><?php echo number_format_i18n(pmpro_getSignups($report_type, $level->id)); ?></td> <td><?php echo number_format_i18n(pmpro_getCancellations($report_type, $level->id)); ?></td> </tr> <?php } ?> </tbody> <?php } ?> </table> <?php if ( function_exists( 'pmpro_report_memberships_page' ) ) { ?> <p class="pmpro_report-button"> <a class="button button-primary" href="<?php echo admin_url( 'admin.php?page=pmpro-reports&report=memberships' ); ?>"><?php _e('Details', 'paid-memberships-pro' );?></a> </p> <?php } ?> </span> <script> jQuery(document).ready(function() { jQuery('.pmpro_report_th ').click(function(event) { //prevent form submit onclick event.preventDefault(); //toggle sub rows jQuery(this).closest('tbody').find('.pmpro_report_tr_sub').toggle(); //change arrow if(jQuery(this).hasClass('pmpro_report_th_closed')) { jQuery(this).removeClass('pmpro_report_th_closed'); jQuery(this).addClass('pmpro_report_th_opened'); } else { jQuery(this).removeClass('pmpro_report_th_opened'); jQuery(this).addClass('pmpro_report_th_closed'); } }); }); </script> <?php } function pmpro_report_memberships_page() { global $wpdb, $pmpro_currency_symbol; //get values from form if(isset($_REQUEST['type'])) $type = sanitize_text_field($_REQUEST['type']); else $type = "signup_v_all"; if(isset($_REQUEST['period'])) $period = sanitize_text_field($_REQUEST['period']); else $period = "monthly"; if(isset($_REQUEST['month'])) $month = intval($_REQUEST['month']); else $month = date_i18n("n"); $thisyear = date_i18n("Y"); if(isset($_REQUEST['year'])) $year = intval($_REQUEST['year']); else $year = date_i18n("Y"); if(isset($_REQUEST['level'])) { if( $_REQUEST['level'] == 'paid-levels' ) { $l = pmpro_report_get_levels( 'paid' ); }elseif( $_REQUEST['level'] == 'free-levels' ) { $l = pmpro_report_get_levels( 'free' ); }else{ $l = intval($_REQUEST['level']); } } else { $l = ""; } if ( isset( $_REQUEST[ 'discount_code' ] ) ) { $discount_code = intval( $_REQUEST[ 'discount_code' ] ); } else { $discount_code = ''; } //calculate start date and how to group dates returned from DB if($period == "daily") { $startdate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-01'; $enddate = $year . '-' . substr("0" . $month, strlen($month) - 1, 2) . '-32'; $date_function = 'DAY'; } elseif($period == "monthly") { $startdate = $year . '-01-01'; $enddate = strval(intval($year)+1) . '-01-01'; $date_function = 'MONTH'; } elseif($period == "annual") { $startdate = '1960-01-01'; //all time $enddate = strval(intval($year)+1) . '-01-01'; $date_function = 'YEAR'; } //testing or live data $gateway_environment = pmpro_getOption("gateway_environment"); //get data if ( $type === "signup_v_cancel" || $type === "signup_v_expiration" || $type === "signup_v_all" ) { $sqlQuery = "SELECT $date_function(mu.startdate) as date, COUNT(DISTINCT mu.user_id) as signups FROM $wpdb->pmpro_memberships_users mu "; if ( ! empty( $discount_code ) ) { $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON mu.user_id = dc.user_id "; } $sqlQuery .= "WHERE mu.startdate >= '" . esc_sql( $startdate ) . "' "; if ( ! empty( $enddate ) ) { $sqlQuery .= "AND mu.startdate < '" . esc_sql( $enddate ) . "' "; } } if ( ! empty( $l ) ) { $sqlQuery .= "AND mu.membership_id IN(" . esc_sql( $l ) . ") "; } if ( ! empty( $discount_code ) ) { $sqlQuery .= "AND dc.code_id = '" . esc_sql( $discount_code ) . "' "; } $sqlQuery .= " GROUP BY date ORDER BY date "; $dates = $wpdb->get_results($sqlQuery); //fill in blanks in dates $cols = array(); if($period == "daily") { $lastday = date_i18n("t", strtotime($startdate, current_time("timestamp"))); for($i = 1; $i <= $lastday; $i++) { // Signups vs. Cancellations, Expirations, or All if ( $type === "signup_v_cancel" || $type === "signup_v_expiration" || $type === "signup_v_all" ) { $cols[$i] = new stdClass(); $cols[$i]->signups = 0; foreach($dates as $day => $date) { if( $date->date == $i ) { $cols[$i]->signups = $date->signups; } } } } } elseif($period == "monthly") { for($i = 1; $i < 13; $i++) { // Signups vs. Cancellations, Expirations, or All if ( $type === "signup_v_cancel" || $type === "signup_v_expiration" || $type === "signup_v_all" ) { $cols[$i] = new stdClass(); $cols[$i]->date = $i; $cols[$i]->signups = 0; foreach($dates as $date) { if( $date->date == $i ) { $cols[$i]->date = $date->date; $cols[$i]->signups = $date->signups; } } } } } elseif($period == "annual") //annual { } $dates = ( ! empty( $cols ) ) ? $cols : $dates; // Signups vs. all if ( $type === "signup_v_cancel" || $type === "signup_v_expiration" || $type === "signup_v_all" ) { $sqlQuery = "SELECT $date_function(mu1.modified) as date, COUNT(DISTINCT mu1.user_id) as cancellations FROM $wpdb->pmpro_memberships_users mu1 "; //restrict by discount code if ( ! empty( $discount_code ) ) { $sqlQuery .= "LEFT JOIN $wpdb->pmpro_discount_codes_uses dc ON mu1.user_id = dc.user_id "; } if ( $type === "signup_v_cancel") $sqlQuery .= "WHERE mu1.status IN('inactive','cancelled','admin_cancelled') "; elseif($type === "signup_v_expiration") $sqlQuery .= "WHERE mu1.status IN('expired') "; else $sqlQuery .= "WHERE mu1.status IN('inactive','expired','cancelled','admin_cancelled') "; $sqlQuery .= "AND mu1.startdate >= '" . esc_sql( $startdate ) . "' AND mu1.startdate < '" . esc_sql( $enddate ) . "' "; //restrict by level if ( ! empty( $l ) ) { $sqlQuery .= "AND mu1.membership_id IN(" . esc_sql( $l ) . ") "; } if ( ! empty( $discount_code ) ) { $sqlQuery .= "AND dc.code_id = '" . esc_sql( $discount_code ) . "' "; } $sqlQuery .= " GROUP BY date ORDER BY date "; /** * Filter query to get cancellation numbers in signups vs cancellations detailed report. * * @since 1.8.8 * * @param string $sqlQuery The current SQL * @param string $type report type * @param string $startdate Start Date in YYYY-MM-DD format * @param string $enddate End Date in YYYY-MM-DD format * @param int $l Level ID */ $sqlQuery = apply_filters('pmpro_reports_signups_sql', $sqlQuery, $type, $startdate, $enddate, $l); $cdates = $wpdb->get_results($sqlQuery, OBJECT_K); foreach( $dates as $day => &$date ) { if(!empty($cdates) && !empty($cdates[$day])) $date->cancellations = $cdates[$day]->cancellations; else $date->cancellations = 0; } } ?> <form id="posts-filter" method="get" action=""> <h1> <?php _e('Membership Stats', 'paid-memberships-pro' );?> </h1> <ul class="subsubsub"> <li> <?php _e('Show', 'paid-memberships-pro' )?> <select id="period" name="period"> <option value="daily" <?php selected($period, "daily");?>><?php _e('Daily', 'paid-memberships-pro' );?></option> <option value="monthly" <?php selected($period, "monthly");?>><?php _e('Monthly', 'paid-memberships-pro' );?></option> <option value="annual" <?php selected($period, "annual");?>><?php _e('Annual', 'paid-memberships-pro' );?></option> </select> <select id="type" name="type"> <option value="signup_v_all" <?php selected($type, "signup_v_all");?>><?php _e('Signups vs. All Cancellations', 'paid-memberships-pro' );?></option> <option value="signup_v_cancel" <?php selected($type, "signup_v_cancel");?>><?php _e('Signups vs. Cancellations', 'paid-memberships-pro' );?></option> <option value="signup_v_expiration" <?php selected($type, "signup_v_expiration");?>><?php _e('Signups vs. Expirations', 'paid-memberships-pro' );?></option> </select> <span id="for"><?php _e('for', 'paid-memberships-pro' )?></span> <select id="month" name="month"> <?php for($i = 1; $i < 13; $i++) { ?> <option value="<?php echo $i;?>" <?php selected($month, $i);?>><?php echo date_i18n("F", mktime(0, 0, 0, $i, 2));?></option> <?php } ?> </select> <select id="year" name="year"> <?php for($i = $thisyear; $i > 2007; $i--) { ?> <option value="<?php echo $i;?>" <?php selected($year, $i);?>><?php echo $i;?></option> <?php } ?> </select> <span id="for"><?php _e('for', 'paid-memberships-pro' )?></span> <select name="level"> <option value="" <?php if(!$l) { ?>selected="selected"<?php } ?>><?php _e('All Levels', 'paid-memberships-pro' );?></option> <option value="paid-levels" <?php if(isset($_REQUEST['level']) && $_REQUEST['level'] == "paid-levels"){?> selected="selected" <?php }?>><?php _e( 'All Paid Levels', 'paid-memberships-pro' ); ?></option> <option value="free-levels" <?php if(isset($_REQUEST['level']) && $_REQUEST['level'] == "free-levels"){?> selected="selected" <?php }?>><?php _e( 'All Free Levels', 'paid-memberships-pro' ); ?></option> <?php $levels = $wpdb->get_results("SELECT id, name FROM $wpdb->pmpro_membership_levels ORDER BY name"); foreach($levels as $level) { ?> <option value="<?php echo $level->id?>" <?php if($l == $level->id) { ?>selected="selected"<?php } ?>><?php echo $level->name?></option> <?php } ?> </select> <?php $sqlQuery = "SELECT SQL_CALC_FOUND_ROWS * FROM $wpdb->pmpro_discount_codes "; $sqlQuery .= "ORDER BY id DESC "; $codes = $wpdb->get_results($sqlQuery, OBJECT); if ( ! empty( $codes ) ) { ?> <select id="discount_code" name="discount_code"> <option value="" <?php if ( empty( $discount_code ) ) { ?>selected="selected"<?php } ?>><?php _e('All Codes', 'paid-memberships-pro' );?></option> <?php foreach ( $codes as $code ) { ?> <option value="<?php echo $code->id; ?>" <?php selected( $discount_code, $code->id ); ?>><?php echo $code->code; ?></option> <?php } ?> </select> <?php } ?> <input type="hidden" name="page" value="pmpro-reports" /> <input type="hidden" name="report" value="memberships" /> <input type="submit" class="button" value="<?php _e('Generate Report', 'paid-memberships-pro' );?>" /> </li> </ul> <div id="chart_div" style="clear: both; width: 100%; height: 500px;"></div> <script> //update month/year when period dropdown is changed jQuery(document).ready(function() { jQuery('#period').change(function() { pmpro_ShowMonthOrYear(); }); }); function pmpro_ShowMonthOrYear() { var period = jQuery('#period').val(); if(period == 'daily') { jQuery('#for').show(); jQuery('#month').show(); jQuery('#year').show(); } else if(period == 'monthly') { jQuery('#for').show(); jQuery('#month').hide(); jQuery('#year').show(); } else { jQuery('#for').hide(); jQuery('#month').hide(); jQuery('#year').hide(); } } pmpro_ShowMonthOrYear(); //draw the chart google.charts.load('current', {'packages':['corechart']}); google.charts.setOnLoadCallback(drawVisualization); function drawVisualization() { var data = google.visualization.arrayToDataTable([ <?php if ( $type === "signup_v_all" ) : // Signups vs. all cancellations ?> ['<?php echo $date_function;?>', 'Signups', 'All Cancellations'], <?php foreach($dates as $key => $value) { ?> ['<?php if($period == "monthly") echo date_i18n("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo $value->signups; ?>, <?php echo $value->cancellations; ?>], <?php } ?> <?php endif; ?> <?php if ( $type === "signup_v_cancel" ) : // Signups vs. cancellations ?> ['<?php echo $date_function;?>', 'Signups', 'Cancellations'], <?php foreach($dates as $key => $value) { ?> ['<?php if($period == "monthly") echo date_i18n("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo $value->signups; ?>, <?php echo $value->cancellations; ?>], <?php } ?> <?php endif; ?> <?php if ( $type === "signup_v_expiration" ) : // Signups vs. expirations ?> ['<?php echo $date_function;?>', 'Signups', 'Expirations'], <?php foreach($dates as $key => $value) { ?> ['<?php if($period == "monthly") echo date_i18n("M", mktime(0,0,0,$value->date,2)); else if($period == "daily") echo $key; else echo $value->date;?>', <?php echo $value->signups; ?>, <?php echo $value->cancellations; ?>], <?php } ?> <?php endif; ?> ]); var options = { colors: ['#0099c6', '#dc3912'], chartArea: {width: '90%'}, legend: { alignment: 'center', position: 'top', textStyle: {color: '#555555', fontSize: '12', italic: false} }, hAxis: { title: '<?php echo $date_function;?>', textStyle: {color: '#555555', fontSize: '12', italic: false}, titleTextStyle: {color: '#555555', fontSize: '20', bold: true, italic: false}, maxAlternation: 1 }, vAxis: { format: '0', textStyle: {color: '#555555', fontSize: '12', italic: false}, }, seriesType: 'bars', }; <?php if ( $type === "signup_v_cancel" || $type === "signup_v_expiration" || $type === "signup_v_all" ) : // Signups vs. cancellations ?> var chart = new google.visualization.ColumnChart(document.getElementById('chart_div')); <?php endif; ?> chart.draw(data, options); } </script> </form> <?php } /* Other code required for your reports. This file is loaded every time WP loads with PMPro enabled. */ //get signups function pmpro_getSignups($period = false, $levels = 'all') { //check for a transient $cache = get_transient( 'pmpro_report_memberships_signups' ); if( ! empty( $cache ) && ! empty( $cache[$period] ) && ! empty( $cache[$period][$levels] ) ) return $cache[$period][$levels]; //a sale is an order with status = success if( $period == 'today' ) $startdate = date_i18n(' Y-m-d' ); elseif( $period == 'this month') $startdate = date_i18n( 'Y-m' ) . '-01'; elseif( $period == 'this year') $startdate = date_i18n( 'Y' ) . '-01-01'; else $startdate = ''; //build query global $wpdb; $sqlQuery = "SELECT COUNT(DISTINCT mu.user_id) FROM $wpdb->pmpro_memberships_users mu WHERE mu.startdate >= '" . esc_sql( $startdate ) . "' "; //restrict by level if(!empty($levels) && $levels != 'all') $sqlQuery .= "AND mu.membership_id IN(" . esc_sql( $levels ) . ") "; $signups = $wpdb->get_var($sqlQuery); //save in cache if(!empty($cache) && !empty($cache[$period])) $cache[$period][$levels] = $signups; elseif(!empty($cache)) $cache[$period] = array($levels => $signups); else $cache = array($period => array($levels => $signups)); set_transient("pmpro_report_memberships_signups", $cache, 3600*24); return $signups; } // /** * get cancellations by status * * @param string $period - Either a string description ('today', 'this month', 'this year') * @param array(int)|string $levels - Either an array of level IDs or the string 'all' * @param array(string) $status - Array of statuses to fetch data for * @return null|int - The # of cancellations for the period specified */ function pmpro_getCancellations($period = null, $levels = 'all', $status = array('inactive','expired','cancelled','admin_cancelled') ) { //make sure status is an array if(!is_array($status)) $status = array($status); //check for a transient $cache = get_transient( 'pmpro_report_memberships_cancellations' ); $hash = md5($period . $levels . implode(',', $status)); if( ! empty( $cache ) && ! empty( $cache[$hash] ) ) return $cache[$hash]; //figure out start date $now = current_time('timestamp'); $year = date("Y", $now); if( $period == 'today' ) { $startdate = date('Y-m-d', $now) . " 00:00:00"; $enddate = "'" . date('Y-m-d', $now) . " 23:59:59'"; } elseif( $period == 'this month') { $startdate = date( 'Y-m', $now ) . '-01 00:00:00'; $enddate = "CONCAT(LAST_DAY('" . date_i18n( 'Y-m', $now ) . '-01' ."'), ' 23:59:59')"; } elseif( $period == 'this year') { $startdate = date( 'Y', $now ) . '-01-01 00:00:00'; $enddate = "'" . date( 'Y', $now ) . "-12-31 23:59:59'"; } else { //all time $startdate = '1970-01-01'; //all time (no point in using a value prior to the start of the UNIX epoch) $enddate = "'".strval(intval($year)+1) . "-01-01'"; } /* build query. cancellations are marked in the memberships users table with status 'inactive', 'expired', 'cancelled', 'admin_cancelled' we try to ignore cancellations when the user gets a new level with 24 hours (probably an upgrade or downgrade) */ global $wpdb; // Note here that we no longer esc_sql the $startdate and $enddate // Escaping broke the MYSQL we passed in. // We generated these vars and can trust them. $sqlQuery = " SELECT COUNT( DISTINCT mu1.user_id ) FROM {$wpdb->pmpro_memberships_users} AS mu1 WHERE mu1.status IN('" . implode( "','", array_map( 'esc_sql', $status ) ) . "') AND mu1.enddate >= '" . $startdate . "' AND mu1.enddate <= " . $enddate . " "; //restrict by level if(!empty($levels) && $levels != 'all') { // the levels provided wasn't in array form if ( ! is_array($levels) ) { $levels = array($levels); } $sqlQuery .= "AND mu1.membership_id IN(" . implode( ',', array_map( 'esc_sql', $levels ) ) . ") "; } /** * Filter query to get cancellation numbers in signups vs cancellations detailed report. * * @since 1.8.8 * * @param string $sqlQuery The current SQL * @param string $period Period for report. today, this month, this year, empty string for all time. * @param array(int) $levels Level IDs to include in report. * @param array(string) $status Statuses to include as cancelled. */ $sqlQuery = apply_filters('pmpro_reports_get_cancellations_sql', $sqlQuery, $period, $levels, $status); $cancellations = $wpdb->get_var($sqlQuery); //save in cache if(!empty($cache) && !empty($cache[$hash])) $cache[$hash] = $cancellations; elseif(!empty($cache)) $cache[$hash] = $cancellations; else $cache = array($hash => $cancellations); set_transient("pmpro_report_memberships_cancellations", $cache, 3600*24); return $cancellations; } //get Cancellation Rate function pmpro_getCancellationRate($period, $levels = 'all', $status = NULL) { //make sure status is an array if(!is_array($status)) $status = array($status); //check for a transient $cache = get_transient("pmpro_report_cancellation_rate"); $hash = md5($period . $levels . implode('',$status)); if(!empty($cache) && !empty($cache[$hash])) return $cache[$hash]; $signups = pmpro_getSignups($period, $levels); $cancellations = pmpro_getCancellations($period, $levels, $status); if(empty($signups)) return false; $rate = number_format(($cancellations / $signups)*100, 2); //save in cache if(!empty($cache) && !empty($cache[$period])) $cache[$period][$levels] = $rate; elseif(!empty($cache)) $cache[$period] = array($levels => $rate); else $cache = array($period => array($levels => $rate)); set_transient("pmpro_report_cancellation_rate", $cache, 3600*24); return $rate; } //delete transients when an order goes through function pmpro_report_memberships_delete_transients() { delete_transient("pmpro_report_cancellation_rate"); delete_transient("pmpro_report_memberships_cancellations"); delete_transient("pmpro_report_memberships_signups"); } add_action("pmpro_after_checkout", "pmpro_report_memberships_delete_transients"); add_action("pmpro_updated_order", "pmpro_report_memberships_delete_transients"); /** * Creates an array of membership level ID's for querying. * @param $type string type of membership level you want to retrieve "free" or "paid". * @since 2.0 */ function pmpro_report_get_levels( $type = NULL ) { if ( empty( $type ) ) { return; } $level_data = pmpro_getAllLevels( true, true ); $r = array(); foreach( $level_data as $key => $value ) { if ( $type === 'free' && pmpro_isLevelFree( $value ) ) { $r[] = intval( $value->id); } elseif( $type === 'paid' && !pmpro_isLevelFree( $value ) ) { $r[] = intval( $value->id ); } } // implode it before returning it. $r = implode( ',', $r ); return $r; }