Няма описание

Table.php 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. <?php
  2. /*******************************************************************************
  3. * Copyright (c) 2019, Code Atlantic LLC
  4. ******************************************************************************/
  5. if ( ! defined( 'ABSPATH' ) ) {
  6. exit;
  7. }
  8. /**
  9. * Class PUM_Admin_Subscribers_Table
  10. */
  11. class PUM_Admin_Subscribers_Table extends PUM_ListTable {
  12. /**
  13. * Constructor.
  14. *
  15. * The child class should call this constructor from its own constructor to override
  16. * the default $args.
  17. *
  18. * @param array|string $args {
  19. * Array or string of arguments.
  20. *
  21. * @type string $plural Plural value used for labels and the objects being listed.
  22. * This affects things such as CSS class-names and nonces used
  23. * in the list table, e.g. 'posts'. Default empty.
  24. * @type string $singular Singular label for an object being listed, e.g. 'post'.
  25. * Default empty
  26. * @type bool $ajax Whether the list table supports Ajax. This includes loading
  27. * and sorting data, for example. If true, the class will call
  28. * the _js_vars() method in the footer to provide variables
  29. * to any scripts handling Ajax events. Default false.
  30. * @type string $screen String containing the hook name used to determine the current
  31. * screen. If left null, the current screen will be automatically set.
  32. * Default null.
  33. * }
  34. */
  35. public function __construct( $args = array() ) {
  36. $args = wp_parse_args( $args, array(
  37. 'plural' => 'subscribers', // Plural value used for labels and the objects being listed.
  38. 'singular' => 'subscriber', // Singular label for an object being listed, e.g. 'post'.
  39. 'ajax' => false, // If true, the parent class will call the _js_vars() method in the footer
  40. ) );
  41. parent::__construct( $args );
  42. }
  43. /**
  44. * Prepares the list of items for displaying.
  45. *
  46. * @uses PUM_ListTable::set_pagination_args()
  47. */
  48. public function prepare_items() {
  49. $this->_column_headers = $this->get_column_info();
  50. // check and process any actions such as bulk actions.
  51. $this->handle_table_actions();
  52. $limit = $this->get_items_per_page( 'pum_subscribers_per_page' );
  53. $query_args = array(
  54. 's' => isset( $_REQUEST['s'] ) ? sanitize_text_field( $_REQUEST['s'] ) : null,
  55. 'limit' => $limit,
  56. 'page' => $this->get_pagenum(),
  57. 'orderby' => isset( $_REQUEST['orderby'] ) ? sanitize_text_field( $_REQUEST['orderby'] ) : null,
  58. 'order' => isset( $_REQUEST['order'] ) ? sanitize_text_field( $_REQUEST['order'] ) : null,
  59. );
  60. $this->items = PUM_DB_Subscribers::instance()->query( $query_args, 'ARRAY_A' );
  61. $total_subscribers = PUM_DB_Subscribers::instance()->total_rows( $query_args );
  62. $this->set_pagination_args( array(
  63. 'total_items' => $total_subscribers,
  64. 'per_page' => $limit,
  65. 'total_pages' => ceil( $total_subscribers / $limit ),
  66. ) );
  67. }
  68. /**
  69. * Get a list of columns. The format is:
  70. * 'internal-name' => 'Title'
  71. *
  72. * @return array
  73. */
  74. public function get_columns() {
  75. return apply_filters( 'pum_subscribers_table_columns', array(
  76. 'cb' => '<input type="checkbox" />', // to display the checkbox.
  77. 'email' => __( 'Email', 'popup-maker' ),
  78. 'name' => __( 'Full Name', 'popup-maker' ),
  79. 'fname' => __( 'First Name', 'popup-maker' ),
  80. 'lname' => __( 'Last Name', 'popup-maker' ),
  81. 'popup_id' => __( 'Popup', 'popup-maker' ),
  82. //'user_id' => __( 'User ID', 'popup-maker' ),
  83. 'created' => _x( 'Subscribed On', 'column name', 'popup-maker' ),
  84. ) );
  85. }
  86. /**
  87. * Get a list of sortable columns. The format is:
  88. * 'internal-name' => 'orderby'
  89. * or
  90. * 'internal-name' => array( 'orderby', true )
  91. *
  92. * The second format will make the initial sorting order be descending
  93. * \ *
  94. *
  95. * @return array
  96. */
  97. protected function get_sortable_columns() {
  98. return apply_filters( 'pum_subscribers_table_columns', array(
  99. 'email' => 'email',
  100. 'fname' => 'fname',
  101. 'lname' => 'lname',
  102. 'popup_id' => 'popup_id',
  103. 'created' => 'created',
  104. ) );
  105. }
  106. /**
  107. * Gets the name of the primary column.
  108. *
  109. * @return string The name of the primary column.
  110. */
  111. protected function get_primary_column_name() {
  112. return 'email';
  113. }
  114. /**
  115. * Text displayed when no user data is available
  116. */
  117. public function no_items() {
  118. _e( 'No subscribers available.', 'popup-maker' );
  119. }
  120. /**
  121. * Render a column when no column specific method exists.
  122. *
  123. * @param array $item
  124. * @param string $column_name
  125. *
  126. * @return mixed
  127. */
  128. public function column_default( $item, $column_name ) {
  129. switch ( $column_name ) {
  130. case 'created':
  131. return date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $item[ $column_name ] ) );
  132. default:
  133. return $item[ $column_name ];
  134. }
  135. }
  136. /**
  137. * Get value for checkbox column.
  138. *
  139. * The special 'cb' column
  140. *
  141. * @param object $item A row's data
  142. *
  143. * @return string Text to be placed inside the column <td>.
  144. */
  145. protected function column_cb( $item ) {
  146. $label = sprintf( '<label class="screen-reader-text" for="subscriber_%d">%s</label>', $item['ID'], sprintf( __( 'Select %s' ), $item['name'] ) );
  147. $input = sprintf( '<input type="checkbox" name="%1$s[]" id="subscriber_%2$d" value="%2$d" />', $this->_args['singular'], $item['ID'] );
  148. return sprintf( '%s%s', $label, $input );
  149. }
  150. /** ************************************************************************
  151. * Recommended. This is a custom column method and is responsible for what
  152. * is rendered in any column with a name/slug of 'title'. Every time the class
  153. * needs to render a column, it first looks for a method named
  154. * column_{$column_title} - if it exists, that method is run. If it doesn't
  155. * exist, column_default() is called instead.
  156. *
  157. * This example also illustrates how to implement rollover actions. Actions
  158. * should be an associative array formatted as 'slug'=>'link html' - and you
  159. * will need to generate the URLs yourself. You could even ensure the links
  160. *
  161. *
  162. * @see WP_List_Table::::single_row_columns()
  163. *
  164. * @param array $item A singular item (one full row's worth of data)
  165. *
  166. * @return string Text to be placed inside the column <td> (movie title only)
  167. **************************************************************************/
  168. function column_email( $item ) {
  169. $url = add_query_arg( array(
  170. 'page' => $_REQUEST['page'],
  171. 'subscriber' => $item['ID'],
  172. '_wpnonce' => wp_create_nonce( 'pum_subscribers_table_action_nonce' ),
  173. ), admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) );
  174. $edit_url = add_query_arg( array(
  175. 'action' => 'edit',
  176. ), $url );
  177. $delete_url = add_query_arg( array(
  178. 'action' => 'delete',
  179. ), $url );
  180. //Build row actions
  181. $actions = array(
  182. //'edit' => sprintf( '<a href="%s">Edit</a>', $edit_url ),
  183. 'delete' => sprintf( '<a href="%s">Delete</a>', $delete_url ),
  184. );
  185. //Return the title contents
  186. return sprintf( '%1$s <span style="color:silver">(id:%2$s)</span>%3$s', /*$1%s*/
  187. $item['email'], /*$2%s*/
  188. $item['ID'], /*$3%s*/
  189. $this->row_actions( $actions ) );
  190. }
  191. /** ************************************************************************
  192. * Recommended. This is a custom column method and is responsible for what
  193. * is rendered in any column with a name/slug of 'title'. Every time the class
  194. * needs to render a column, it first looks for a method named
  195. * column_{$column_title} - if it exists, that method is run. If it doesn't
  196. * exist, column_default() is called instead.
  197. *
  198. * This example also illustrates how to implement rollover actions. Actions
  199. * should be an associative array formatted as 'slug'=>'link html' - and you
  200. * will need to generate the URLs yourself. You could even ensure the links
  201. *
  202. *
  203. * @see WP_List_Table::::single_row_columns()
  204. *
  205. * @param array $item A singular item (one full row's worth of data)
  206. *
  207. * @return string Text to be placed inside the column <td> (movie title only)
  208. **************************************************************************/
  209. function column_name( $item ) {
  210. $user_id = $item['user_id'] > 0 ? absint( $item['user_id'] ) : null;
  211. if ( $user_id ) {
  212. $url = admin_url( "user-edit.php?user_id=$user_id" );
  213. //Return the title contents
  214. return sprintf( '%s<br/><small style="color:silver">(%s: <a href="%s">#%s</a>)</small>', $item['name'], __( 'User ID', 'popup-maker' ), $url, $item['user_id'] );
  215. } else {
  216. return $item['name'];
  217. }
  218. }
  219. /** ************************************************************************
  220. * Recommended. This is a custom column method and is responsible for what
  221. * is rendered in any column with a name/slug of 'title'. Every time the class
  222. * needs to render a column, it first looks for a method named
  223. * column_{$column_title} - if it exists, that method is run. If it doesn't
  224. * exist, column_default() is called instead.
  225. *
  226. * This example also illustrates how to implement rollover actions. Actions
  227. * should be an associative array formatted as 'slug'=>'link html' - and you
  228. * will need to generate the URLs yourself. You could even ensure the links
  229. *
  230. *
  231. * @see WP_List_Table::::single_row_columns()
  232. *
  233. * @param array $item A singular item (one full row's worth of data)
  234. *
  235. * @return string Text to be placed inside the column <td> (movie title only)
  236. **************************************************************************/
  237. function column_popup_id( $item ) {
  238. $popup_id = $item['popup_id'] > 0 ? absint( $item['popup_id'] ) : null;
  239. $popup = pum_get_popup( $popup_id );
  240. if ( $popup_id && pum_is_popup( $popup ) ) {
  241. $url = admin_url( "post.php?post={$popup_id}&action=edit" );;
  242. //Return the title contents
  243. return sprintf( '%s<br/><small style="color:silver">(%s: <a href="%s">#%s</a>)</small>', $popup->post_title, __( 'ID', 'popup-maker' ), $url, $item['popup_id'] );
  244. } else {
  245. return __( 'N/A', 'popup-maker' );
  246. }
  247. }
  248. /**
  249. * Returns an associative array containing the bulk action
  250. *
  251. * @return array
  252. */
  253. public function get_bulk_actions() {
  254. /*
  255. * on hitting apply in bulk actions the url params are set as
  256. * ?action=bulk-download&paged=1&action2=-1
  257. *
  258. * action and action2 are set based on the triggers above or below the table
  259. */
  260. $actions = array(
  261. 'bulk-delete' => __( 'Delete', 'popup-maker' ),
  262. );
  263. return $actions;
  264. }
  265. /**
  266. * Process actions triggered by the user
  267. *
  268. * @since 1.0.0
  269. *
  270. */
  271. public function handle_table_actions() {
  272. //Detect when a bulk action is being triggered...
  273. $action1 = $this->current_action();
  274. if ( in_array( $action1, array( 'delete', 'bulk-delete' ) ) ) {
  275. // verify the nonce.
  276. if ( ! wp_verify_nonce( wp_unslash( $_REQUEST['_wpnonce'] ), $action1 == 'delete' ? 'pum_subscribers_table_action_nonce' : 'bulk-subscribers' ) ) {
  277. $this->invalid_nonce_redirect();
  278. } else {
  279. $subscribers = isset( $_REQUEST['subscriber'] ) ? $_REQUEST['subscriber'] : array();
  280. if ( is_numeric( $subscribers ) ) {
  281. $subscribers = array( $subscribers );
  282. }
  283. $subscribers = wp_parse_id_list( $subscribers );
  284. if ( $subscribers ) {
  285. $status = array();
  286. foreach ( $subscribers as $subscriber_id ) {
  287. $status[] = PUM_DB_Subscribers::instance()->delete( $subscriber_id );
  288. }
  289. if ( ! in_array( false, $status ) ) {
  290. wp_die( sprintf( _n( 'Subscriber deleted!', '%d Subscribers deleted!', count( $subscribers ), 'popup-maker' ), count( $subscribers ) ), __( 'Success', 'popup-maker' ), array(
  291. 'response' => 200,
  292. 'back_link' => esc_url( admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) ),
  293. ) );
  294. } else {
  295. $succeeded = count( array_filter( $status ) );
  296. $failed = count( $subscribers ) - $succeeded;
  297. if ( count( $subscribers ) == 1 ) {
  298. wp_die( __( 'Deleting subscriber failed.', 'popup-maker' ), __( 'Error', 'popup-maker' ), array(
  299. 'response' => 200,
  300. 'back_link' => esc_url( admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) ),
  301. ) );
  302. } else {
  303. wp_die( sprintf( __( '%d Subscribers deleted, %d failed', 'popup-maker' ), $succeeded, $failed ), __( 'Error', 'popup-maker' ), array(
  304. 'response' => 200,
  305. 'back_link' => esc_url( admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) ),
  306. ) );
  307. }
  308. }
  309. }
  310. wp_die( __( 'Uh oh, the subscribers was not deleted successfully!', 'popup-maker' ), __( 'Error', 'popup-maker' ), array(
  311. 'response' => 200,
  312. 'back_link' => esc_url( admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) ),
  313. ) );
  314. exit;
  315. }
  316. }
  317. /*
  318. * Note: Table bulk_actions can be identified by checking $_REQUEST['action'] and $_REQUEST['action2']
  319. *
  320. * action - is set if checkbox from top-most select-all is set, otherwise returns -1
  321. * action2 - is set if checkbox the bottom-most select-all checkbox is set, otherwise returns -1
  322. */
  323. // check for individual row actions
  324. $the_table_action = $this->current_action();
  325. if ( 'view_usermeta' === $the_table_action ) {
  326. $nonce = wp_unslash( $_REQUEST['_wpnonce'] );
  327. // verify the nonce.
  328. if ( ! wp_verify_nonce( $nonce, 'view_usermeta_nonce' ) ) {
  329. $this->invalid_nonce_redirect();
  330. } else {
  331. $this->page_view_usermeta( absint( $_REQUEST['user_id'] ) );
  332. $this->graceful_exit();
  333. }
  334. }
  335. if ( 'add_usermeta' === $the_table_action ) {
  336. $nonce = wp_unslash( $_REQUEST['_wpnonce'] );
  337. // verify the nonce.
  338. if ( ! wp_verify_nonce( $nonce, 'add_usermeta_nonce' ) ) {
  339. $this->invalid_nonce_redirect();
  340. } else {
  341. $this->page_add_usermeta( absint( $_REQUEST['user_id'] ) );
  342. $this->graceful_exit();
  343. }
  344. }
  345. // check for table bulk actions
  346. if ( ( isset( $_REQUEST['action'] ) && $_REQUEST['action'] === 'bulk-download' ) || ( isset( $_REQUEST['action2'] ) && $_REQUEST['action2'] === 'bulk-download' ) ) {
  347. $nonce = wp_unslash( $_REQUEST['_wpnonce'] );
  348. // verify the nonce.
  349. /*
  350. * Note: the nonce field is set by the parent class
  351. * wp_nonce_field( 'bulk-' . $this->_args['plural'] );
  352. *
  353. */
  354. if ( ! wp_verify_nonce( $nonce, 'bulk-users' ) ) {
  355. $this->invalid_nonce_redirect();
  356. } else {
  357. $this->page_bulk_download( $_REQUEST['users'] );
  358. $this->graceful_exit();
  359. }
  360. }
  361. }
  362. /**
  363. * Die when the nonce check fails.
  364. */
  365. public function invalid_nonce_redirect() {
  366. wp_die( __( 'Invalid Nonce', 'popup-maker' ), __( 'Error', 'popup-maker' ), array(
  367. 'response' => 403,
  368. 'back_link' => esc_url( admin_url( 'edit.php?page=pum-subscribers&post_type=popup' ) ),
  369. ) );
  370. }
  371. }