Нема описа

class-wp-ms-sites-list-table.php 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742
  1. <?php
  2. /**
  3. * List Table API: WP_MS_Sites_List_Table class
  4. *
  5. * @package WordPress
  6. * @subpackage Administration
  7. * @since 3.1.0
  8. */
  9. /**
  10. * Core class used to implement displaying sites in a list table for the network admin.
  11. *
  12. * @since 3.1.0
  13. * @access private
  14. *
  15. * @see WP_List_Table
  16. */
  17. class WP_MS_Sites_List_Table extends WP_List_Table {
  18. /**
  19. * Site status list.
  20. *
  21. * @since 4.3.0
  22. * @var array
  23. */
  24. public $status_list;
  25. /**
  26. * Constructor.
  27. *
  28. * @since 3.1.0
  29. *
  30. * @see WP_List_Table::__construct() for more information on default arguments.
  31. *
  32. * @param array $args An associative array of arguments.
  33. */
  34. public function __construct( $args = array() ) {
  35. $this->status_list = array(
  36. 'archived' => array( 'site-archived', __( 'Archived' ) ),
  37. 'spam' => array( 'site-spammed', _x( 'Spam', 'site' ) ),
  38. 'deleted' => array( 'site-deleted', __( 'Deleted' ) ),
  39. 'mature' => array( 'site-mature', __( 'Mature' ) ),
  40. );
  41. parent::__construct(
  42. array(
  43. 'plural' => 'sites',
  44. 'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
  45. )
  46. );
  47. }
  48. /**
  49. * @return bool
  50. */
  51. public function ajax_user_can() {
  52. return current_user_can( 'manage_sites' );
  53. }
  54. /**
  55. * Prepares the list of sites for display.
  56. *
  57. * @since 3.1.0
  58. *
  59. * @global string $mode List table view mode.
  60. * @global string $s
  61. * @global wpdb $wpdb WordPress database abstraction object.
  62. */
  63. public function prepare_items() {
  64. global $mode, $s, $wpdb;
  65. if ( ! empty( $_REQUEST['mode'] ) ) {
  66. $mode = 'excerpt' === $_REQUEST['mode'] ? 'excerpt' : 'list';
  67. set_user_setting( 'sites_list_mode', $mode );
  68. } else {
  69. $mode = get_user_setting( 'sites_list_mode', 'list' );
  70. }
  71. $per_page = $this->get_items_per_page( 'sites_network_per_page' );
  72. $pagenum = $this->get_pagenum();
  73. $s = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST['s'] ) ) : '';
  74. $wild = '';
  75. if ( false !== strpos( $s, '*' ) ) {
  76. $wild = '*';
  77. $s = trim( $s, '*' );
  78. }
  79. /*
  80. * If the network is large and a search is not being performed, show only
  81. * the latest sites with no paging in order to avoid expensive count queries.
  82. */
  83. if ( ! $s && wp_is_large_network() ) {
  84. if ( ! isset( $_REQUEST['orderby'] ) ) {
  85. $_GET['orderby'] = '';
  86. $_REQUEST['orderby'] = '';
  87. }
  88. if ( ! isset( $_REQUEST['order'] ) ) {
  89. $_GET['order'] = 'DESC';
  90. $_REQUEST['order'] = 'DESC';
  91. }
  92. }
  93. $args = array(
  94. 'number' => (int) $per_page,
  95. 'offset' => (int) ( ( $pagenum - 1 ) * $per_page ),
  96. 'network_id' => get_current_network_id(),
  97. );
  98. if ( empty( $s ) ) {
  99. // Nothing to do.
  100. } elseif ( preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $s ) ||
  101. preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
  102. preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
  103. preg_match( '/^[0-9]{1,3}\.$/', $s ) ) {
  104. // IPv4 address.
  105. $sql = $wpdb->prepare( "SELECT blog_id FROM {$wpdb->registration_log} WHERE {$wpdb->registration_log}.IP LIKE %s", $wpdb->esc_like( $s ) . ( ! empty( $wild ) ? '%' : '' ) );
  106. $reg_blog_ids = $wpdb->get_col( $sql );
  107. if ( $reg_blog_ids ) {
  108. $args['site__in'] = $reg_blog_ids;
  109. }
  110. } elseif ( is_numeric( $s ) && empty( $wild ) ) {
  111. $args['ID'] = $s;
  112. } else {
  113. $args['search'] = $s;
  114. if ( ! is_subdomain_install() ) {
  115. $args['search_columns'] = array( 'path' );
  116. }
  117. }
  118. $order_by = isset( $_REQUEST['orderby'] ) ? $_REQUEST['orderby'] : '';
  119. if ( 'registered' === $order_by ) {
  120. // 'registered' is a valid field name.
  121. } elseif ( 'lastupdated' === $order_by ) {
  122. $order_by = 'last_updated';
  123. } elseif ( 'blogname' === $order_by ) {
  124. if ( is_subdomain_install() ) {
  125. $order_by = 'domain';
  126. } else {
  127. $order_by = 'path';
  128. }
  129. } elseif ( 'blog_id' === $order_by ) {
  130. $order_by = 'id';
  131. } elseif ( ! $order_by ) {
  132. $order_by = false;
  133. }
  134. $args['orderby'] = $order_by;
  135. if ( $order_by ) {
  136. $args['order'] = ( isset( $_REQUEST['order'] ) && 'DESC' === strtoupper( $_REQUEST['order'] ) ) ? 'DESC' : 'ASC';
  137. }
  138. if ( wp_is_large_network() ) {
  139. $args['no_found_rows'] = true;
  140. } else {
  141. $args['no_found_rows'] = false;
  142. }
  143. // Take into account the role the user has selected.
  144. $status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : '';
  145. if ( in_array( $status, array( 'public', 'archived', 'mature', 'spam', 'deleted' ), true ) ) {
  146. $args[ $status ] = 1;
  147. }
  148. /**
  149. * Filters the arguments for the site query in the sites list table.
  150. *
  151. * @since 4.6.0
  152. *
  153. * @param array $args An array of get_sites() arguments.
  154. */
  155. $args = apply_filters( 'ms_sites_list_table_query_args', $args );
  156. $_sites = get_sites( $args );
  157. if ( is_array( $_sites ) ) {
  158. update_site_cache( $_sites );
  159. $this->items = array_slice( $_sites, 0, $per_page );
  160. }
  161. $total_sites = get_sites(
  162. array_merge(
  163. $args,
  164. array(
  165. 'count' => true,
  166. 'offset' => 0,
  167. 'number' => 0,
  168. )
  169. )
  170. );
  171. $this->set_pagination_args(
  172. array(
  173. 'total_items' => $total_sites,
  174. 'per_page' => $per_page,
  175. )
  176. );
  177. }
  178. /**
  179. */
  180. public function no_items() {
  181. _e( 'No sites found.' );
  182. }
  183. /**
  184. * Gets links to filter sites by status.
  185. *
  186. * @since 5.3.0
  187. *
  188. * @return array
  189. */
  190. protected function get_views() {
  191. $counts = wp_count_sites();
  192. $statuses = array(
  193. /* translators: %s: Number of sites. */
  194. 'all' => _nx_noop(
  195. 'All <span class="count">(%s)</span>',
  196. 'All <span class="count">(%s)</span>',
  197. 'sites'
  198. ),
  199. /* translators: %s: Number of sites. */
  200. 'public' => _n_noop(
  201. 'Public <span class="count">(%s)</span>',
  202. 'Public <span class="count">(%s)</span>'
  203. ),
  204. /* translators: %s: Number of sites. */
  205. 'archived' => _n_noop(
  206. 'Archived <span class="count">(%s)</span>',
  207. 'Archived <span class="count">(%s)</span>'
  208. ),
  209. /* translators: %s: Number of sites. */
  210. 'mature' => _n_noop(
  211. 'Mature <span class="count">(%s)</span>',
  212. 'Mature <span class="count">(%s)</span>'
  213. ),
  214. /* translators: %s: Number of sites. */
  215. 'spam' => _nx_noop(
  216. 'Spam <span class="count">(%s)</span>',
  217. 'Spam <span class="count">(%s)</span>',
  218. 'sites'
  219. ),
  220. /* translators: %s: Number of sites. */
  221. 'deleted' => _n_noop(
  222. 'Deleted <span class="count">(%s)</span>',
  223. 'Deleted <span class="count">(%s)</span>'
  224. ),
  225. );
  226. $view_links = array();
  227. $requested_status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : '';
  228. $url = 'sites.php';
  229. foreach ( $statuses as $status => $label_count ) {
  230. $current_link_attributes = $requested_status === $status || ( '' === $requested_status && 'all' === $status )
  231. ? ' class="current" aria-current="page"'
  232. : '';
  233. if ( (int) $counts[ $status ] > 0 ) {
  234. $label = sprintf( translate_nooped_plural( $label_count, $counts[ $status ] ), number_format_i18n( $counts[ $status ] ) );
  235. $full_url = 'all' === $status ? $url : add_query_arg( 'status', $status, $url );
  236. $view_links[ $status ] = sprintf(
  237. '<a href="%1$s"%2$s>%3$s</a>',
  238. esc_url( $full_url ),
  239. $current_link_attributes,
  240. $label
  241. );
  242. }
  243. }
  244. return $view_links;
  245. }
  246. /**
  247. * @return array
  248. */
  249. protected function get_bulk_actions() {
  250. $actions = array();
  251. if ( current_user_can( 'delete_sites' ) ) {
  252. $actions['delete'] = __( 'Delete' );
  253. }
  254. $actions['spam'] = _x( 'Mark as spam', 'site' );
  255. $actions['notspam'] = _x( 'Not spam', 'site' );
  256. return $actions;
  257. }
  258. /**
  259. * @global string $mode List table view mode.
  260. *
  261. * @param string $which The location of the pagination nav markup: 'top' or 'bottom'.
  262. */
  263. protected function pagination( $which ) {
  264. global $mode;
  265. parent::pagination( $which );
  266. if ( 'top' === $which ) {
  267. $this->view_switcher( $mode );
  268. }
  269. }
  270. /**
  271. * Extra controls to be displayed between bulk actions and pagination.
  272. *
  273. * @since 5.3.0
  274. *
  275. * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
  276. */
  277. protected function extra_tablenav( $which ) {
  278. ?>
  279. <div class="alignleft actions">
  280. <?php
  281. if ( 'top' === $which ) {
  282. ob_start();
  283. /**
  284. * Fires before the Filter button on the MS sites list table.
  285. *
  286. * @since 5.3.0
  287. *
  288. * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
  289. */
  290. do_action( 'restrict_manage_sites', $which );
  291. $output = ob_get_clean();
  292. if ( ! empty( $output ) ) {
  293. echo $output;
  294. submit_button( __( 'Filter' ), '', 'filter_action', false, array( 'id' => 'site-query-submit' ) );
  295. }
  296. }
  297. ?>
  298. </div>
  299. <?php
  300. /**
  301. * Fires immediately following the closing "actions" div in the tablenav for the
  302. * MS sites list table.
  303. *
  304. * @since 5.3.0
  305. *
  306. * @param string $which The location of the extra table nav markup: 'top' or 'bottom'.
  307. */
  308. do_action( 'manage_sites_extra_tablenav', $which );
  309. }
  310. /**
  311. * @return array
  312. */
  313. public function get_columns() {
  314. $sites_columns = array(
  315. 'cb' => '<input type="checkbox" />',
  316. 'blogname' => __( 'URL' ),
  317. 'lastupdated' => __( 'Last Updated' ),
  318. 'registered' => _x( 'Registered', 'site' ),
  319. 'users' => __( 'Users' ),
  320. );
  321. if ( has_filter( 'wpmublogsaction' ) ) {
  322. $sites_columns['plugins'] = __( 'Actions' );
  323. }
  324. /**
  325. * Filters the displayed site columns in Sites list table.
  326. *
  327. * @since MU (3.0.0)
  328. *
  329. * @param string[] $sites_columns An array of displayed site columns. Default 'cb',
  330. * 'blogname', 'lastupdated', 'registered', 'users'.
  331. */
  332. return apply_filters( 'wpmu_blogs_columns', $sites_columns );
  333. }
  334. /**
  335. * @return array
  336. */
  337. protected function get_sortable_columns() {
  338. return array(
  339. 'blogname' => 'blogname',
  340. 'lastupdated' => 'lastupdated',
  341. 'registered' => 'blog_id',
  342. );
  343. }
  344. /**
  345. * Handles the checkbox column output.
  346. *
  347. * @since 4.3.0
  348. *
  349. * @param array $blog Current site.
  350. */
  351. public function column_cb( $blog ) {
  352. if ( ! is_main_site( $blog['blog_id'] ) ) :
  353. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  354. ?>
  355. <label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>">
  356. <?php
  357. /* translators: %s: Site URL. */
  358. printf( __( 'Select %s' ), $blogname );
  359. ?>
  360. </label>
  361. <input type="checkbox" id="blog_<?php echo $blog['blog_id']; ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ); ?>" />
  362. <?php
  363. endif;
  364. }
  365. /**
  366. * Handles the ID column output.
  367. *
  368. * @since 4.4.0
  369. *
  370. * @param array $blog Current site.
  371. */
  372. public function column_id( $blog ) {
  373. echo $blog['blog_id'];
  374. }
  375. /**
  376. * Handles the site name column output.
  377. *
  378. * @since 4.3.0
  379. *
  380. * @global string $mode List table view mode.
  381. *
  382. * @param array $blog Current site.
  383. */
  384. public function column_blogname( $blog ) {
  385. global $mode;
  386. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  387. ?>
  388. <strong>
  389. <a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname; ?></a>
  390. <?php $this->site_states( $blog ); ?>
  391. </strong>
  392. <?php
  393. if ( 'list' !== $mode ) {
  394. switch_to_blog( $blog['blog_id'] );
  395. echo '<p>';
  396. printf(
  397. /* translators: 1: Site title, 2: Site tagline. */
  398. __( '%1$s &#8211; %2$s' ),
  399. get_option( 'blogname' ),
  400. '<em>' . get_option( 'blogdescription' ) . '</em>'
  401. );
  402. echo '</p>';
  403. restore_current_blog();
  404. }
  405. }
  406. /**
  407. * Handles the lastupdated column output.
  408. *
  409. * @since 4.3.0
  410. *
  411. * @global string $mode List table view mode.
  412. *
  413. * @param array $blog Current site.
  414. */
  415. public function column_lastupdated( $blog ) {
  416. global $mode;
  417. if ( 'list' === $mode ) {
  418. $date = __( 'Y/m/d' );
  419. } else {
  420. $date = __( 'Y/m/d g:i:s a' );
  421. }
  422. echo ( '0000-00-00 00:00:00' === $blog['last_updated'] ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
  423. }
  424. /**
  425. * Handles the registered column output.
  426. *
  427. * @since 4.3.0
  428. *
  429. * @global string $mode List table view mode.
  430. *
  431. * @param array $blog Current site.
  432. */
  433. public function column_registered( $blog ) {
  434. global $mode;
  435. if ( 'list' === $mode ) {
  436. $date = __( 'Y/m/d' );
  437. } else {
  438. $date = __( 'Y/m/d g:i:s a' );
  439. }
  440. if ( '0000-00-00 00:00:00' === $blog['registered'] ) {
  441. echo '&#x2014;';
  442. } else {
  443. echo mysql2date( $date, $blog['registered'] );
  444. }
  445. }
  446. /**
  447. * Handles the users column output.
  448. *
  449. * @since 4.3.0
  450. *
  451. * @param array $blog Current site.
  452. */
  453. public function column_users( $blog ) {
  454. $user_count = wp_cache_get( $blog['blog_id'] . '_user_count', 'blog-details' );
  455. if ( ! $user_count ) {
  456. $blog_users = new WP_User_Query(
  457. array(
  458. 'blog_id' => $blog['blog_id'],
  459. 'fields' => 'ID',
  460. 'number' => 1,
  461. 'count_total' => true,
  462. )
  463. );
  464. $user_count = $blog_users->get_total();
  465. wp_cache_set( $blog['blog_id'] . '_user_count', $user_count, 'blog-details', 12 * HOUR_IN_SECONDS );
  466. }
  467. printf(
  468. '<a href="%s">%s</a>',
  469. esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ),
  470. number_format_i18n( $user_count )
  471. );
  472. }
  473. /**
  474. * Handles the plugins column output.
  475. *
  476. * @since 4.3.0
  477. *
  478. * @param array $blog Current site.
  479. */
  480. public function column_plugins( $blog ) {
  481. if ( has_filter( 'wpmublogsaction' ) ) {
  482. /**
  483. * Fires inside the auxiliary 'Actions' column of the Sites list table.
  484. *
  485. * By default this column is hidden unless something is hooked to the action.
  486. *
  487. * @since MU (3.0.0)
  488. *
  489. * @param int $blog_id The site ID.
  490. */
  491. do_action( 'wpmublogsaction', $blog['blog_id'] );
  492. }
  493. }
  494. /**
  495. * Handles output for the default column.
  496. *
  497. * @since 4.3.0
  498. *
  499. * @param array $blog Current site.
  500. * @param string $column_name Current column name.
  501. */
  502. public function column_default( $blog, $column_name ) {
  503. /**
  504. * Fires for each registered custom column in the Sites list table.
  505. *
  506. * @since 3.1.0
  507. *
  508. * @param string $column_name The name of the column to display.
  509. * @param int $blog_id The site ID.
  510. */
  511. do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
  512. }
  513. /**
  514. * @global string $mode List table view mode.
  515. */
  516. public function display_rows() {
  517. foreach ( $this->items as $blog ) {
  518. $blog = $blog->to_array();
  519. $class = '';
  520. reset( $this->status_list );
  521. foreach ( $this->status_list as $status => $col ) {
  522. if ( 1 == $blog[ $status ] ) {
  523. $class = " class='{$col[0]}'";
  524. }
  525. }
  526. echo "<tr{$class}>";
  527. $this->single_row_columns( $blog );
  528. echo '</tr>';
  529. }
  530. }
  531. /**
  532. * Maybe output comma-separated site states.
  533. *
  534. * @since 5.3.0
  535. *
  536. * @param array $site
  537. */
  538. protected function site_states( $site ) {
  539. $site_states = array();
  540. // $site is still an array, so get the object.
  541. $_site = WP_Site::get_instance( $site['blog_id'] );
  542. if ( is_main_site( $_site->id ) ) {
  543. $site_states['main'] = __( 'Main' );
  544. }
  545. reset( $this->status_list );
  546. $site_status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : '';
  547. foreach ( $this->status_list as $status => $col ) {
  548. if ( ( 1 === (int) $_site->{$status} ) && ( $site_status !== $status ) ) {
  549. $site_states[ $col[0] ] = $col[1];
  550. }
  551. }
  552. /**
  553. * Filters the default site display states for items in the Sites list table.
  554. *
  555. * @since 5.3.0
  556. *
  557. * @param array $site_states An array of site states. Default 'Main',
  558. * 'Archived', 'Mature', 'Spam', 'Deleted'.
  559. * @param WP_Site $site The current site object.
  560. */
  561. $site_states = apply_filters( 'display_site_states', $site_states, $_site );
  562. if ( ! empty( $site_states ) ) {
  563. $state_count = count( $site_states );
  564. $i = 0;
  565. echo ' &mdash; ';
  566. foreach ( $site_states as $state ) {
  567. ++$i;
  568. ( $i == $state_count ) ? $sep = '' : $sep = ', ';
  569. echo "<span class='post-state'>{$state}{$sep}</span>";
  570. }
  571. }
  572. }
  573. /**
  574. * Gets the name of the default primary column.
  575. *
  576. * @since 4.3.0
  577. *
  578. * @return string Name of the default primary column, in this case, 'blogname'.
  579. */
  580. protected function get_default_primary_column_name() {
  581. return 'blogname';
  582. }
  583. /**
  584. * Generates and displays row action links.
  585. *
  586. * @since 4.3.0
  587. *
  588. * @param array $blog Site being acted upon.
  589. * @param string $column_name Current column name.
  590. * @param string $primary Primary column name.
  591. * @return string Row actions output for sites in Multisite, or an empty string
  592. * if the current column is not the primary column.
  593. */
  594. protected function handle_row_actions( $blog, $column_name, $primary ) {
  595. if ( $primary !== $column_name ) {
  596. return '';
  597. }
  598. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  599. // Preordered.
  600. $actions = array(
  601. 'edit' => '',
  602. 'backend' => '',
  603. 'activate' => '',
  604. 'deactivate' => '',
  605. 'archive' => '',
  606. 'unarchive' => '',
  607. 'spam' => '',
  608. 'unspam' => '',
  609. 'delete' => '',
  610. 'visit' => '',
  611. );
  612. $actions['edit'] = '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a>';
  613. $actions['backend'] = "<a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a>';
  614. if ( get_network()->site_id != $blog['blog_id'] ) {
  615. if ( '1' == $blog['deleted'] ) {
  616. $actions['activate'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=activateblog&amp;id=' . $blog['blog_id'] ), 'activateblog_' . $blog['blog_id'] ) ) . '">' . __( 'Activate' ) . '</a>';
  617. } else {
  618. $actions['deactivate'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deactivateblog&amp;id=' . $blog['blog_id'] ), 'deactivateblog_' . $blog['blog_id'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
  619. }
  620. if ( '1' == $blog['archived'] ) {
  621. $actions['unarchive'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unarchiveblog&amp;id=' . $blog['blog_id'] ), 'unarchiveblog_' . $blog['blog_id'] ) ) . '">' . __( 'Unarchive' ) . '</a>';
  622. } else {
  623. $actions['archive'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=archiveblog&amp;id=' . $blog['blog_id'] ), 'archiveblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Archive', 'verb; site' ) . '</a>';
  624. }
  625. if ( '1' == $blog['spam'] ) {
  626. $actions['unspam'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=unspamblog&amp;id=' . $blog['blog_id'] ), 'unspamblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Not Spam', 'site' ) . '</a>';
  627. } else {
  628. $actions['spam'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=spamblog&amp;id=' . $blog['blog_id'] ), 'spamblog_' . $blog['blog_id'] ) ) . '">' . _x( 'Spam', 'site' ) . '</a>';
  629. }
  630. if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
  631. $actions['delete'] = '<a href="' . esc_url( wp_nonce_url( network_admin_url( 'sites.php?action=confirm&amp;action2=deleteblog&amp;id=' . $blog['blog_id'] ), 'deleteblog_' . $blog['blog_id'] ) ) . '">' . __( 'Delete' ) . '</a>';
  632. }
  633. }
  634. $actions['visit'] = "<a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='bookmark'>" . __( 'Visit' ) . '</a>';
  635. /**
  636. * Filters the action links displayed for each site in the Sites list table.
  637. *
  638. * The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
  639. * default for each site. The site's status determines whether to show the
  640. * 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
  641. * 'Not Spam' or 'Spam' link for each site.
  642. *
  643. * @since 3.1.0
  644. *
  645. * @param string[] $actions An array of action links to be displayed.
  646. * @param int $blog_id The site ID.
  647. * @param string $blogname Site path, formatted depending on whether it is a sub-domain
  648. * or subdirectory multisite installation.
  649. */
  650. $actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
  651. return $this->row_actions( $actions );
  652. }
  653. }