PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.1
WooCommerce v10.9.1
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / src / Internal / StockNotifications / Admin / ListTable.php
woocommerce / src / Internal / StockNotifications / Admin Last commit date
Templates 4 weeks ago AdminManager.php 10 months ago ListTable.php 10 months ago MenusController.php 10 months ago NotificationCreatePage.php 10 months ago NotificationEditPage.php 4 weeks ago NotificationsPage.php 4 weeks ago SettingsController.php 10 months ago
ListTable.php
825 lines
1 <?php
2
3 declare( strict_types = 1 );
4
5 namespace Automattic\WooCommerce\Internal\StockNotifications\Admin;
6
7 use Automattic\WooCommerce\Internal\DataStores\StockNotifications\StockNotificationsDataStore;
8 use Automattic\WooCommerce\Internal\StockNotifications\Enums\NotificationStatus;
9 use Automattic\WooCommerce\Internal\StockNotifications\Notification;
10 use Automattic\WooCommerce\Internal\StockNotifications\Factory;
11 use Automattic\WooCommerce\Internal\StockNotifications\Admin\NotificationsPage;
12 use Automattic\WooCommerce\Internal\StockNotifications\Utilities\EligibilityService;
13
14 /**
15 * Notifications list table for Customer Stock Notifications.
16 */
17 class ListTable extends \WP_List_Table {
18
19 /**
20 * Total view records.
21 *
22 * @var int
23 */
24 public $total_items = 0;
25
26 /**
27 * Total active records.
28 *
29 * @var int
30 */
31 public $total_active_items = 0;
32
33 /**
34 * Total pending records.
35 *
36 * @var int
37 */
38 public $total_pending_items = 0;
39
40 /**
41 * Total cancelled records.
42 *
43 * @var int
44 */
45 public $total_cancelled_items = 0;
46
47 /**
48 * Total sent records.
49 *
50 * @var int
51 */
52 public $total_sent_items = 0;
53
54 /**
55 * Has stock notifications.
56 *
57 * @var bool
58 */
59 public $has_stock_notifications = false;
60
61 /**
62 * Data store.
63 *
64 * @var StockNotificationsDataStore
65 */
66 public $data_store;
67
68 /**
69 * Eligibility service.
70 *
71 * @var EligibilityService
72 */
73 public $eligibility_service;
74
75 /**
76 * Init.
77 *
78 * @internal
79 *
80 * @param EligibilityService $eligibility_service Eligibility service.
81 */
82 final public function init( EligibilityService $eligibility_service ) {
83 $this->eligibility_service = $eligibility_service;
84 }
85
86 /**
87 * Constructor.
88 *
89 * @return void
90 */
91 public function __construct() {
92
93 $this->data_store = \WC_Data_Store::load( 'stock_notification' );
94 $this->has_stock_notifications = $this->data_store->query( array( 'return' => 'count' ) ) > 0;
95
96 parent::__construct(
97 array(
98 'singular' => 'woocommerce_stock_notification',
99 'plural' => 'woocommerce_stock_notifications',
100 )
101 );
102 }
103
104 /**
105 * Handles the checkbox column output.
106 *
107 * @param Notification $notification The notification object.
108 * @return void
109 */
110 public function column_cb( $notification ) {
111 ?><label class="screen-reader-text" for="cb-select-<?php echo absint( $notification->get_id() ); ?>">
112 <?php
113 /* translators: %s: Notification code */
114 printf( esc_html__( 'Select %s', 'woocommerce' ), esc_html( $notification->get_id() ) );
115 ?>
116 </label>
117 <input id="cb-select-<?php echo absint( $notification->get_id() ); ?>" type="checkbox" name="notification[]" value="<?php echo absint( $notification->get_id() ); ?>" />
118 <?php
119 }
120
121 /**
122 * Handles the title column output.
123 *
124 * @param Notification $notification The notification object.
125 * @return void
126 */
127 public function column_id( $notification ) {
128 $actions = array(
129 'edit' => sprintf( '<a href="' . admin_url( NotificationsPage::PAGE_URL . '&notification_action=edit&notification_id=%d' ) . '">%s</a>', $notification->get_id(), __( 'Edit', 'woocommerce' ) ),
130 'delete' => sprintf( '<a href="' . wp_nonce_url( admin_url( NotificationsPage::PAGE_URL . '&notification_action=delete&notification_id=%d' ), 'delete_customer_stock_notification' ) . '">%s</a>', $notification->get_id(), __( 'Delete', 'woocommerce' ) ),
131 );
132
133 $title = $notification->get_id();
134
135 printf(
136 '<a class="row-title" href="%s" aria-label="%s">#%s</a>%s',
137 esc_url( admin_url( NotificationsPage::PAGE_URL . '&notification_action=edit&notification_id=' . $notification->get_id() ) ),
138 /* translators: %s: Notification code */
139 sprintf( esc_attr__( '&#8220;%s&#8221; (Edit)', 'woocommerce' ), esc_attr( $title ) ),
140 esc_html( $title ),
141 wp_kses_post( $this->row_actions( $actions ) )
142 );
143 }
144
145 /**
146 * Handles the status column output.
147 *
148 * @param Notification $notification The notification object.
149 * @return void
150 */
151 public function column_status( $notification ) {
152
153 if ( $notification->get_status() === NotificationStatus::PENDING ) {
154 $status = 'cancelled';
155 $label = _x( 'Pending', 'stock notification status', 'woocommerce' );
156 } elseif ( $notification->get_status() === NotificationStatus::CANCELLED ) {
157 $status = 'cancelled';
158 $label = _x( 'Cancelled', 'stock notification status', 'woocommerce' );
159 } elseif ( $notification->get_status() === NotificationStatus::SENT ) {
160 $status = 'cancelled';
161 $label = _x( 'Sent', 'stock notification status', 'woocommerce' );
162 } else {
163 $status = 'completed';
164 $label = _x( 'Active', 'stock notification status', 'woocommerce' );
165 }
166
167 printf( '<mark class="order-status %s"><span>%s</span></mark>', esc_attr( sanitize_html_class( 'status-' . $status ) ), esc_html( $label ) );
168 }
169
170 /**
171 * Handles the redeemed user column output.
172 *
173 * @param Notification $notification The notification object.
174 * @return void
175 */
176 public function column_user( $notification ) {
177 if ( $notification->get_user_id() ) {
178 $user = get_user_by( 'id', $notification->get_user_id() );
179 }
180
181 if ( isset( $user ) && $user ) {
182 printf( '<a href="%s" target="_blank">%s</a>', esc_url( get_edit_user_link( $user->ID ) ), esc_html( $user->display_name ) );
183 } else {
184 echo esc_html( $notification->get_user_email() );
185 }
186 }
187
188 /**
189 * Handles the product column output.
190 *
191 * @param Notification $notification The notification object.
192 * @return void
193 */
194 public function column_product( $notification ) {
195 $product = $notification->get_product();
196
197 if ( ! is_a( $product, 'WC_Product' ) ) {
198 echo '&mdash;';
199 return;
200 }
201
202 $name = $product->get_name();
203 $formatted_variation_list = $this->get_product_formatted_variation_list( true );
204
205 if ( $formatted_variation_list ) {
206 /* translators: product name, identifier */
207 $name .= '<span class="description">' . $formatted_variation_list . '</span>';
208 }
209
210 echo wp_kses_post(
211 sprintf(
212 '<a target="_blank" href="' . admin_url( 'post.php?post=%d&action=edit' ) . '">%s</a>',
213 $product->get_parent_id() ? absint( $product->get_parent_id() ) : absint( $product->get_id() ),
214 $name
215 )
216 );
217 }
218
219 /**
220 * Handles the product SKU output.
221 *
222 * @param Notification $notification The notification object.
223 * @return void
224 */
225 public function column_sku( $notification ) {
226 $product = $notification->get_product();
227 $sku = false;
228
229 if ( is_a( $product, 'WC_Product' ) ) {
230 $sku = $product->get_sku();
231 }
232
233 if ( $sku ) {
234 echo wp_kses_post( $sku );
235 } else {
236 echo '&mdash;';
237 }
238 }
239
240 /**
241 * Handles the notification date column output.
242 *
243 * @param Notification $notification The notification object.
244 * @return void
245 */
246 public function column_date_created_gmt( $notification ) {
247 $date_created = $notification->get_date_created();
248
249 if ( ! $date_created ) {
250 $t_time = __( '&mdash;', 'woocommerce' );
251 $h_time = $t_time;
252 } else {
253 $date_created = $date_created->getTimestamp();
254 $t_time = date_i18n( _x( 'Y/m/d g:i:s a', 'list table date hover format', 'woocommerce' ), $date_created );
255 $h_time = date_i18n( wc_date_format(), $date_created );
256 }
257
258 echo '<span title="' . esc_attr( $t_time ) . '">' . esc_html( $h_time ) . '</span>';
259 }
260
261 /**
262 * Message to be displayed when there are no items.
263 *
264 * @return void
265 */
266 public function no_items() {
267 ?>
268 <p class="main">
269 <?php esc_html_e( 'No Notifications found', 'woocommerce' ); ?>
270 </p>
271 <?php
272 }
273
274 /**
275 * Get a list of columns. The format is:
276 * 'internal-name' => 'Title'
277 */
278 public function get_columns() {
279
280 $columns = array();
281 $columns['cb'] = '<input type="checkbox" />';
282 $columns['id'] = _x( 'Notification', 'column_name', 'woocommerce' );
283 $columns['status'] = _x( 'Status', 'column_name', 'woocommerce' );
284 $columns['user'] = _x( 'User/Email', 'column_name', 'woocommerce' );
285 $columns['product'] = _x( 'Product', 'column_name', 'woocommerce' );
286 $columns['sku'] = _x( 'SKU', 'column_name', 'woocommerce' );
287 $columns['date_created_gmt'] = _x( 'Signed Up', 'column_name', 'woocommerce' );
288
289 return $columns;
290 }
291
292 /**
293 * Return sortable columns.
294 *
295 * @return array
296 */
297 public function get_sortable_columns() {
298 $sortable_columns = array(
299 'id' => array( 'id', true ),
300 'product' => array( 'product_id', true ),
301 );
302
303 return $sortable_columns;
304 }
305
306 /**
307 * Returns bulk actions.
308 *
309 * @return array
310 */
311 protected function get_bulk_actions() {
312 $actions = array();
313 $actions['enable'] = __( 'Activate', 'woocommerce' );
314 $actions['cancel'] = __( 'Cancel', 'woocommerce' );
315 $actions['delete'] = __( 'Delete permanently', 'woocommerce' );
316 return $actions;
317 }
318
319 /**
320 * Query the DB and attach items.
321 *
322 * @return void
323 */
324 public function prepare_items() {
325 $per_page = (int) get_user_meta( get_current_user_id(), 'stock_notifications_per_page', true );
326 $per_page = $per_page > 0 ? $per_page : 10;
327
328 // Table columns.
329 $columns = $this->get_columns();
330 $hidden = array();
331 $sortable = $this->get_sortable_columns();
332 $this->_column_headers = array( $columns, $hidden, $sortable );
333
334 // Setup params.
335 $paged = isset( $_REQUEST['paged'] ) ? max( 0, (int) wp_unslash( $_REQUEST['paged'] ) - 1 ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
336 $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
337 $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
338
339 // Query args.
340 $query_args = array(
341 'order_by' => array( $orderby => $order ),
342 'limit' => $per_page,
343 'offset' => $paged * $per_page,
344 );
345
346 // Search.
347 if ( isset( $_REQUEST['s'] ) && ! empty( $_REQUEST['s'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
348 $query_args['user_email'] = wc_clean( wp_unslash( $_REQUEST['s'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
349 }
350
351 // Views.
352 if ( ! empty( $_REQUEST['status'] ) && 'active_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
353 $query_args['status'] = NotificationStatus::ACTIVE;
354 } elseif ( ! empty( $_REQUEST['status'] ) && 'sent_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
355 $query_args['status'] = NotificationStatus::SENT;
356 } elseif ( ! empty( $_REQUEST['status'] ) && 'cancelled_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
357 $query_args['status'] = NotificationStatus::CANCELLED;
358 } elseif ( ! empty( $_REQUEST['status'] ) && 'pending_customer_stock_notifications' === $_REQUEST['status'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
359 $query_args['status'] = NotificationStatus::PENDING;
360 }
361
362 // Filters.
363 if ( ! empty( $_GET['m'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
364 $filter = absint( wp_unslash( $_GET['m'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
365 $month = substr( (string) $filter, 4, 6 );
366 $year = substr( (string) $filter, 0, 4 ); // This will break at year 10.000 AC :).
367
368 $start_timestamp = mktime( 0, 0, 0, (int) $month, 1, (int) $year );
369 $query_args['start_date'] = gmdate( 'Y-m-d H:i:s', $start_timestamp );
370
371 $end_timestamp = mktime( 0, 0, 0, (int) $month + 1, 1, (int) $year );
372 $query_args['end_date'] = gmdate( 'Y-m-d H:i:s', $end_timestamp );
373 }
374
375 if ( ! empty( $_GET['customer_stock_notifications_product_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
376 $filter = absint( wp_unslash( $_GET['customer_stock_notifications_product_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
377 $product = wc_get_product( $filter );
378 if ( $product instanceof \WC_Product ) {
379 $target_ids = $this->eligibility_service->get_target_product_ids( $product );
380 $query_args['product_id'] = $target_ids;
381 } else {
382 NotificationsPage::add_notice( __( 'Invalid product selected.', 'woocommerce' ), 'error' );
383 }
384 }
385
386 if ( ! empty( $_GET['customer_stock_notifications_customer_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
387 $filter = absint( wp_unslash( $_GET['customer_stock_notifications_customer_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
388 $query_args['user_id'] = array( $filter );
389 }
390
391 $query_args['return'] = 'objects';
392 $this->items = $this->data_store->query( $query_args );
393
394 // Count total items.
395 $query_args['return'] = 'count';
396 unset( $query_args['limit'] );
397 unset( $query_args['offset'] );
398 $this->total_items = $this->data_store->query( $query_args );
399
400 // Count active.
401 $query_args['status'] = NotificationStatus::ACTIVE;
402 $this->total_active_items = $this->data_store->query( $query_args );
403
404 // Count sent.
405 $query_args['status'] = NotificationStatus::SENT;
406 $this->total_sent_items = $this->data_store->query( $query_args );
407
408 // Count cancelled.
409 $query_args['status'] = NotificationStatus::CANCELLED;
410 $this->total_cancelled_items = $this->data_store->query( $query_args );
411
412 // Count pending.
413 $query_args['status'] = NotificationStatus::PENDING;
414 $this->total_pending_items = $this->data_store->query( $query_args );
415
416 // Configure pagination.
417 $this->set_pagination_args(
418 array(
419 'total_items' => $this->total_items, // Total items defined above.
420 'per_page' => $per_page, // Per page constant defined at top of method.
421 'total_pages' => ceil( $this->total_items / $per_page ), // Calculate pages count.
422 )
423 );
424 }
425
426 /**
427 * Display table extra nav.
428 *
429 * @param string $which top|bottom.
430 * @return void
431 */
432 public function extra_tablenav( $which ) {
433 if ( 'top' === $which && ! is_singular() ) {
434 ?>
435 <div class="alignleft actions">
436 <?php
437 $this->render_filters();
438 submit_button( __( 'Filter', 'woocommerce' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
439 ?>
440 </div>
441 <?php
442 }
443 }
444
445 /**
446 * Display table filters.
447 *
448 * @return void
449 */
450 protected function render_filters() {
451 $this->display_months_dropdown();
452 $this->display_customer_dropdown();
453 $this->display_product_dropdown();
454 }
455
456 /**
457 * Display product filter.
458 *
459 * @return void
460 */
461 protected function display_product_dropdown() {
462 $product_string = '';
463 $product_id = '';
464
465 if ( ! empty( $_GET['customer_stock_notifications_product_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
466 $product_id = wc_clean( wp_unslash( $_GET['customer_stock_notifications_product_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
467 $product = wc_get_product( absint( $product_id ) );
468
469 if ( $product ) {
470 $product_string = sprintf(
471 /* translators: 1: product title 2: product ID */
472 esc_html__( '%1$s (#%2$s)', 'woocommerce' ),
473 $product->get_parent_id() ? $product->get_name() : $product->get_title(),
474 absint( $product->get_id() )
475 );
476 }
477 }
478 ?>
479 <select class="wc-product-search" name="customer_stock_notifications_product_filter" data-placeholder="<?php esc_attr_e( 'Select product&hellip;', 'woocommerce' ); ?>" data-allow_clear="true" id="customer_stock_notifications_product_filter">
480 <?php if ( $product_string && $product_id ) { ?>
481 <option value="<?php echo esc_attr( $product_id ); ?>" selected="selected"><?php echo wp_kses_post( htmlspecialchars( $product_string, ENT_COMPAT ) ); ?></option>
482 <?php } ?>
483 </select>
484 <?php
485 }
486
487 /**
488 * Display customer filter.
489 *
490 * @return void
491 */
492 protected function display_customer_dropdown() {
493 $user_string = '';
494 $user_id = '';
495
496 if ( ! empty( $_GET['customer_stock_notifications_customer_filter'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
497 $user_id = wc_clean( wp_unslash( $_GET['customer_stock_notifications_customer_filter'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
498 $user = get_user_by( 'id', absint( $user_id ) );
499
500 if ( $user ) {
501 $user_string = sprintf(
502 /* translators: 1: user display name 2: user ID 3: user email */
503 esc_html__( '%1$s (#%2$s &ndash; %3$s)', 'woocommerce' ),
504 $user->display_name,
505 absint( $user->ID ),
506 $user->user_email
507 );
508 }
509 }
510 ?>
511 <select class="wc-customer-search" name="customer_stock_notifications_customer_filter" data-placeholder="<?php esc_attr_e( 'Select customer&hellip;', 'woocommerce' ); ?>" data-allow_clear="true" id="customer_stock_notifications_customer_filter">
512 <?php if ( $user_string && $user_id ) { ?>
513 <option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo wp_kses_post( htmlspecialchars( $user_string, ENT_COMPAT ) ); ?></option>
514 <?php } ?>
515 </select>
516 <?php
517 }
518
519 /**
520 * Items of the `subsubsub` status menu.
521 *
522 * @return array
523 */
524 protected function get_views() {
525 $status_links = array();
526
527 // All view.
528 $class = ! empty( $_REQUEST['status'] ) && 'all_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
529 $all_inner_html = sprintf(
530 /* translators: %s: Notifications count */
531 _nx(
532 'All <span class="count">(%s)</span>',
533 'All <span class="count">(%s)</span>',
534 $this->total_items,
535 'notifications_status',
536 'woocommerce'
537 ),
538 number_format_i18n( $this->total_items )
539 );
540
541 $status_links['all'] = $this->get_link( array( 'status' => 'all_customer_stock_notifications' ), $all_inner_html, $class );
542
543 // Active view.
544 $class = ! empty( $_REQUEST['status'] ) && 'active_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
545 $active_inner_html = sprintf(
546 /* translators: %s: Notifications count */
547 _nx(
548 'Active <span class="count">(%s)</span>',
549 'Active <span class="count">(%s)</span>',
550 $this->total_active_items,
551 'notifications_status',
552 'woocommerce'
553 ),
554 number_format_i18n( $this->total_active_items )
555 );
556
557 $status_links['active'] = $this->get_link( array( 'status' => 'active_customer_stock_notifications' ), $active_inner_html, $class );
558
559 // Sent view.
560 $class = ! empty( $_REQUEST['status'] ) && 'sent_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
561 $sent_inner_html = sprintf(
562 /* translators: %s: Notifications count */
563 _nx(
564 'Sent <span class="count">(%s)</span>',
565 'Sent <span class="count">(%s)</span>',
566 $this->total_sent_items,
567 'notifications_status',
568 'woocommerce'
569 ),
570 number_format_i18n( $this->total_sent_items )
571 );
572
573 $status_links['sent'] = $this->get_link( array( 'status' => 'sent_customer_stock_notifications' ), $sent_inner_html, $class );
574
575 // Cancelled view.
576 $class = ! empty( $_REQUEST['status'] ) && 'cancelled_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
577 $cancelled_inner_html = sprintf(
578 /* translators: %s: Notifications count */
579 _nx(
580 'Cancelled <span class="count">(%s)</span>',
581 'Cancelled <span class="count">(%s)</span>',
582 $this->total_cancelled_items,
583 'notifications_status',
584 'woocommerce'
585 ),
586 number_format_i18n( $this->total_cancelled_items )
587 );
588
589 $status_links['cancelled'] = $this->get_link( array( 'status' => 'cancelled_customer_stock_notifications' ), $cancelled_inner_html, $class );
590
591 // Pending view.
592 $class = ! empty( $_REQUEST['status'] ) && 'pending_customer_stock_notifications' === $_REQUEST['status'] ? 'current' : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
593 $pending_inner_html = sprintf(
594 /* translators: %s: Notifications count */
595 _nx(
596 'Pending <span class="count">(%s)</span>',
597 'Pending <span class="count">(%s)</span>',
598 $this->total_pending_items,
599 'notifications_status',
600 'woocommerce'
601 ),
602 number_format_i18n( $this->total_pending_items )
603 );
604
605 $status_links['pending'] = $this->get_link( array( 'status' => 'pending_customer_stock_notifications' ), $pending_inner_html, $class );
606
607 return $status_links;
608 }
609
610 /**
611 * Construct a link string from args.
612 *
613 * @param array $args Arguments for the link.
614 * @param string $label Link label.
615 * @param string $css_class CSS class.
616 * @return string
617 */
618 protected function get_link( $args, $label, $css_class = '' ) {
619 $url = add_query_arg( $args );
620
621 $class_html = '';
622 $aria_current = '';
623 if ( ! empty( $css_class ) ) {
624 $class_html = sprintf(
625 ' class="%s"',
626 esc_attr( $css_class )
627 );
628
629 if ( 'current' === $css_class ) {
630 $aria_current = ' aria-current="page"';
631 }
632 }
633
634 return sprintf(
635 '<a href="%s"%s%s>%s</a>',
636 esc_url( $url ),
637 $class_html,
638 $aria_current,
639 $label
640 );
641 }
642
643 /**
644 * Display dates dropdown filter.
645 *
646 * @return void
647 */
648 protected function display_months_dropdown() {
649 global $wp_locale;
650
651 $months = $this->data_store->get_distinct_dates();
652
653 if ( ! is_array( $months ) ) {
654 return;
655 }
656
657 $month_count = count( $months );
658
659 if ( $month_count < 1 ) {
660 return;
661 }
662
663 $m = isset( $_GET['m'] ) ? (int) wp_unslash( $_GET['m'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
664 ?>
665 <label for="filter-by-date" class="screen-reader-text"><?php esc_html_e( 'Filter by date', 'woocommerce' ); ?></label>
666 <select name="m" id="filter-by-date">
667 <option<?php selected( $m, 0 ); ?> value="0"><?php esc_html_e( 'All dates', 'woocommerce' ); ?></option>
668 <?php
669 foreach ( $months as $arc_row ) {
670 if ( 0 === (int) $arc_row->year || 0 === (int) $arc_row->month ) {
671 continue;
672 }
673
674 $month = zeroise( $arc_row->month, 2 );
675 $year = $arc_row->year;
676
677 printf(
678 "<option %s value='%s'>%s</option>\n",
679 selected( $m, $year . $month, false ),
680 esc_attr( $arc_row->year . $month ),
681 /* translators: %1$s: month %2$s: year */
682 sprintf( esc_html__( '%1$s %2$d', 'woocommerce' ), esc_html( $wp_locale->get_month( $month ) ), esc_html( $year ) )
683 );
684 }
685 ?>
686 </select>
687 <?php
688 }
689
690 /**
691 * Process actions.
692 */
693 public function process_actions(): void {
694 $this->process_delete_action();
695 $this->process_bulk_action();
696 }
697
698 /**
699 * Process delete action.
700 *
701 * @return void
702 */
703 public function process_delete_action(): void {
704
705 $action = isset( $_GET['notification_action'] ) ? wc_clean( wp_unslash( $_GET['notification_action'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
706
707 if ( 'delete' !== $action ) {
708 return;
709 }
710
711 $notification_id = isset( $_GET['notification_id'] ) ? absint( $_GET['notification_id'] ) : 0;
712
713 if ( ! $notification_id ) {
714 return;
715 }
716
717 check_admin_referer( 'delete_customer_stock_notification' );
718
719 try {
720
721 $notification = Factory::get_notification( $notification_id );
722 $this->data_store->delete( $notification );
723
724 $notice_message = __( 'Notification deleted.', 'woocommerce' );
725 NotificationsPage::add_notice( $notice_message, 'success' );
726
727 } catch ( \Exception $e ) {
728
729 $notice_message = __( 'Notification not found.', 'woocommerce' );
730 NotificationsPage::add_notice( $notice_message, 'error' );
731 }
732
733 wp_safe_redirect( admin_url( NotificationsPage::PAGE_URL ) );
734 exit();
735 }
736
737 /**
738 * Process bulk actions.
739 *
740 * @return void
741 */
742 private function process_bulk_action() {
743 if ( ! $this->current_action() ) {
744 return;
745 }
746
747 check_admin_referer( 'bulk-' . $this->_args['plural'] );
748
749 $notifications = isset( $_GET['notification'] ) && is_array( $_GET['notification'] ) ? array_map( 'absint', $_GET['notification'] ) : array();
750
751 if ( empty( $notifications ) ) {
752 return;
753 }
754
755 $redirect_url = NotificationsPage::PAGE_URL;
756
757 if ( 'enable' === $this->current_action() ) {
758 foreach ( $notifications as $id ) {
759
760 $notification = Factory::get_notification( $id );
761 $notification->set_status( NotificationStatus::ACTIVE );
762 $this->data_store->update( $notification );
763
764 }
765 $notice_message = sprintf(
766 /* translators: %s: Notifications count */
767 _nx(
768 '%s notification updated.',
769 '%s notifications updated.',
770 count( $notifications ),
771 'notifications_status',
772 'woocommerce'
773 ),
774 count( $notifications )
775 );
776
777 NotificationsPage::add_notice( $notice_message, 'success' );
778
779 } elseif ( 'cancel' === $this->current_action() ) {
780 foreach ( $notifications as $id ) {
781 $notification = Factory::get_notification( $id );
782 $notification->set_status( NotificationStatus::CANCELLED );
783 $this->data_store->update( $notification );
784 }
785
786 $notice_message = sprintf(
787 /* translators: %s: Notifications count */
788 _nx(
789 '%s notification updated.',
790 '%s notifications updated.',
791 count( $notifications ),
792 'notifications_status',
793 'woocommerce'
794 ),
795 count( $notifications )
796 );
797
798 NotificationsPage::add_notice( $notice_message, 'success' );
799
800 } elseif ( 'delete' === $this->current_action() ) {
801 foreach ( $notifications as $id ) {
802 $notification = Factory::get_notification( $id );
803 $this->data_store->delete( $notification );
804 }
805
806 $notice_message = sprintf(
807 /* translators: %s: Notifications count */
808 _nx(
809 '%s notification deleted.',
810 '%s notifications deleted.',
811 count( $notifications ),
812 'notifications_status',
813 'woocommerce'
814 ),
815 count( $notifications )
816 );
817
818 NotificationsPage::add_notice( $notice_message, 'success' );
819 }
820
821 wp_safe_redirect( $redirect_url );
822 exit();
823 }
824 }
825