eligibility_service = $eligibility_service; } /** * Constructor. * * @return void */ public function __construct() { $this->data_store = \WC_Data_Store::load( 'stock_notification' ); $this->has_stock_notifications = $this->data_store->query( array( 'return' => 'count' ) ) > 0; parent::__construct( array( 'singular' => 'woocommerce_stock_notification', 'plural' => 'woocommerce_stock_notifications', ) ); } /** * Handles the checkbox column output. * * @param Notification $notification The notification object. * @return void */ public function column_cb( $notification ) { ?> sprintf( '%s', $notification->get_id(), __( 'Edit', 'woocommerce' ) ), 'delete' => sprintf( '%s', $notification->get_id(), __( 'Delete', 'woocommerce' ) ), ); $title = $notification->get_id(); printf( '#%s%s', esc_url( admin_url( NotificationsPage::PAGE_URL . '¬ification_action=edit¬ification_id=' . $notification->get_id() ) ), /* translators: %s: Notification code */ sprintf( esc_attr__( '“%s” (Edit)', 'woocommerce' ), esc_attr( $title ) ), esc_html( $title ), wp_kses_post( $this->row_actions( $actions ) ) ); } /** * Handles the status column output. * * @param Notification $notification The notification object. * @return void */ public function column_status( $notification ) { if ( $notification->get_status() === NotificationStatus::PENDING ) { $status = 'cancelled'; $label = _x( 'Pending', 'stock notification status', 'woocommerce' ); } elseif ( $notification->get_status() === NotificationStatus::CANCELLED ) { $status = 'cancelled'; $label = _x( 'Cancelled', 'stock notification status', 'woocommerce' ); } elseif ( $notification->get_status() === NotificationStatus::SENT ) { $status = 'cancelled'; $label = _x( 'Sent', 'stock notification status', 'woocommerce' ); } else { $status = 'completed'; $label = _x( 'Active', 'stock notification status', 'woocommerce' ); } printf( '%s', esc_attr( sanitize_html_class( 'status-' . $status ) ), esc_html( $label ) ); } /** * Handles the redeemed user column output. * * @param Notification $notification The notification object. * @return void */ public function column_user( $notification ) { if ( $notification->get_user_id() ) { $user = get_user_by( 'id', $notification->get_user_id() ); } if ( isset( $user ) && $user ) { printf( '%s', esc_url( get_edit_user_link( $user->ID ) ), esc_html( $user->display_name ) ); } else { echo esc_html( $notification->get_user_email() ); } } /** * Handles the product column output. * * @param Notification $notification The notification object. * @return void */ public function column_product( $notification ) { $product = $notification->get_product(); if ( ! is_a( $product, 'WC_Product' ) ) { echo '—'; return; } $name = $product->get_title(); $formatted_variation_list = $notification->get_product_formatted_variation_list( true ); if ( $formatted_variation_list ) { /* translators: product name, identifier */ $name .= '' . $formatted_variation_list . ''; } echo wp_kses_post( sprintf( '%s', $product->get_parent_id() ? absint( $product->get_parent_id() ) : absint( $product->get_id() ), $name ) ); } /** * Handles the product SKU output. * * @param Notification $notification The notification object. * @return void */ public function column_sku( $notification ) { $product = $notification->get_product(); $sku = false; if ( is_a( $product, 'WC_Product' ) ) { $sku = $product->get_sku(); } if ( $sku ) { echo wp_kses_post( $sku ); } else { echo '—'; } } /** * Handles the notification date column output. * * @param Notification $notification The notification object. * @return void */ public function column_date_created_gmt( $notification ) { $date_created = $notification->get_date_created(); if ( ! $date_created ) { $t_time = __( '—', 'woocommerce' ); $h_time = $t_time; } else { $date_created = $date_created->getTimestamp(); $t_time = date_i18n( _x( 'Y/m/d g:i:s a', 'list table date hover format', 'woocommerce' ), $date_created ); $h_time = date_i18n( wc_date_format(), $date_created ); } echo '' . esc_html( $h_time ) . ''; } /** * Message to be displayed when there are no items. * * @return void */ public function no_items() { ?>

'Title' */ public function get_columns() { $columns = array(); $columns['cb'] = ''; $columns['id'] = _x( 'Notification', 'column_name', 'woocommerce' ); $columns['status'] = _x( 'Status', 'column_name', 'woocommerce' ); $columns['user'] = _x( 'User/Email', 'column_name', 'woocommerce' ); $columns['product'] = _x( 'Product', 'column_name', 'woocommerce' ); $columns['sku'] = _x( 'SKU', 'column_name', 'woocommerce' ); $columns['date_created_gmt'] = _x( 'Signed Up', 'column_name', 'woocommerce' ); return $columns; } /** * Return sortable columns. * * @return array */ public function get_sortable_columns() { $sortable_columns = array( 'id' => array( 'id', true ), 'product' => array( 'product_id', true ), ); return $sortable_columns; } /** * Returns bulk actions. * * @return array */ protected function get_bulk_actions() { $actions = array(); $actions['enable'] = __( 'Activate', 'woocommerce' ); $actions['cancel'] = __( 'Cancel', 'woocommerce' ); $actions['delete'] = __( 'Delete permanently', 'woocommerce' ); return $actions; } /** * Query the DB and attach items. * * @return void */ public function prepare_items() { $per_page = (int) get_user_meta( get_current_user_id(), 'stock_notifications_per_page', true ); $per_page = $per_page > 0 ? $per_page : 10; // Table columns. $columns = $this->get_columns(); $hidden = array(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); // Setup params. $paged = isset( $_REQUEST['paged'] ) ? max( 0, (int) wp_unslash( $_REQUEST['paged'] ) - 1 ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $orderby = ( isset( $_REQUEST['orderby'] ) && in_array( wp_unslash( $_REQUEST['orderby'] ), array_keys( $this->get_sortable_columns() ), true ) ) ? wc_clean( wp_unslash( $_REQUEST['orderby'] ) ) : 'id'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $order = ( isset( $_REQUEST['order'] ) && in_array( wp_unslash( $_REQUEST['order'] ), array( 'asc', 'desc' ), true ) ) ? wc_clean( wp_unslash( $_REQUEST['order'] ) ) : 'desc'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended // Query args. $query_args = array( 'order_by' => array( $orderby => $order ), 'limit' => $per_page, 'offset' => $paged * $per_page, ); // Search. if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['user_email'] = EmailNormalizer::normalize( sanitize_text_field( wp_unslash( $_REQUEST['s'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } // Views. if ( ! empty( $_REQUEST['status'] ) && 'active_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['status'] = NotificationStatus::ACTIVE; } elseif ( ! empty( $_REQUEST['status'] ) && 'sent_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['status'] = NotificationStatus::SENT; } elseif ( ! empty( $_REQUEST['status'] ) && 'cancelled_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['status'] = NotificationStatus::CANCELLED; } elseif ( ! empty( $_REQUEST['status'] ) && 'pending_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['status'] = NotificationStatus::PENDING; } // Filters. if ( ! empty( $_GET['m'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $filter = absint( wp_unslash( $_GET['m'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $month = substr( (string) $filter, 4, 6 ); $year = substr( (string) $filter, 0, 4 ); // This will break at year 10.000 AC :). $start_timestamp = mktime( 0, 0, 0, (int) $month, 1, (int) $year ); $query_args['start_date'] = gmdate( 'Y-m-d H:i:s', $start_timestamp ); $end_timestamp = mktime( 0, 0, 0, (int) $month + 1, 1, (int) $year ); $query_args['end_date'] = gmdate( 'Y-m-d H:i:s', $end_timestamp ); } if ( ! empty( $_GET['customer_stock_notifications_product_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $filter = absint( wp_unslash( $_GET['customer_stock_notifications_product_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $product = wc_get_product( $filter ); if ( $product instanceof \WC_Product ) { $children = $product->get_children(); $query_args['product_id'] = $product->is_type( ProductType::VARIABLE ) ? array_merge( array( $product->get_id() ), is_array( $children ) ? $children : array() ) : array( $product->get_id() ); } else { NotificationsPage::add_notice( __( 'Invalid product selected.', 'woocommerce' ), 'error' ); } } if ( ! empty( $_GET['customer_stock_notifications_customer_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $query_args['user_id'] = absint( wp_unslash( $_GET['customer_stock_notifications_customer_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended } $query_args['return'] = 'objects'; $this->items = $this->data_store->query( $query_args ); // Count total items. $query_args['return'] = 'count'; unset( $query_args['limit'] ); unset( $query_args['offset'] ); $this->total_items = $this->data_store->query( $query_args ); // Count active. $query_args['status'] = NotificationStatus::ACTIVE; $this->total_active_items = $this->data_store->query( $query_args ); // Count sent. $query_args['status'] = NotificationStatus::SENT; $this->total_sent_items = $this->data_store->query( $query_args ); // Count cancelled. $query_args['status'] = NotificationStatus::CANCELLED; $this->total_cancelled_items = $this->data_store->query( $query_args ); // Count pending. $query_args['status'] = NotificationStatus::PENDING; $this->total_pending_items = $this->data_store->query( $query_args ); // Configure pagination. $this->set_pagination_args( array( 'total_items' => $this->total_items, // Total items defined above. 'per_page' => $per_page, // Per page constant defined at top of method. 'total_pages' => ceil( $this->total_items / $per_page ), // Calculate pages count. ) ); } /** * Display table extra nav. * * @param string $which top|bottom. * @return void */ public function extra_tablenav( $which ) { if ( 'top' === $which && ! is_singular() ) { ?>
render_filters(); submit_button( __( 'Filter', 'woocommerce' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) ); ?>
display_months_dropdown(); $this->display_customer_dropdown(); $this->display_product_dropdown(); } /** * Display product filter. * * @return void */ protected function display_product_dropdown() { $product_string = ''; $product_id = ''; if ( ! empty( $_GET['customer_stock_notifications_product_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $product_id = wc_clean( wp_unslash( $_GET['customer_stock_notifications_product_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended $product = wc_get_product( absint( $product_id ) ); if ( $product ) { $product_string = sprintf( /* translators: 1: product title 2: product ID */ esc_html__( '%1$s (#%2$s)', 'woocommerce' ), $product->get_parent_id() ? $product->get_name() : $product->get_title(), absint( $product->get_id() ) ); } } ?> display_name, absint( $user->ID ), $user->user_email ); } } ?> (%s)', 'All (%s)', $this->total_items, 'notifications_status', 'woocommerce' ), number_format_i18n( $this->total_items ) ); $status_links['all'] = $this->get_link( array( 'status' => 'all_customer_stock_notifications' ), $all_inner_html, $class ); // Active view. $class = ! empty( $_REQUEST['status'] ) && 'active_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $active_inner_html = sprintf( /* translators: %s: Notifications count */ _nx( 'Active (%s)', 'Active (%s)', $this->total_active_items, 'notifications_status', 'woocommerce' ), number_format_i18n( $this->total_active_items ) ); $status_links['active'] = $this->get_link( array( 'status' => 'active_customer_stock_notifications' ), $active_inner_html, $class ); // Sent view. $class = ! empty( $_REQUEST['status'] ) && 'sent_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $sent_inner_html = sprintf( /* translators: %s: Notifications count */ _nx( 'Sent (%s)', 'Sent (%s)', $this->total_sent_items, 'notifications_status', 'woocommerce' ), number_format_i18n( $this->total_sent_items ) ); $status_links['sent'] = $this->get_link( array( 'status' => 'sent_customer_stock_notifications' ), $sent_inner_html, $class ); // Cancelled view. $class = ! empty( $_REQUEST['status'] ) && 'cancelled_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $cancelled_inner_html = sprintf( /* translators: %s: Notifications count */ _nx( 'Cancelled (%s)', 'Cancelled (%s)', $this->total_cancelled_items, 'notifications_status', 'woocommerce' ), number_format_i18n( $this->total_cancelled_items ) ); $status_links['cancelled'] = $this->get_link( array( 'status' => 'cancelled_customer_stock_notifications' ), $cancelled_inner_html, $class ); // Pending view. $class = ! empty( $_REQUEST['status'] ) && 'pending_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended $pending_inner_html = sprintf( /* translators: %s: Notifications count */ _nx( 'Pending (%s)', 'Pending (%s)', $this->total_pending_items, 'notifications_status', 'woocommerce' ), number_format_i18n( $this->total_pending_items ) ); $status_links['pending'] = $this->get_link( array( 'status' => 'pending_customer_stock_notifications' ), $pending_inner_html, $class ); return $status_links; } /** * Construct a link string from args. * * @param array $args Arguments for the link. * @param string $label Link label. * @param string $css_class CSS class. * @return string */ protected function get_link( $args, $label, $css_class = '' ) { $url = add_query_arg( $args ); $class_html = ''; $aria_current = ''; if ( ! empty( $css_class ) ) { $class_html = sprintf( ' class="%s"', esc_attr( $css_class ) ); if ( 'current' === $css_class ) { $aria_current = ' aria-current="page"'; } } return sprintf( '%s', esc_url( $url ), $class_html, $aria_current, $label ); } /** * Display dates dropdown filter. * * @return void */ protected function display_months_dropdown() { global $wp_locale; $months = $this->data_store->get_distinct_dates(); if ( ! is_array( $months ) ) { return; } $month_count = count( $months ); if ( $month_count < 1 ) { return; } $m = isset( $_GET['m'] ) ? (int) wp_unslash( $_GET['m'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?> process_delete_action(); $this->process_bulk_action(); } /** * Process delete action. * * @return void */ public function process_delete_action(): void { $action = isset( $_GET['notification_action'] ) ? wc_clean( wp_unslash( $_GET['notification_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( 'delete' !== $action ) { return; } $notification_id = isset( $_GET['notification_id'] ) ? absint( $_GET['notification_id'] ) : 0; if ( ! $notification_id ) { return; } check_admin_referer( 'delete_customer_stock_notification' ); try { $notification = Factory::get_notification( $notification_id ); $this->data_store->delete( $notification ); $notice_message = __( 'Notification deleted.', 'woocommerce' ); NotificationsPage::add_notice( $notice_message, 'success' ); } catch ( \Exception $e ) { $notice_message = __( 'Notification not found.', 'woocommerce' ); NotificationsPage::add_notice( $notice_message, 'error' ); } wp_safe_redirect( admin_url( NotificationsPage::PAGE_URL ) ); exit(); } /** * Process bulk actions. * * @return void */ private function process_bulk_action() { if ( ! $this->current_action() ) { return; } check_admin_referer( 'bulk-' . $this->_args['plural'] ); $notifications = isset( $_GET['notification'] ) && is_array( $_GET['notification'] ) ? array_map( 'absint', $_GET['notification'] ) : array(); if ( empty( $notifications ) ) { return; } $redirect_url = NotificationsPage::PAGE_URL; if ( 'enable' === $this->current_action() ) { foreach ( $notifications as $id ) { $notification = Factory::get_notification( $id ); $notification->set_status( NotificationStatus::ACTIVE ); $this->data_store->update( $notification ); } $notice_message = sprintf( /* translators: %s: Notifications count */ _nx( '%s notification updated.', '%s notifications updated.', count( $notifications ), 'notifications_status', 'woocommerce' ), count( $notifications ) ); NotificationsPage::add_notice( $notice_message, 'success' ); } elseif ( 'cancel' === $this->current_action() ) { foreach ( $notifications as $id ) { $notification = Factory::get_notification( $id ); $notification->set_status( NotificationStatus::CANCELLED ); $this->data_store->update( $notification ); } $notice_message = sprintf( /* translators: %s: Notifications count */ _nx( '%s notification updated.', '%s notifications updated.', count( $notifications ), 'notifications_status', 'woocommerce' ), count( $notifications ) ); NotificationsPage::add_notice( $notice_message, 'success' ); } elseif ( 'delete' === $this->current_action() ) { foreach ( $notifications as $id ) { $notification = Factory::get_notification( $id ); $this->data_store->delete( $notification ); } $notice_message = sprintf( /* translators: %s: Notifications count */ _nx( '%s notification deleted.', '%s notifications deleted.', count( $notifications ), 'notifications_status', 'woocommerce' ), count( $notifications ) ); NotificationsPage::add_notice( $notice_message, 'success' ); } wp_safe_redirect( $redirect_url ); exit(); } }