Admin changes for #5046
- Removed post type classes. Since they were always loaded, there was no benefit having them split up. Combined meaning less hooked in methods. - Stopped loading some function files and sessions in the admin area. They are not needed there. - Made a few admin page classes static as they are stateless
This commit is contained in:
parent
7c5c113b61
commit
ded4b7404d
|
@ -10,8 +10,6 @@
|
|||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_Addons' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_Addons Class
|
||||
*/
|
||||
|
@ -20,7 +18,7 @@ class WC_Admin_Addons {
|
|||
/**
|
||||
* Handles output of the reports page in admin.
|
||||
*/
|
||||
public function output() {
|
||||
public static function output() {
|
||||
|
||||
if ( false === ( $addons = get_transient( 'woocommerce_addons_data' ) ) ) {
|
||||
$addons_json = wp_remote_get( 'http://d3t0oesq8995hv.cloudfront.net/woocommerce-addons.json', array( 'user-agent' => 'WooCommerce Addons Page' ) );
|
||||
|
@ -37,7 +35,3 @@ class WC_Admin_Addons {
|
|||
include_once( 'views/html-admin-page-addons.php' );
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
return new WC_Admin_Addons();
|
|
@ -12,8 +12,6 @@
|
|||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_Attributes' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_Attributes Class
|
||||
*/
|
||||
|
@ -25,7 +23,7 @@ class WC_Admin_Attributes {
|
|||
* Shows the created attributes and lets you add new ones or edit existing ones.
|
||||
* The added attributes are stored in the database and can be used for layered navigation.
|
||||
*/
|
||||
public function output() {
|
||||
public static function output() {
|
||||
global $wpdb, $woocommerce;
|
||||
|
||||
// Action to perform: add, edit, delete or none
|
||||
|
@ -206,9 +204,9 @@ class WC_Admin_Attributes {
|
|||
|
||||
// Show admin interface
|
||||
if ( ! empty( $_GET['edit'] ) )
|
||||
$this->edit_attribute();
|
||||
self::edit_attribute();
|
||||
else
|
||||
$this->add_attribute();
|
||||
self::add_attribute();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -216,7 +214,7 @@ class WC_Admin_Attributes {
|
|||
*
|
||||
* Shows the interface for changing an attributes type between select and text
|
||||
*/
|
||||
public function edit_attribute() {
|
||||
public static function edit_attribute() {
|
||||
global $wpdb;
|
||||
|
||||
$edit = absint( $_GET['edit'] );
|
||||
|
@ -292,7 +290,7 @@ class WC_Admin_Attributes {
|
|||
*
|
||||
* Shows the interface for adding new attributes
|
||||
*/
|
||||
public function add_attribute() {
|
||||
public static function add_attribute() {
|
||||
?>
|
||||
<div class="wrap woocommerce">
|
||||
<div class="icon32 icon32-attributes" id="icon-woocommerce"><br/></div>
|
||||
|
@ -424,7 +422,3 @@ class WC_Admin_Attributes {
|
|||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
return new WC_Admin_Attributes();
|
|
@ -180,8 +180,9 @@ class WC_Admin_Menus {
|
|||
* @return bool
|
||||
*/
|
||||
public function custom_menu_order() {
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) )
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -189,7 +190,6 @@ class WC_Admin_Menus {
|
|||
* Init the reports page
|
||||
*/
|
||||
public function reports_page() {
|
||||
include_once( 'class-wc-admin-reports.php' );
|
||||
WC_Admin_Reports::output();
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,6 @@ class WC_Admin_Menus {
|
|||
* Init the settings page
|
||||
*/
|
||||
public function settings_page() {
|
||||
include_once( 'class-wc-admin-settings.php' );
|
||||
WC_Admin_Settings::output();
|
||||
}
|
||||
|
||||
|
@ -205,24 +204,21 @@ class WC_Admin_Menus {
|
|||
* Init the attributes page
|
||||
*/
|
||||
public function attributes_page() {
|
||||
$page = include( 'class-wc-admin-attributes.php' );
|
||||
$page->output();
|
||||
WC_Admin_Attributes::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the status page
|
||||
*/
|
||||
public function status_page() {
|
||||
$page = include( 'class-wc-admin-status.php' );
|
||||
$page->output();
|
||||
WC_Admin_Status::output();
|
||||
}
|
||||
|
||||
/**
|
||||
* Init the addons page
|
||||
*/
|
||||
public function addons_page() {
|
||||
$page = include( 'class-wc-admin-addons.php' );
|
||||
$page->output();
|
||||
WC_Admin_Addons::output();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -99,8 +99,7 @@ class WC_Admin_Notices {
|
|||
return;
|
||||
}
|
||||
|
||||
$status = include( 'class-wc-admin-status.php' );
|
||||
$core_templates = $status->scan_template_files( WC()->plugin_path() . '/templates' );
|
||||
$core_templates = WC_Admin_Status::scan_template_files( WC()->plugin_path() . '/templates' );
|
||||
$outdated = false;
|
||||
|
||||
foreach ( $core_templates as $file ) {
|
||||
|
|
|
@ -21,8 +21,8 @@ class WC_Admin_Permalink_Settings {
|
|||
* Hook in tabs.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_init', array( $this, 'settings_init' ) );
|
||||
add_action( 'admin_init', array( $this, 'settings_save' ) );
|
||||
$this->settings_init();
|
||||
$this->settings_save();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,8 +10,6 @@
|
|||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_Status' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_Status Class
|
||||
*/
|
||||
|
@ -20,7 +18,7 @@ class WC_Admin_Status {
|
|||
/**
|
||||
* Handles output of the reports page in admin.
|
||||
*/
|
||||
public function output() {
|
||||
public static function output() {
|
||||
$current_tab = ! empty( $_REQUEST['tab'] ) ? sanitize_title( $_REQUEST['tab'] ) : 'status';
|
||||
|
||||
include_once( 'views/html-admin-page-status.php' );
|
||||
|
@ -29,7 +27,7 @@ class WC_Admin_Status {
|
|||
/**
|
||||
* Handles output of report
|
||||
*/
|
||||
public function status_report() {
|
||||
public static function status_report() {
|
||||
global $wpdb;
|
||||
include_once( 'views/html-admin-page-status-report.php' );
|
||||
}
|
||||
|
@ -37,10 +35,10 @@ class WC_Admin_Status {
|
|||
/**
|
||||
* Handles output of tools
|
||||
*/
|
||||
public function status_tools() {
|
||||
public static function status_tools() {
|
||||
global $woocommerce, $wpdb;
|
||||
|
||||
$tools = $this->get_tools();
|
||||
$tools = self::get_tools();
|
||||
|
||||
if ( ! empty( $_GET['action'] ) && ! empty( $_REQUEST['_wpnonce'] ) && wp_verify_nonce( $_REQUEST['_wpnonce'], 'debug_action' ) ) {
|
||||
|
||||
|
@ -168,7 +166,7 @@ class WC_Admin_Status {
|
|||
*
|
||||
* @return array of tools
|
||||
*/
|
||||
public function get_tools() {
|
||||
public static function get_tools() {
|
||||
return apply_filters( 'woocommerce_debug_tools', array(
|
||||
'clear_transients' => array(
|
||||
'name' => __( 'WC Transients','woocommerce'),
|
||||
|
@ -211,8 +209,8 @@ class WC_Admin_Status {
|
|||
/**
|
||||
* Show the logs page
|
||||
*/
|
||||
public function status_logs() {
|
||||
$logs = $this->scan_log_files();
|
||||
public static function status_logs() {
|
||||
$logs = self::scan_log_files();
|
||||
if ( ! empty( $_POST['log_file'] ) && isset( $logs[ sanitize_title( $_POST['log_file'] ) ] ) ) {
|
||||
$viewed_log = $logs[ sanitize_title( $_POST['log_file'] ) ];
|
||||
} elseif ( $logs ) {
|
||||
|
@ -228,7 +226,7 @@ class WC_Admin_Status {
|
|||
* @param string $file Path to the file
|
||||
* @param array $all_headers List of headers, in the format array('HeaderKey' => 'Header Name')
|
||||
*/
|
||||
public function get_file_version( $file ) {
|
||||
public static function get_file_version( $file ) {
|
||||
// We don't need to write to the file, so just open for reading.
|
||||
$fp = fopen( $file, 'r' );
|
||||
|
||||
|
@ -254,14 +252,14 @@ class WC_Admin_Status {
|
|||
* @param string $template_path
|
||||
* @return array
|
||||
*/
|
||||
public function scan_template_files( $template_path ) {
|
||||
public static function scan_template_files( $template_path ) {
|
||||
$files = scandir( $template_path );
|
||||
$result = array();
|
||||
if ( $files ) {
|
||||
foreach ( $files as $key => $value ) {
|
||||
if ( ! in_array( $value, array( ".",".." ) ) ) {
|
||||
if ( is_dir( $template_path . DIRECTORY_SEPARATOR . $value ) ) {
|
||||
$sub_files = $this->scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
|
||||
$sub_files = self::scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
|
||||
foreach ( $sub_files as $sub_file ) {
|
||||
$result[] = $value . DIRECTORY_SEPARATOR . $sub_file;
|
||||
}
|
||||
|
@ -279,7 +277,7 @@ class WC_Admin_Status {
|
|||
*
|
||||
* @return array
|
||||
*/
|
||||
public function scan_log_files() {
|
||||
public static function scan_log_files() {
|
||||
$files = @scandir( WC_LOG_DIR );
|
||||
$result = array();
|
||||
if ( $files ) {
|
||||
|
@ -294,7 +292,3 @@ class WC_Admin_Status {
|
|||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
return new WC_Admin_Status();
|
||||
|
|
|
@ -36,6 +36,9 @@ class WC_Admin_Taxonomies {
|
|||
// Taxonomy page descriptions
|
||||
add_action( 'product_cat_pre_add_form', array( $this, 'product_cat_description' ) );
|
||||
add_action( 'product_shipping_class_pre_add_form', array( $this, 'shipping_class_description' ) );
|
||||
|
||||
// Maintain hierarchy of terms
|
||||
add_filter( 'wp_terms_checklist_args', array( $this, 'disable_checked_ontop' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -328,6 +331,18 @@ class WC_Admin_Taxonomies {
|
|||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maintain term hierarchy when editing a product.
|
||||
* @param array $args
|
||||
* @return array
|
||||
*/
|
||||
public function disable_checked_ontop( $args ) {
|
||||
if ( 'product_cat' == $args['taxonomy'] ) {
|
||||
$args['checked_ontop'] = false;
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
}
|
||||
|
||||
new WC_Admin_Taxonomies();
|
||||
|
|
|
@ -21,7 +21,6 @@ class WC_Admin {
|
|||
add_action( 'init', array( $this, 'includes' ) );
|
||||
add_action( 'current_screen', array( $this, 'conditonal_includes' ) );
|
||||
add_action( 'admin_init', array( $this, 'prevent_admin_access' ) );
|
||||
add_action( 'wp_ajax_page_slurp', array( 'WC_Gateway_Mijireh', 'page_slurp' ) );
|
||||
add_action( 'admin_init', array( $this, 'preview_emails' ) );
|
||||
add_action( 'admin_footer', 'wc_print_js', 25 );
|
||||
}
|
||||
|
@ -38,23 +37,24 @@ class WC_Admin {
|
|||
include_once( 'class-wc-admin-post-types.php' );
|
||||
include_once( 'class-wc-admin-taxonomies.php' );
|
||||
|
||||
// Classes we only need if the ajax is not-ajax
|
||||
// Classes we only need during non-ajax requests
|
||||
if ( ! is_ajax() ) {
|
||||
include( 'class-wc-admin-menus.php' );
|
||||
include( 'class-wc-admin-welcome.php' );
|
||||
include( 'class-wc-admin-notices.php' );
|
||||
include( 'class-wc-admin-assets.php' );
|
||||
include( 'class-wc-admin-permalink-settings.php' );
|
||||
|
||||
// Help
|
||||
if ( apply_filters( 'woocommerce_enable_admin_help_tab', true ) )
|
||||
if ( apply_filters( 'woocommerce_enable_admin_help_tab', true ) ) {
|
||||
include( 'class-wc-admin-help.php' );
|
||||
}
|
||||
}
|
||||
|
||||
// Importers
|
||||
if ( defined( 'WP_LOAD_IMPORTERS' ) )
|
||||
if ( defined( 'WP_LOAD_IMPORTERS' ) ) {
|
||||
include( 'class-wc-admin-importers.php' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include admin files conditionally
|
||||
|
@ -66,6 +66,9 @@ class WC_Admin {
|
|||
case 'dashboard' :
|
||||
include( 'class-wc-admin-dashboard.php' );
|
||||
break;
|
||||
case 'options-permalink' :
|
||||
include( 'class-wc-admin-permalink-settings.php' );
|
||||
break;
|
||||
case 'users' :
|
||||
case 'user' :
|
||||
case 'profile' :
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,232 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin functions for the shop_coupon post type.
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce/Admin/Post Types
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_CPT' ) )
|
||||
include( 'class-wc-admin-cpt.php' );
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_CPT_Shop_Coupon' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_CPT_Shop_Coupon Class
|
||||
*/
|
||||
class WC_Admin_CPT_Shop_Coupon extends WC_Admin_CPT {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->type = 'shop_coupon';
|
||||
|
||||
// Post title fields
|
||||
add_filter( 'enter_title_here', array( $this, 'enter_title_here' ), 1, 2 );
|
||||
add_action( 'edit_form_after_title', array( $this, 'coupon_description_field' ) );
|
||||
|
||||
// Admin Columns
|
||||
add_filter( 'manage_edit-shop_coupon_columns', array( $this, 'edit_columns' ) );
|
||||
add_action( 'manage_shop_coupon_posts_custom_column', array( $this, 'custom_columns' ), 2 );
|
||||
add_filter( 'request', array( $this, 'coupons_by_type_query' ) );
|
||||
|
||||
// Product filtering
|
||||
add_action( 'restrict_manage_posts', array( $this, 'coupon_filters' ) );
|
||||
|
||||
// Call WC_Admin_CPT constructor
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change title boxes in admin.
|
||||
* @param string $text
|
||||
* @param object $post
|
||||
* @return string
|
||||
*/
|
||||
public function enter_title_here( $text, $post ) {
|
||||
if ( $post->post_type == 'shop_coupon' )
|
||||
return __( 'Coupon code', 'woocommerce' );
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print coupon description textarea field
|
||||
* @param WP_Post $post
|
||||
*/
|
||||
public function coupon_description_field( $post ) {
|
||||
if ( $post->post_type != 'shop_coupon' )
|
||||
return;
|
||||
?>
|
||||
<textarea id="woocommerce-coupon-description" name="excerpt" cols="5" rows="2" placeholder="<?php esc_attr_e( 'Description (optional)', 'woocommerce' ); ?>"><?php echo esc_textarea( $post->post_excerpt ); ?></textarea>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the columns shown in admin.
|
||||
*/
|
||||
public function edit_columns( $columns ) {
|
||||
$columns = array();
|
||||
|
||||
$columns["cb"] = "<input type=\"checkbox\" />";
|
||||
$columns["coupon_code"] = __( 'Code', 'woocommerce' );
|
||||
$columns["type"] = __( 'Coupon type', 'woocommerce' );
|
||||
$columns["amount"] = __( 'Coupon amount', 'woocommerce' );
|
||||
$columns["description"] = __( 'Description', 'woocommerce' );
|
||||
$columns["products"] = __( 'Product IDs', 'woocommerce' );
|
||||
$columns["usage"] = __( 'Usage / Limit', 'woocommerce' );
|
||||
$columns["expiry_date"] = __( 'Expiry date', 'woocommerce' );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define our custom columns shown in admin.
|
||||
* @param string $column
|
||||
*/
|
||||
public function custom_columns( $column ) {
|
||||
global $post, $woocommerce;
|
||||
|
||||
switch ( $column ) {
|
||||
case "coupon_code" :
|
||||
$edit_link = get_edit_post_link( $post->ID );
|
||||
$title = _draft_or_post_title();
|
||||
$post_type_object = get_post_type_object( $post->post_type );
|
||||
$can_edit_post = current_user_can( $post_type_object->cap->edit_post, $post->ID );
|
||||
|
||||
echo '<div class="code tips" data-tip="' . __( 'Edit coupon', 'woocommerce' ) . '"><a href="' . esc_attr( $edit_link ) . '"><span>' . esc_html( $title ). '</span></a></div>';
|
||||
|
||||
_post_states( $post );
|
||||
|
||||
// Get actions
|
||||
$actions = array();
|
||||
|
||||
if ( current_user_can( $post_type_object->cap->delete_post, $post->ID ) ) {
|
||||
if ( 'trash' == $post->post_status )
|
||||
$actions['untrash'] = "<a title='" . esc_attr( __( 'Restore this item from the Trash', 'woocommerce' ) ) . "' href='" . wp_nonce_url( admin_url( sprintf( $post_type_object->_edit_link . '&action=untrash', $post->ID ) ), 'untrash-post_' . $post->ID ) . "'>" . __( 'Restore', 'woocommerce' ) . "</a>";
|
||||
elseif ( EMPTY_TRASH_DAYS )
|
||||
$actions['trash'] = "<a class='submitdelete' title='" . esc_attr( __( 'Move this item to the Trash', 'woocommerce' ) ) . "' href='" . get_delete_post_link( $post->ID ) . "'>" . __( 'Trash', 'woocommerce' ) . "</a>";
|
||||
if ( 'trash' == $post->post_status || !EMPTY_TRASH_DAYS )
|
||||
$actions['delete'] = "<a class='submitdelete' title='" . esc_attr( __( 'Delete this item permanently', 'woocommerce' ) ) . "' href='" . get_delete_post_link( $post->ID, '', true ) . "'>" . __( 'Delete Permanently', 'woocommerce' ) . "</a>";
|
||||
}
|
||||
|
||||
$actions = apply_filters( 'post_row_actions', $actions, $post );
|
||||
|
||||
echo '<div class="row-actions">';
|
||||
|
||||
$i = 0;
|
||||
$action_count = sizeof($actions);
|
||||
|
||||
foreach ( $actions as $action => $link ) {
|
||||
++$i;
|
||||
( $i == $action_count ) ? $sep = '' : $sep = ' | ';
|
||||
echo "<span class='$action'>$link$sep</span>";
|
||||
}
|
||||
echo '</div>';
|
||||
|
||||
break;
|
||||
case "type" :
|
||||
echo esc_html( wc_get_coupon_type( get_post_meta( $post->ID, 'discount_type', true ) ) );
|
||||
break;
|
||||
case "amount" :
|
||||
echo esc_html( get_post_meta( $post->ID, 'coupon_amount', true ) );
|
||||
break;
|
||||
case "products" :
|
||||
$product_ids = get_post_meta( $post->ID, 'product_ids', true );
|
||||
$product_ids = $product_ids ? array_map( 'absint', explode( ',', $product_ids ) ) : array();
|
||||
if ( sizeof( $product_ids ) > 0 )
|
||||
echo esc_html( implode( ', ', $product_ids ) );
|
||||
else
|
||||
echo '–';
|
||||
break;
|
||||
case "usage_limit" :
|
||||
$usage_limit = get_post_meta( $post->ID, 'usage_limit', true );
|
||||
|
||||
if ( $usage_limit )
|
||||
echo esc_html( $usage_limit );
|
||||
else
|
||||
echo '–';
|
||||
break;
|
||||
case "usage" :
|
||||
$usage_count = absint( get_post_meta( $post->ID, 'usage_count', true ) );
|
||||
$usage_limit = esc_html( get_post_meta($post->ID, 'usage_limit', true) );
|
||||
|
||||
if ( $usage_limit )
|
||||
printf( __( '%s / %s', 'woocommerce' ), $usage_count, $usage_limit );
|
||||
else
|
||||
printf( __( '%s / ∞', 'woocommerce' ), $usage_count );
|
||||
break;
|
||||
case "expiry_date" :
|
||||
$expiry_date = get_post_meta($post->ID, 'expiry_date', true);
|
||||
|
||||
if ( $expiry_date )
|
||||
echo esc_html( date_i18n( 'F j, Y', strtotime( $expiry_date ) ) );
|
||||
else
|
||||
echo '–';
|
||||
break;
|
||||
case "description" :
|
||||
echo wp_kses_post( $post->post_excerpt );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the coupons by the type.
|
||||
*
|
||||
* @param array $vars
|
||||
* @return array
|
||||
*/
|
||||
public function coupons_by_type_query( $vars ) {
|
||||
global $typenow, $wp_query;
|
||||
if ( $typenow == 'shop_coupon' && ! empty( $_GET['coupon_type'] ) ) {
|
||||
|
||||
$vars['meta_key'] = 'discount_type';
|
||||
$vars['meta_value'] = wc_clean( $_GET['coupon_type'] );
|
||||
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show custom filters to filter coupons by type.
|
||||
*/
|
||||
public function coupon_filters() {
|
||||
global $woocommerce, $typenow, $wp_query;
|
||||
|
||||
if ( $typenow != 'shop_coupon' )
|
||||
return;
|
||||
|
||||
// Type
|
||||
?>
|
||||
<select name='coupon_type' id='dropdown_shop_coupon_type'>
|
||||
<option value=""><?php _e( 'Show all types', 'woocommerce' ); ?></option>
|
||||
<?php
|
||||
$types = wc_get_coupon_types();
|
||||
|
||||
foreach ( $types as $name => $type ) {
|
||||
echo '<option value="' . esc_attr( $name ) . '"';
|
||||
|
||||
if ( isset( $_GET['coupon_type'] ) )
|
||||
selected( $name, $_GET['coupon_type'] );
|
||||
|
||||
echo '>' . esc_html__( $type, 'woocommerce' ) . '</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
|
||||
wc_enqueue_js( "
|
||||
jQuery('select#dropdown_shop_coupon_type, select[name=m]').css('width', '150px').chosen();
|
||||
" );
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
return new WC_Admin_CPT_Shop_Coupon();
|
|
@ -1,724 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin functions for the shop order post type
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce/Admin/Post Types
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
// Exit if accessed directly
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_CPT' ) ) {
|
||||
include( 'class-wc-admin-cpt.php' );
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_CPT_Shop_Order' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_CPT_Shop_Order Class
|
||||
*/
|
||||
class WC_Admin_CPT_Shop_Order extends WC_Admin_CPT {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->type = 'shop_order';
|
||||
|
||||
// Before data updates
|
||||
add_filter( 'wp_insert_post_data', array( $this, 'wp_insert_post_data' ) );
|
||||
|
||||
// Admin Columns
|
||||
add_filter( 'manage_edit-' . $this->type . '_columns', array( $this, 'edit_columns' ) );
|
||||
add_action( 'manage_' . $this->type . '_posts_custom_column', array( $this, 'custom_columns' ), 2 );
|
||||
|
||||
// Views and filtering
|
||||
add_filter( 'views_edit-shop_order', array( $this, 'custom_order_views' ) );
|
||||
add_filter( 'bulk_actions-edit-shop_order', array( $this, 'bulk_actions' ) );
|
||||
add_filter( 'post_row_actions', array( $this, 'remove_row_actions' ), 10, 1 );
|
||||
add_action( 'restrict_manage_posts', array( $this, 'restrict_manage_orders' ) );
|
||||
add_filter( 'request', array( $this, 'orders_by_customer_query' ) );
|
||||
add_filter( "manage_edit-shop_order_sortable_columns", array( $this, 'custom_shop_order_sort' ) );
|
||||
add_filter( 'request', array( $this, 'custom_shop_order_orderby' ) );
|
||||
add_filter( 'get_search_query', array( $this, 'shop_order_search_label' ) );
|
||||
add_filter( 'query_vars', array( $this, 'add_custom_query_var' ) );
|
||||
add_action( 'parse_query', array( $this, 'shop_order_search_custom_fields' ) );
|
||||
add_action( 'before_delete_post', array( $this, 'delete_order_items' ) );
|
||||
|
||||
// Bulk edit
|
||||
add_action( 'admin_footer', array( $this, 'bulk_admin_footer' ), 10 );
|
||||
add_action( 'load-edit.php', array( $this, 'bulk_action' ) );
|
||||
add_action( 'admin_notices', array( $this, 'bulk_admin_notices' ) );
|
||||
|
||||
// Call WC_Admin_CPT constructor
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the order posts to have a title in a certain format (containing the date)
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public function wp_insert_post_data( $data ) {
|
||||
global $post;
|
||||
|
||||
if ( $data['post_type'] == 'shop_order' && isset( $data['post_date'] ) ) {
|
||||
|
||||
$order_title = 'Order';
|
||||
if ( $data['post_date'] ) {
|
||||
$order_title.= ' – ' . date_i18n( 'F j, Y @ h:i A', strtotime( $data['post_date'] ) );
|
||||
}
|
||||
|
||||
$data['post_title'] = $order_title;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the columns shown in admin.
|
||||
*/
|
||||
public function edit_columns( $existing_columns ) {
|
||||
$columns = array();
|
||||
|
||||
$columns['cb'] = '<input type="checkbox" />';
|
||||
$columns['order_status'] = '<span class="status_head tips" data-tip="' . esc_attr__( 'Status', 'woocommerce' ) . '">' . esc_attr__( 'Status', 'woocommerce' ) . '</span>';
|
||||
$columns['order_title'] = __( 'Order', 'woocommerce' );
|
||||
$columns['order_items'] = __( 'Purchased', 'woocommerce' );
|
||||
$columns['shipping_address'] = __( 'Ship to', 'woocommerce' );
|
||||
|
||||
$columns['customer_message'] = '<span class="notes_head tips" data-tip="' . esc_attr__( 'Customer Message', 'woocommerce' ) . '">' . esc_attr__( 'Customer Message', 'woocommerce' ) . '</span>';
|
||||
$columns['order_notes'] = '<span class="order-notes_head tips" data-tip="' . esc_attr__( 'Order Notes', 'woocommerce' ) . '">' . esc_attr__( 'Order Notes', 'woocommerce' ) . '</span>';
|
||||
$columns['order_date'] = __( 'Date', 'woocommerce' );
|
||||
$columns['order_total'] = __( 'Total', 'woocommerce' );
|
||||
$columns['order_actions'] = __( 'Actions', 'woocommerce' );
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Define our custom columns shown in admin.
|
||||
* @param string $column
|
||||
*/
|
||||
public function custom_columns( $column ) {
|
||||
global $post, $woocommerce, $the_order;
|
||||
|
||||
if ( empty( $the_order ) || $the_order->id != $post->ID ) {
|
||||
$the_order = new WC_Order( $post->ID );
|
||||
}
|
||||
|
||||
switch ( $column ) {
|
||||
case 'order_status' :
|
||||
|
||||
printf( '<mark class="%s tips" data-tip="%s">%s</mark>', sanitize_title( $the_order->get_status() ), wc_get_order_status_name( $the_order->get_status() ), wc_get_order_status_name( $the_order->get_status() ) );
|
||||
|
||||
break;
|
||||
case 'order_date' :
|
||||
|
||||
if ( '0000-00-00 00:00:00' == $post->post_date ) {
|
||||
$t_time = $h_time = __( 'Unpublished', 'woocommerce' );
|
||||
} else {
|
||||
$t_time = get_the_time( __( 'Y/m/d g:i:s A', 'woocommerce' ), $post );
|
||||
$gmt_time = strtotime( $post->post_date_gmt . ' UTC' );
|
||||
$time_diff = current_time( 'timestamp', 1 ) - $gmt_time;
|
||||
$h_time = get_the_time( __( 'Y/m/d', 'woocommerce' ), $post );
|
||||
}
|
||||
|
||||
echo '<abbr title="' . esc_attr( $t_time ) . '">' . esc_html( apply_filters( 'post_date_column_time', $h_time, $post ) ) . '</abbr>';
|
||||
|
||||
break;
|
||||
case 'customer_message' :
|
||||
|
||||
if ( $the_order->customer_message )
|
||||
echo '<span class="note-on tips" data-tip="' . esc_attr( $the_order->customer_message ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
|
||||
else
|
||||
echo '<span class="na">–</span>';
|
||||
|
||||
break;
|
||||
case 'billing_address' :
|
||||
if ( $the_order->get_formatted_billing_address() )
|
||||
echo '<a target="_blank" href="' . esc_url( 'http://maps.google.com/maps?&q=' . urlencode( $the_order->get_billing_address() ) . '&z=16' ) . '">' . esc_html( preg_replace( '#<br\s*/?>#i', ', ', $the_order->get_formatted_billing_address() ) ) .'</a>';
|
||||
else
|
||||
echo '–';
|
||||
|
||||
if ( $the_order->payment_method_title )
|
||||
echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->payment_method_title ) . '</small>';
|
||||
break;
|
||||
case 'order_items' :
|
||||
|
||||
printf( '<a href="#" class="show_order_items">' . _n( '%d item', '%d items', sizeof( $the_order->get_items() ), 'woocommerce' ) . '</a>', sizeof( $the_order->get_items() ) );
|
||||
|
||||
if ( sizeof( $the_order->get_items() ) > 0 ) {
|
||||
|
||||
echo '<table class="order_items" cellspacing="0">';
|
||||
|
||||
foreach ( $the_order->get_items() as $item ) {
|
||||
$_product = apply_filters( 'woocommerce_order_item_product', $the_order->get_product_from_item( $item ), $item );
|
||||
$item_meta = new WC_Order_Item_Meta( $item['item_meta'] );
|
||||
$item_meta_html = $item_meta->display( true, true );
|
||||
?>
|
||||
<tr>
|
||||
<td class="qty"><?php echo absint( $item['qty'] ); ?></td>
|
||||
<td class="name">
|
||||
<?php if ( wc_product_sku_enabled() && $_product && $_product->get_sku() ) echo $_product->get_sku() . ' - '; ?><?php echo apply_filters( 'woocommerce_order_item_name', $item['name'], $item ); ?>
|
||||
<?php if ( $item_meta_html ) : ?>
|
||||
<a class="tips" href="#" data-tip="<?php echo esc_attr( $item_meta_html ); ?>">[?]</a>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
|
||||
} else echo '–';
|
||||
break;
|
||||
case 'shipping_address' :
|
||||
if ( $the_order->get_formatted_shipping_address() )
|
||||
echo '<a target="_blank" href="' . esc_url( 'http://maps.google.com/maps?&q=' . urlencode( $the_order->get_shipping_address() ) . '&z=16' ) . '">'. esc_html( preg_replace( '#<br\s*/?>#i', ', ', $the_order->get_formatted_shipping_address() ) ) .'</a>';
|
||||
else
|
||||
echo '–';
|
||||
|
||||
if ( $the_order->get_shipping_method() )
|
||||
echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->get_shipping_method() ) . '</small>';
|
||||
|
||||
break;
|
||||
case 'order_notes' :
|
||||
|
||||
if ( $post->comment_count ) {
|
||||
|
||||
// check the status of the post
|
||||
( $post->post_status !== 'trash' ) ? $status = '' : $status = 'post-trashed';
|
||||
|
||||
$latest_notes = get_comments( array(
|
||||
'post_id' => $post->ID,
|
||||
'number' => 1,
|
||||
'status' => $status
|
||||
) );
|
||||
|
||||
$latest_note = current( $latest_notes );
|
||||
|
||||
if ( $post->comment_count == 1 ) {
|
||||
echo '<span class="note-on tips" data-tip="' . esc_attr( $latest_note->comment_content ) . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
|
||||
} else {
|
||||
$note_tip = isset( $latest_note->comment_content ) ? esc_attr( $latest_note->comment_content . '<small style="display:block">' . sprintf( _n( 'plus %d other note', 'plus %d other notes', ( $post->comment_count - 1 ), 'woocommerce' ), ( $post->comment_count - 1 ) ) . '</small>' ) : sprintf( _n( '%d note', '%d notes', $post->comment_count, 'woocommerce' ), $post->comment_count );
|
||||
|
||||
echo '<span class="note-on tips" data-tip="' . $note_tip . '">' . __( 'Yes', 'woocommerce' ) . '</span>';
|
||||
}
|
||||
|
||||
} else {
|
||||
echo '<span class="na">–</span>';
|
||||
}
|
||||
|
||||
break;
|
||||
case 'order_total' :
|
||||
echo esc_html( strip_tags( $the_order->get_formatted_order_total() ) );
|
||||
|
||||
if ( $the_order->payment_method_title ) {
|
||||
echo '<small class="meta">' . __( 'Via', 'woocommerce' ) . ' ' . esc_html( $the_order->payment_method_title ) . '</small>';
|
||||
}
|
||||
break;
|
||||
case 'order_title' :
|
||||
|
||||
$customer_tip = '';
|
||||
|
||||
if ( $address = $the_order->get_formatted_billing_address() ) {
|
||||
$customer_tip .= __( 'Billing:', 'woocommerce' ) . ' ' . $address . '<br/><br/>';
|
||||
}
|
||||
|
||||
if ( $the_order->billing_phone ) {
|
||||
$customer_tip .= __( 'Tel:', 'woocommerce' ) . ' ' . $the_order->billing_phone;
|
||||
}
|
||||
|
||||
echo '<div class="tips" data-tip="' . esc_attr( $customer_tip ) . '">';
|
||||
|
||||
if ( $the_order->user_id ) {
|
||||
$user_info = get_userdata( $the_order->user_id );
|
||||
}
|
||||
|
||||
if ( ! empty( $user_info ) ) {
|
||||
|
||||
$username = '<a href="user-edit.php?user_id=' . absint( $user_info->ID ) . '">';
|
||||
|
||||
if ( $user_info->first_name || $user_info->last_name ) {
|
||||
$username .= esc_html( ucfirst( $user_info->first_name ) . ' ' . ucfirst( $user_info->last_name ) );
|
||||
} else {
|
||||
$username .= esc_html( ucfirst( $user_info->display_name ) );
|
||||
}
|
||||
|
||||
$username .= '</a>';
|
||||
|
||||
} else {
|
||||
if ( $the_order->billing_first_name || $the_order->billing_last_name ) {
|
||||
$username = trim( $the_order->billing_first_name . ' ' . $the_order->billing_last_name );
|
||||
} else {
|
||||
$username = __( 'Guest', 'woocommerce' );
|
||||
}
|
||||
}
|
||||
|
||||
printf( __( '%s by %s', 'woocommerce' ), '<a href="' . admin_url( 'post.php?post=' . absint( $post->ID ) . '&action=edit' ) . '"><strong>' . esc_attr( $the_order->get_order_number() ) . '</strong></a>', $username );
|
||||
|
||||
if ( $the_order->billing_email ) {
|
||||
echo '<small class="meta email"><a href="' . esc_url( 'mailto:' . $the_order->billing_email ) . '">' . esc_html( $the_order->billing_email ) . '</a></small>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
break;
|
||||
case 'order_actions' :
|
||||
|
||||
?><p>
|
||||
<?php
|
||||
do_action( 'woocommerce_admin_order_actions_start', $the_order );
|
||||
|
||||
$actions = array();
|
||||
|
||||
if ( $the_order->has_status( array( 'pending', 'on-hold' ) ) ) {
|
||||
$actions['processing'] = array(
|
||||
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_processing&order_id=' . $post->ID ), 'woocommerce-mark-order-processing' ),
|
||||
'name' => __( 'Processing', 'woocommerce' ),
|
||||
'action' => "processing"
|
||||
);
|
||||
}
|
||||
|
||||
if ( $the_order->has_status( array( 'pending', 'on-hold', 'processing' ) ) ) {
|
||||
$actions['complete'] = array(
|
||||
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_mark_order_complete&order_id=' . $post->ID ), 'woocommerce-mark-order-complete' ),
|
||||
'name' => __( 'Complete', 'woocommerce' ),
|
||||
'action' => "complete"
|
||||
);
|
||||
}
|
||||
|
||||
$actions['view'] = array(
|
||||
'url' => admin_url( 'post.php?post=' . $post->ID . '&action=edit' ),
|
||||
'name' => __( 'View', 'woocommerce' ),
|
||||
'action' => "view"
|
||||
);
|
||||
|
||||
$actions = apply_filters( 'woocommerce_admin_order_actions', $actions, $the_order );
|
||||
|
||||
foreach ( $actions as $action ) {
|
||||
printf( '<a class="button tips %s" href="%s" data-tip="%s">%s</a>', esc_attr( $action['action'] ), esc_url( $action['url'] ), esc_attr( $action['name'] ), esc_attr( $action['name'] ) );
|
||||
}
|
||||
|
||||
do_action( 'woocommerce_admin_order_actions_end', $the_order );
|
||||
?>
|
||||
</p><?php
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters for the order page.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $views
|
||||
* @return array
|
||||
*/
|
||||
public function custom_order_views( $views ) {
|
||||
|
||||
unset( $views['publish'] );
|
||||
|
||||
if ( isset( $views['trash'] ) ) {
|
||||
$trash = $views['trash'];
|
||||
unset( $views['draft'] );
|
||||
unset( $views['trash'] );
|
||||
$views['trash'] = $trash;
|
||||
}
|
||||
|
||||
return $views;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove edit from the bulk actions.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $actions
|
||||
* @return array
|
||||
*/
|
||||
public function bulk_actions( $actions ) {
|
||||
|
||||
if ( isset( $actions['edit'] ) ) {
|
||||
unset( $actions['edit'] );
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Actions for the orders page.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $actions
|
||||
* @return array
|
||||
*/
|
||||
public function remove_row_actions( $actions ) {
|
||||
if ( 'shop_order' === get_post_type() ) {
|
||||
unset( $actions['view'] );
|
||||
unset( $actions['inline hide-if-no-js'] );
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show custom filters to filter orders by status/customer.
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function restrict_manage_orders() {
|
||||
global $woocommerce, $typenow, $wp_query;
|
||||
|
||||
if ( 'shop_order' != $typenow ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Customers
|
||||
?>
|
||||
<select id="dropdown_customers" name="_customer_user">
|
||||
<option value=""><?php _e( 'Show all customers', 'woocommerce' ) ?></option>
|
||||
<?php
|
||||
if ( ! empty( $_GET['_customer_user'] ) ) {
|
||||
$user = get_user_by( 'id', absint( $_GET['_customer_user'] ) );
|
||||
echo '<option value="' . absint( $user->ID ) . '" ';
|
||||
selected( 1, 1 );
|
||||
echo '>' . esc_html( $user->display_name ) . ' (#' . absint( $user->ID ) . ' – ' . esc_html( $user->user_email ) . ')</option>';
|
||||
}
|
||||
?>
|
||||
</select>
|
||||
<?php
|
||||
|
||||
wc_enqueue_js( "
|
||||
jQuery('select#dropdown_customers').css('width', '250px').ajaxChosen({
|
||||
method: 'GET',
|
||||
url: '" . admin_url( 'admin-ajax.php' ) . "',
|
||||
dataType: 'json',
|
||||
afterTypeDelay: 100,
|
||||
minTermLength: 1,
|
||||
data: {
|
||||
action: 'woocommerce_json_search_customers',
|
||||
security: '" . wp_create_nonce( 'search-customers' ) . "',
|
||||
default: '" . __( 'Show all customers', 'woocommerce' ) . "'
|
||||
}
|
||||
}, function (data) {
|
||||
|
||||
var terms = {};
|
||||
|
||||
$.each(data, function (i, val) {
|
||||
terms[i] = val;
|
||||
});
|
||||
|
||||
return terms;
|
||||
});
|
||||
" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the orders by the posted customer.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $vars
|
||||
* @return array
|
||||
*/
|
||||
public function orders_by_customer_query( $vars ) {
|
||||
global $typenow, $wp_query;
|
||||
|
||||
if ( $typenow == 'shop_order' && isset( $_GET['_customer_user'] ) && $_GET['_customer_user'] > 0 ) {
|
||||
$vars['meta_key'] = '_customer_user';
|
||||
$vars['meta_value'] = (int) $_GET['_customer_user'];
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make order columns sortable.
|
||||
*
|
||||
* https://gist.github.com/906872
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $columns
|
||||
* @return array
|
||||
*/
|
||||
public function custom_shop_order_sort( $columns ) {
|
||||
$custom = array(
|
||||
'order_title' => 'ID',
|
||||
'order_total' => 'order_total',
|
||||
'order_date' => 'date'
|
||||
);
|
||||
unset( $columns['comments'] );
|
||||
|
||||
return wp_parse_args( $custom, $columns );
|
||||
}
|
||||
|
||||
/**
|
||||
* Order column orderby/request.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $vars
|
||||
* @return array
|
||||
*/
|
||||
public function custom_shop_order_orderby( $vars ) {
|
||||
global $typenow, $wp_query;
|
||||
|
||||
if ( 'shop_order' != $typenow ) {
|
||||
return $vars;
|
||||
}
|
||||
|
||||
// Sorting
|
||||
if ( isset( $vars['orderby'] ) ) {
|
||||
if ( 'order_total' == $vars['orderby'] ) {
|
||||
$vars = array_merge( $vars, array(
|
||||
'meta_key' => '_order_total',
|
||||
'orderby' => 'meta_value_num'
|
||||
) );
|
||||
}
|
||||
}
|
||||
|
||||
return $vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search custom fields as well as content.
|
||||
*
|
||||
* @access public
|
||||
* @param WP_Query $wp
|
||||
* @return void
|
||||
*/
|
||||
public function shop_order_search_custom_fields( $wp ) {
|
||||
global $pagenow, $wpdb;
|
||||
|
||||
if ( 'edit.php' != $pagenow || empty( $wp->query_vars['s'] ) || $wp->query_vars['post_type'] != 'shop_order' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$search_fields = array_map( 'wc_clean', apply_filters( 'woocommerce_shop_order_search_fields', array(
|
||||
'_order_key',
|
||||
'_billing_company',
|
||||
'_billing_address_1',
|
||||
'_billing_address_2',
|
||||
'_billing_city',
|
||||
'_billing_postcode',
|
||||
'_billing_country',
|
||||
'_billing_state',
|
||||
'_billing_email',
|
||||
'_billing_phone',
|
||||
'_shipping_address_1',
|
||||
'_shipping_address_2',
|
||||
'_shipping_city',
|
||||
'_shipping_postcode',
|
||||
'_shipping_country',
|
||||
'_shipping_state'
|
||||
) ) );
|
||||
|
||||
$search_order_id = str_replace( 'Order #', '', $_GET['s'] );
|
||||
if ( ! is_numeric( $search_order_id ) ) {
|
||||
$search_order_id = 0;
|
||||
}
|
||||
|
||||
// Search orders
|
||||
$post_ids = array_unique( array_merge(
|
||||
$wpdb->get_col(
|
||||
$wpdb->prepare( "
|
||||
SELECT p1.post_id
|
||||
FROM {$wpdb->postmeta} p1
|
||||
INNER JOIN {$wpdb->postmeta} p2 ON p1.post_id = p2.post_id
|
||||
WHERE
|
||||
( p1.meta_key = '_billing_first_name' AND p2.meta_key = '_billing_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
|
||||
OR
|
||||
( p1.meta_key = '_shipping_first_name' AND p2.meta_key = '_shipping_last_name' AND CONCAT(p1.meta_value, ' ', p2.meta_value) LIKE '%%%s%%' )
|
||||
OR
|
||||
( p1.meta_key IN ('" . implode( "','", $search_fields ) . "') AND p1.meta_value LIKE '%%%s%%' )
|
||||
",
|
||||
esc_attr( $_GET['s'] ), esc_attr( $_GET['s'] ), esc_attr( $_GET['s'] )
|
||||
)
|
||||
),
|
||||
$wpdb->get_col(
|
||||
$wpdb->prepare( "
|
||||
SELECT order_id
|
||||
FROM {$wpdb->prefix}woocommerce_order_items as order_items
|
||||
WHERE order_item_name LIKE '%%%s%%'
|
||||
",
|
||||
esc_attr( $_GET['s'] )
|
||||
)
|
||||
),
|
||||
array( $search_order_id )
|
||||
) );
|
||||
|
||||
// Remove s - we don't want to search order name
|
||||
unset( $wp->query_vars['s'] );
|
||||
|
||||
// so we know we're doing this
|
||||
$wp->query_vars['shop_order_search'] = true;
|
||||
|
||||
// Search by found posts
|
||||
$wp->query_vars['post__in'] = $post_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the label when searching orders.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $query
|
||||
* @return string
|
||||
*/
|
||||
public function shop_order_search_label( $query ) {
|
||||
global $pagenow, $typenow;
|
||||
|
||||
if ( 'edit.php' != $pagenow ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
if ( $typenow != 'shop_order' ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
if ( ! get_query_var( 'shop_order_search' ) ) {
|
||||
return $query;
|
||||
}
|
||||
|
||||
return wp_unslash( $_GET['s'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Query vars for custom searches.
|
||||
*
|
||||
* @access public
|
||||
* @param mixed $public_query_vars
|
||||
* @return array
|
||||
*/
|
||||
public function add_custom_query_var( $public_query_vars ) {
|
||||
$public_query_vars[] = 'sku';
|
||||
$public_query_vars[] = 'shop_order_search';
|
||||
|
||||
return $public_query_vars;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item meta on permanent deletion
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
**/
|
||||
public function delete_order_items( $postid ) {
|
||||
global $wpdb;
|
||||
|
||||
if ( get_post_type( $postid ) == 'shop_order' ) {
|
||||
do_action( 'woocommerce_delete_order_items', $postid );
|
||||
|
||||
$wpdb->query( "
|
||||
DELETE {$wpdb->prefix}woocommerce_order_items, {$wpdb->prefix}woocommerce_order_itemmeta
|
||||
FROM {$wpdb->prefix}woocommerce_order_items
|
||||
JOIN {$wpdb->prefix}woocommerce_order_itemmeta ON {$wpdb->prefix}woocommerce_order_items.order_item_id = {$wpdb->prefix}woocommerce_order_itemmeta.order_item_id
|
||||
WHERE {$wpdb->prefix}woocommerce_order_items.order_id = '{$postid}';
|
||||
" );
|
||||
|
||||
do_action( 'woocommerce_deleted_order_items', $postid );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add extra bulk action options to mark orders as complete or processing
|
||||
*
|
||||
* Using Javascript until WordPress core fixes: http://core.trac.wordpress.org/ticket/16031
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function bulk_admin_footer() {
|
||||
global $post_type;
|
||||
|
||||
if ( 'shop_order' == $post_type ) {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
jQuery(function() {
|
||||
jQuery('<option>').val('mark_processing').text('<?php _e( 'Mark processing', 'woocommerce' )?>').appendTo("select[name='action']");
|
||||
jQuery('<option>').val('mark_processing').text('<?php _e( 'Mark processing', 'woocommerce' )?>').appendTo("select[name='action2']");
|
||||
|
||||
jQuery('<option>').val('mark_on-hold').text('<?php _e( 'Mark on-hold', 'woocommerce' )?>').appendTo("select[name='action']");
|
||||
jQuery('<option>').val('mark_on-hold').text('<?php _e( 'Mark on-hold', 'woocommerce' )?>').appendTo("select[name='action2']");
|
||||
|
||||
jQuery('<option>').val('mark_completed').text('<?php _e( 'Mark complete', 'woocommerce' )?>').appendTo("select[name='action']");
|
||||
jQuery('<option>').val('mark_completed').text('<?php _e( 'Mark complete', 'woocommerce' )?>').appendTo("select[name='action2']");
|
||||
});
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the new bulk actions for changing order status
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function bulk_action() {
|
||||
$wp_list_table = _get_list_table( 'WP_Posts_List_Table' );
|
||||
$action = $wp_list_table->current_action();
|
||||
|
||||
switch ( $action ) {
|
||||
case 'mark_completed':
|
||||
$new_status = 'completed';
|
||||
$report_action = 'marked_complete';
|
||||
break;
|
||||
case 'mark_processing':
|
||||
$new_status = 'processing';
|
||||
$report_action = 'marked_processing';
|
||||
break;
|
||||
case 'mark_on-hold' :
|
||||
$new_status = 'on-hold';
|
||||
$report_action = 'marked_on-hold';
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
$changed = 0;
|
||||
|
||||
$post_ids = array_map( 'absint', (array) $_REQUEST['post'] );
|
||||
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$order = new WC_Order( $post_id );
|
||||
$order->update_status( $new_status, __( 'Order status changed by bulk edit:', 'woocommerce' ) );
|
||||
$changed++;
|
||||
}
|
||||
|
||||
$sendback = add_query_arg( array( 'post_type' => 'shop_order', $report_action => true, 'changed' => $changed, 'ids' => join( ',', $post_ids ) ), '' );
|
||||
wp_redirect( $sendback );
|
||||
exit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Show confirmation message that order status changed for number of orders
|
||||
*
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function bulk_admin_notices() {
|
||||
global $post_type, $pagenow;
|
||||
|
||||
if ( isset( $_REQUEST['marked_complete'] ) || isset( $_REQUEST['marked_processing'] ) || isset( $_REQUEST['marked_on-hold'] ) ) {
|
||||
$number = isset( $_REQUEST['changed'] ) ? absint( $_REQUEST['changed'] ) : 0;
|
||||
|
||||
if ( 'edit.php' == $pagenow && 'shop_order' == $post_type ) {
|
||||
$message = sprintf( _n( 'Order status changed.', '%s order statuses changed.', $number, 'woocommerce' ), number_format_i18n( $number ) );
|
||||
echo '<div class="updated"><p>' . $message . '</p></div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
return new WC_Admin_CPT_Shop_Order();
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* Admin functions for post types
|
||||
*
|
||||
* @author WooThemes
|
||||
* @category Admin
|
||||
* @package WooCommerce/Admin/Post Types
|
||||
* @version 2.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
if ( ! class_exists( 'WC_Admin_CPT' ) ) :
|
||||
|
||||
/**
|
||||
* WC_Admin_CPT Class
|
||||
*/
|
||||
class WC_Admin_CPT {
|
||||
|
||||
protected $type = '';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct() {
|
||||
// Insert into X media browser
|
||||
add_filter( 'media_view_strings', array( $this, 'change_insert_into_post' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Change label for insert buttons.
|
||||
* @access public
|
||||
* @param array $strings
|
||||
* @return array
|
||||
*/
|
||||
function change_insert_into_post( $strings ) {
|
||||
global $post_type;
|
||||
|
||||
if ( $post_type == $this->type ) {
|
||||
$obj = get_post_type_object( $this->type );
|
||||
|
||||
$strings['insertIntoPost'] = sprintf( __( 'Insert into %s', 'woocommerce' ), $obj->labels->singular_name );
|
||||
$strings['uploadedToThisPost'] = sprintf( __( 'Uploaded to this %s', 'woocommerce' ), $obj->labels->singular_name );
|
||||
}
|
||||
|
||||
return $strings;
|
||||
}
|
||||
}
|
||||
|
||||
endif;
|
|
@ -452,7 +452,7 @@
|
|||
$found_files = array();
|
||||
|
||||
foreach ( $template_paths as $plugin_name => $template_path ) {
|
||||
$scanned_files[ $plugin_name ] = $this->scan_template_files( $template_path );
|
||||
$scanned_files[ $plugin_name ] = WC_Admin_Status::scan_template_files( $template_path );
|
||||
}
|
||||
|
||||
foreach ( $scanned_files as $plugin_name => $files ) {
|
||||
|
@ -470,8 +470,8 @@
|
|||
}
|
||||
|
||||
if ( $theme_file ) {
|
||||
$core_version = $this->get_file_version( WC()->plugin_path() . '/templates/' . $file );
|
||||
$theme_version = $this->get_file_version( $theme_file );
|
||||
$core_version = WC_Admin_Status::get_file_version( WC()->plugin_path() . '/templates/' . $file );
|
||||
$theme_version = WC_Admin_Status::get_file_version( $theme_file );
|
||||
|
||||
if ( $core_version && ( empty( $theme_version ) || version_compare( $theme_version, $core_version, '<' ) ) ) {
|
||||
$found_files[ $plugin_name ][] = sprintf( __( '<code>%s</code> version <strong style="color:red">%s</strong> is out of date. The core version is %s', 'woocommerce' ), basename( $theme_file ), $theme_version ? $theme_version : '-', $core_version );
|
||||
|
|
|
@ -16,13 +16,13 @@
|
|||
<?php
|
||||
switch ( $current_tab ) {
|
||||
case "tools" :
|
||||
$this->status_tools();
|
||||
WC_Admin_Status::status_tools();
|
||||
break;
|
||||
case "logs" :
|
||||
$this->status_logs();
|
||||
WC_Admin_Status::status_logs();
|
||||
break;
|
||||
default :
|
||||
$this->status_report();
|
||||
WC_Admin_Status::status_report();
|
||||
break;
|
||||
}
|
||||
?>
|
||||
|
|
|
@ -67,6 +67,8 @@ class WC_AJAX {
|
|||
add_action( 'wp_ajax_nopriv_woocommerce_' . $ajax_event, array( __CLASS__, $ajax_event ) );
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'wp_ajax_page_slurp', array( 'WC_Gateway_Mijireh', 'page_slurp' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -653,7 +655,7 @@ class WC_AJAX {
|
|||
$image_id = 0;
|
||||
$variation = get_post( $variation_id ); // Get the variation object
|
||||
|
||||
include( 'admin/post-types/meta-boxes/views/html-variation-admin.php' );
|
||||
include( 'admin/meta-boxes/views/html-variation-admin.php' );
|
||||
}
|
||||
|
||||
die();
|
||||
|
@ -888,7 +890,7 @@ class WC_AJAX {
|
|||
} else {
|
||||
$file_count = sprintf( __( 'File %d', 'woocommerce' ), $file_counter );
|
||||
}
|
||||
include( 'admin/post-types/meta-boxes/views/html-order-download-permission.php' );
|
||||
include( 'admin/meta-boxes/views/html-order-download-permission.php' );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1000,7 +1002,7 @@ class WC_AJAX {
|
|||
|
||||
$item = apply_filters( 'woocommerce_ajax_order_item', $item, $item_id );
|
||||
|
||||
include( 'admin/post-types/meta-boxes/views/html-order-item.php' );
|
||||
include( 'admin/meta-boxes/views/html-order-item.php' );
|
||||
|
||||
// Quit out
|
||||
die();
|
||||
|
@ -1029,7 +1031,7 @@ class WC_AJAX {
|
|||
wc_add_order_item_meta( $item_id, '_line_tax', '' );
|
||||
}
|
||||
|
||||
include( 'admin/post-types/meta-boxes/views/html-order-fee.php' );
|
||||
include( 'admin/meta-boxes/views/html-order-fee.php' );
|
||||
|
||||
// Quit out
|
||||
die();
|
||||
|
@ -1342,7 +1344,7 @@ class WC_AJAX {
|
|||
wc_add_order_item_meta( $item_id, 'shipping_tax_amount', $item['shipping_tax_amount'] );
|
||||
}
|
||||
|
||||
include( 'admin/post-types/meta-boxes/views/html-order-tax.php' );
|
||||
include( 'admin/meta-boxes/views/html-order-tax.php' );
|
||||
}
|
||||
|
||||
$tax_row_html = ob_get_clean();
|
||||
|
|
|
@ -27,6 +27,8 @@ class WC_Post_Data {
|
|||
add_action( 'edited_term', array( __CLASS__, 'edited_term' ), 10, 3 );
|
||||
add_filter( 'update_order_item_metadata', array( __CLASS__, 'update_order_item_metadata' ), 10, 5 );
|
||||
add_filter( 'update_post_metadata', array( __CLASS__, 'update_post_metadata' ), 10, 5 );
|
||||
add_filter( 'wp_insert_post_data', array( __CLASS__, 'wp_insert_post_data' ) );
|
||||
add_action( 'pre_post_update', array( __CLASS__, 'pre_post_update' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -112,6 +114,51 @@ class WC_Post_Data {
|
|||
}
|
||||
return $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces the order posts to have a title in a certain format (containing the date).
|
||||
* Forces certain product data based on the product's type, e.g. grouped products cannot have a parent.
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
public static function wp_insert_post_data( $data ) {
|
||||
global $post;
|
||||
|
||||
if ( 'shop_order' === $data['post_type'] && isset( $data['post_date'] ) ) {
|
||||
$order_title = 'Order';
|
||||
if ( $data['post_date'] ) {
|
||||
$order_title.= ' – ' . date_i18n( 'F j, Y @ h:i A', strtotime( $data['post_date'] ) );
|
||||
}
|
||||
$data['post_title'] = $order_title;
|
||||
}
|
||||
|
||||
elseif ( 'product' === $data['post_type'] && isset( $_POST['product-type'] ) ) {
|
||||
$product_type = stripslashes( $_POST['product-type'] );
|
||||
switch ( $product_type ) {
|
||||
case 'grouped' :
|
||||
case 'variable' :
|
||||
$data['post_parent'] = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Some functions, like the term recount, require the visibility to be set prior. Lets save that here.
|
||||
*
|
||||
* @param int $post_id
|
||||
*/
|
||||
public function pre_post_update( $post_id ) {
|
||||
if ( isset( $_POST['_visibility'] ) ) {
|
||||
update_post_meta( $post_id, '_visibility', stripslashes( $_POST['_visibility'] ) );
|
||||
}
|
||||
if ( isset( $_POST['_stock_status'] ) ) {
|
||||
wc_update_product_stock_status( $post_id, wc_clean( $_POST['_stock_status'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WC_Post_Data::init();
|
|
@ -12,14 +12,12 @@
|
|||
|
||||
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
|
||||
|
||||
// Include core functions
|
||||
include( 'wc-cart-functions.php' );
|
||||
// Include core functions (available in both admin and frontend)
|
||||
include( 'wc-conditional-functions.php' );
|
||||
include( 'wc-coupon-functions.php' );
|
||||
include( 'wc-user-functions.php' );
|
||||
include( 'wc-deprecated-functions.php' );
|
||||
include( 'wc-formatting-functions.php' );
|
||||
include( 'wc-notice-functions.php' );
|
||||
include( 'wc-order-functions.php' );
|
||||
include( 'wc-page-functions.php' );
|
||||
include( 'wc-product-functions.php' );
|
||||
|
@ -452,3 +450,27 @@ function wc_fix_rewrite_rules( $rules ) {
|
|||
return $rules;
|
||||
}
|
||||
add_filter( 'rewrite_rules_array', 'wc_fix_rewrite_rules' );
|
||||
|
||||
/**
|
||||
* Protect downloads from ms-files.php in multisite
|
||||
*
|
||||
* @param mixed $rewrite
|
||||
* @return string
|
||||
*/
|
||||
function wc_ms_protect_download_rewite_rules( $rewrite ) {
|
||||
global $wp_rewrite;
|
||||
|
||||
if ( ! is_multisite() || 'redirect' == get_option( 'woocommerce_file_download_method' ) ) {
|
||||
return $rewrite;
|
||||
}
|
||||
|
||||
$rule = "\n# WooCommerce Rules - Protect Files from ms-files.php\n\n";
|
||||
$rule .= "<IfModule mod_rewrite.c>\n";
|
||||
$rule .= "RewriteEngine On\n";
|
||||
$rule .= "RewriteCond %{QUERY_STRING} file=woocommerce_uploads/ [NC]\n";
|
||||
$rule .= "RewriteRule /ms-files.php$ - [F]\n";
|
||||
$rule .= "</IfModule>\n\n";
|
||||
|
||||
return $rule . $rewrite;
|
||||
}
|
||||
add_filter( 'mod_rewrite_rules', 'wc_ms_protect_download_rewite_rules' );
|
|
@ -202,7 +202,7 @@ final class WooCommerce {
|
|||
} elseif ( strpos( $class, 'wc_shortcode_' ) === 0 ) {
|
||||
$path = $this->plugin_path() . '/includes/shortcodes/';
|
||||
} elseif ( strpos( $class, 'wc_meta_box' ) === 0 ) {
|
||||
$path = $this->plugin_path() . '/includes/admin/post-types/meta-boxes/';
|
||||
$path = $this->plugin_path() . '/includes/admin/meta-boxes/';
|
||||
} elseif ( strpos( $class, 'wc_admin' ) === 0 ) {
|
||||
$path = $this->plugin_path() . '/includes/admin/';
|
||||
}
|
||||
|
@ -263,8 +263,6 @@ final class WooCommerce {
|
|||
include_once( 'includes/class-wc-download-handler.php' );
|
||||
include_once( 'includes/class-wc-comments.php' );
|
||||
include_once( 'includes/class-wc-post-data.php' );
|
||||
include_once( 'includes/abstracts/abstract-wc-session.php' );
|
||||
include_once( 'includes/class-wc-session-handler.php' );
|
||||
|
||||
if ( is_admin() ) {
|
||||
include_once( 'includes/admin/class-wc-admin.php' );
|
||||
|
@ -299,10 +297,6 @@ final class WooCommerce {
|
|||
include_once( 'includes/class-wc-countries.php' ); // Defines countries and states
|
||||
include_once( 'includes/class-wc-integrations.php' ); // Loads integrations
|
||||
include_once( 'includes/class-wc-cache-helper.php' ); // Cache Helper
|
||||
include_once( 'includes/class-wc-https.php' ); // https Helper
|
||||
|
||||
// Include template hooks in time for themes to remove/modify them
|
||||
include_once( 'includes/wc-template-hooks.php' );
|
||||
|
||||
// Download/update languages
|
||||
include_once( 'includes/class-wc-language-pack-upgrader.php' );
|
||||
|
@ -319,6 +313,14 @@ final class WooCommerce {
|
|||
* Include required frontend files.
|
||||
*/
|
||||
public function frontend_includes() {
|
||||
// Functions
|
||||
include_once( 'includes/wc-cart-functions.php' );
|
||||
include_once( 'includes/wc-notice-functions.php' );
|
||||
|
||||
// Classes
|
||||
include_once( 'includes/abstracts/abstract-wc-session.php' );
|
||||
include_once( 'includes/class-wc-session-handler.php' );
|
||||
include_once( 'includes/wc-template-hooks.php' );
|
||||
include_once( 'includes/class-wc-template-loader.php' ); // Template Loader
|
||||
include_once( 'includes/class-wc-frontend-scripts.php' ); // Frontend Scripts
|
||||
include_once( 'includes/class-wc-form-handler.php' ); // Form Handlers
|
||||
|
@ -326,14 +328,17 @@ final class WooCommerce {
|
|||
include_once( 'includes/class-wc-tax.php' ); // Tax class
|
||||
include_once( 'includes/class-wc-customer.php' ); // Customer class
|
||||
include_once( 'includes/class-wc-shortcodes.php' ); // Shortcodes class
|
||||
include_once( 'includes/class-wc-https.php' ); // https Helper
|
||||
}
|
||||
|
||||
/**
|
||||
* Function used to Init WooCommerce Template Functions - This makes them pluggable by plugins and themes.
|
||||
*/
|
||||
public function include_template_functions() {
|
||||
if ( ! is_admin() || defined( 'DOING_AJAX' ) ) {
|
||||
include_once( 'includes/wc-template-functions.php' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Include core widgets
|
||||
|
@ -363,18 +368,18 @@ final class WooCommerce {
|
|||
// Set up localisation
|
||||
$this->load_plugin_textdomain();
|
||||
|
||||
// Session class, handles session data for users - can be overwritten if custom handler is needed
|
||||
$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
|
||||
|
||||
// Load class instances
|
||||
$this->product_factory = new WC_Product_Factory(); // Product Factory to create new product instances
|
||||
$this->countries = new WC_Countries(); // Countries class
|
||||
$this->integrations = new WC_Integrations(); // Integrations class
|
||||
$this->session = new $session_class();
|
||||
|
||||
// Classes/actions loaded for the frontend and for ajax requests
|
||||
if ( ! is_admin() || defined( 'DOING_AJAX' ) ) {
|
||||
// Session class, handles session data for users - can be overwritten if custom handler is needed
|
||||
$session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' );
|
||||
|
||||
// Class instances
|
||||
$this->session = new $session_class();
|
||||
$this->cart = new WC_Cart(); // Cart class, stores the cart contents
|
||||
$this->customer = new WC_Customer(); // Customer class, handles data such as customer location
|
||||
}
|
||||
|
@ -394,8 +399,9 @@ final class WooCommerce {
|
|||
'woocommerce_created_customer'
|
||||
);
|
||||
|
||||
foreach ( $email_actions as $action )
|
||||
foreach ( $email_actions as $action ) {
|
||||
add_action( $action, array( $this, 'send_transactional_email' ), 10, 10 );
|
||||
}
|
||||
|
||||
// Init action
|
||||
do_action( 'woocommerce_init' );
|
||||
|
|
Loading…
Reference in New Issue