Нет описания

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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755
  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. * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support.
  349. *
  350. * @param array $item Current site.
  351. */
  352. public function column_cb( $item ) {
  353. // Restores the more descriptive, specific name for use within this method.
  354. $blog = $item;
  355. if ( ! is_main_site( $blog['blog_id'] ) ) :
  356. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  357. ?>
  358. <label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>">
  359. <?php
  360. /* translators: %s: Site URL. */
  361. printf( __( 'Select %s' ), $blogname );
  362. ?>
  363. </label>
  364. <input type="checkbox" id="blog_<?php echo $blog['blog_id']; ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ); ?>" />
  365. <?php
  366. endif;
  367. }
  368. /**
  369. * Handles the ID column output.
  370. *
  371. * @since 4.4.0
  372. *
  373. * @param array $blog Current site.
  374. */
  375. public function column_id( $blog ) {
  376. echo $blog['blog_id'];
  377. }
  378. /**
  379. * Handles the site name column output.
  380. *
  381. * @since 4.3.0
  382. *
  383. * @global string $mode List table view mode.
  384. *
  385. * @param array $blog Current site.
  386. */
  387. public function column_blogname( $blog ) {
  388. global $mode;
  389. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  390. ?>
  391. <strong>
  392. <a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname; ?></a>
  393. <?php $this->site_states( $blog ); ?>
  394. </strong>
  395. <?php
  396. if ( 'list' !== $mode ) {
  397. switch_to_blog( $blog['blog_id'] );
  398. echo '<p>';
  399. printf(
  400. /* translators: 1: Site title, 2: Site tagline. */
  401. __( '%1$s &#8211; %2$s' ),
  402. get_option( 'blogname' ),
  403. '<em>' . get_option( 'blogdescription' ) . '</em>'
  404. );
  405. echo '</p>';
  406. restore_current_blog();
  407. }
  408. }
  409. /**
  410. * Handles the lastupdated column output.
  411. *
  412. * @since 4.3.0
  413. *
  414. * @global string $mode List table view mode.
  415. *
  416. * @param array $blog Current site.
  417. */
  418. public function column_lastupdated( $blog ) {
  419. global $mode;
  420. if ( 'list' === $mode ) {
  421. $date = __( 'Y/m/d' );
  422. } else {
  423. $date = __( 'Y/m/d g:i:s a' );
  424. }
  425. echo ( '0000-00-00 00:00:00' === $blog['last_updated'] ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
  426. }
  427. /**
  428. * Handles the registered column output.
  429. *
  430. * @since 4.3.0
  431. *
  432. * @global string $mode List table view mode.
  433. *
  434. * @param array $blog Current site.
  435. */
  436. public function column_registered( $blog ) {
  437. global $mode;
  438. if ( 'list' === $mode ) {
  439. $date = __( 'Y/m/d' );
  440. } else {
  441. $date = __( 'Y/m/d g:i:s a' );
  442. }
  443. if ( '0000-00-00 00:00:00' === $blog['registered'] ) {
  444. echo '&#x2014;';
  445. } else {
  446. echo mysql2date( $date, $blog['registered'] );
  447. }
  448. }
  449. /**
  450. * Handles the users column output.
  451. *
  452. * @since 4.3.0
  453. *
  454. * @param array $blog Current site.
  455. */
  456. public function column_users( $blog ) {
  457. $user_count = wp_cache_get( $blog['blog_id'] . '_user_count', 'blog-details' );
  458. if ( ! $user_count ) {
  459. $blog_users = new WP_User_Query(
  460. array(
  461. 'blog_id' => $blog['blog_id'],
  462. 'fields' => 'ID',
  463. 'number' => 1,
  464. 'count_total' => true,
  465. )
  466. );
  467. $user_count = $blog_users->get_total();
  468. wp_cache_set( $blog['blog_id'] . '_user_count', $user_count, 'blog-details', 12 * HOUR_IN_SECONDS );
  469. }
  470. printf(
  471. '<a href="%s">%s</a>',
  472. esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ),
  473. number_format_i18n( $user_count )
  474. );
  475. }
  476. /**
  477. * Handles the plugins column output.
  478. *
  479. * @since 4.3.0
  480. *
  481. * @param array $blog Current site.
  482. */
  483. public function column_plugins( $blog ) {
  484. if ( has_filter( 'wpmublogsaction' ) ) {
  485. /**
  486. * Fires inside the auxiliary 'Actions' column of the Sites list table.
  487. *
  488. * By default this column is hidden unless something is hooked to the action.
  489. *
  490. * @since MU (3.0.0)
  491. *
  492. * @param int $blog_id The site ID.
  493. */
  494. do_action( 'wpmublogsaction', $blog['blog_id'] );
  495. }
  496. }
  497. /**
  498. * Handles output for the default column.
  499. *
  500. * @since 4.3.0
  501. * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support.
  502. *
  503. * @param array $item Current site.
  504. * @param string $column_name Current column name.
  505. */
  506. public function column_default( $item, $column_name ) {
  507. /**
  508. * Fires for each registered custom column in the Sites list table.
  509. *
  510. * @since 3.1.0
  511. *
  512. * @param string $column_name The name of the column to display.
  513. * @param int $blog_id The site ID.
  514. */
  515. do_action( 'manage_sites_custom_column', $column_name, $item['blog_id'] );
  516. }
  517. /**
  518. * @global string $mode List table view mode.
  519. */
  520. public function display_rows() {
  521. foreach ( $this->items as $blog ) {
  522. $blog = $blog->to_array();
  523. $class = '';
  524. reset( $this->status_list );
  525. foreach ( $this->status_list as $status => $col ) {
  526. if ( 1 == $blog[ $status ] ) {
  527. $class = " class='{$col[0]}'";
  528. }
  529. }
  530. echo "<tr{$class}>";
  531. $this->single_row_columns( $blog );
  532. echo '</tr>';
  533. }
  534. }
  535. /**
  536. * Maybe output comma-separated site states.
  537. *
  538. * @since 5.3.0
  539. *
  540. * @param array $site
  541. */
  542. protected function site_states( $site ) {
  543. $site_states = array();
  544. // $site is still an array, so get the object.
  545. $_site = WP_Site::get_instance( $site['blog_id'] );
  546. if ( is_main_site( $_site->id ) ) {
  547. $site_states['main'] = __( 'Main' );
  548. }
  549. reset( $this->status_list );
  550. $site_status = isset( $_REQUEST['status'] ) ? wp_unslash( trim( $_REQUEST['status'] ) ) : '';
  551. foreach ( $this->status_list as $status => $col ) {
  552. if ( ( 1 === (int) $_site->{$status} ) && ( $site_status !== $status ) ) {
  553. $site_states[ $col[0] ] = $col[1];
  554. }
  555. }
  556. /**
  557. * Filters the default site display states for items in the Sites list table.
  558. *
  559. * @since 5.3.0
  560. *
  561. * @param string[] $site_states An array of site states. Default 'Main',
  562. * 'Archived', 'Mature', 'Spam', 'Deleted'.
  563. * @param WP_Site $site The current site object.
  564. */
  565. $site_states = apply_filters( 'display_site_states', $site_states, $_site );
  566. if ( ! empty( $site_states ) ) {
  567. $state_count = count( $site_states );
  568. $i = 0;
  569. echo ' &mdash; ';
  570. foreach ( $site_states as $state ) {
  571. ++$i;
  572. $sep = ( $i < $state_count ) ? ', ' : '';
  573. echo "<span class='post-state'>{$state}{$sep}</span>";
  574. }
  575. }
  576. }
  577. /**
  578. * Gets the name of the default primary column.
  579. *
  580. * @since 4.3.0
  581. *
  582. * @return string Name of the default primary column, in this case, 'blogname'.
  583. */
  584. protected function get_default_primary_column_name() {
  585. return 'blogname';
  586. }
  587. /**
  588. * Generates and displays row action links.
  589. *
  590. * @since 4.3.0
  591. * @since 5.9.0 Renamed `$blog` to `$item` to match parent class for PHP 8 named parameter support.
  592. *
  593. * @param array $item Site being acted upon.
  594. * @param string $column_name Current column name.
  595. * @param string $primary Primary column name.
  596. * @return string Row actions output for sites in Multisite, or an empty string
  597. * if the current column is not the primary column.
  598. */
  599. protected function handle_row_actions( $item, $column_name, $primary ) {
  600. if ( $primary !== $column_name ) {
  601. return '';
  602. }
  603. // Restores the more descriptive, specific name for use within this method.
  604. $blog = $item;
  605. $blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
  606. // Preordered.
  607. $actions = array(
  608. 'edit' => '',
  609. 'backend' => '',
  610. 'activate' => '',
  611. 'deactivate' => '',
  612. 'archive' => '',
  613. 'unarchive' => '',
  614. 'spam' => '',
  615. 'unspam' => '',
  616. 'delete' => '',
  617. 'visit' => '',
  618. );
  619. $actions['edit'] = '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a>';
  620. $actions['backend'] = "<a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a>';
  621. if ( get_network()->site_id != $blog['blog_id'] ) {
  622. if ( '1' == $blog['deleted'] ) {
  623. $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>';
  624. } else {
  625. $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>';
  626. }
  627. if ( '1' == $blog['archived'] ) {
  628. $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>';
  629. } else {
  630. $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>';
  631. }
  632. if ( '1' == $blog['spam'] ) {
  633. $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>';
  634. } else {
  635. $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>';
  636. }
  637. if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
  638. $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>';
  639. }
  640. }
  641. $actions['visit'] = "<a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='bookmark'>" . __( 'Visit' ) . '</a>';
  642. /**
  643. * Filters the action links displayed for each site in the Sites list table.
  644. *
  645. * The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
  646. * default for each site. The site's status determines whether to show the
  647. * 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
  648. * 'Not Spam' or 'Spam' link for each site.
  649. *
  650. * @since 3.1.0
  651. *
  652. * @param string[] $actions An array of action links to be displayed.
  653. * @param int $blog_id The site ID.
  654. * @param string $blogname Site path, formatted depending on whether it is a sub-domain
  655. * or subdirectory multisite installation.
  656. */
  657. $actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
  658. return $this->row_actions( $actions );
  659. }
  660. }