Initiale Version

This commit is contained in:
Jan Unger
2016-08-16 21:20:53 +02:00
commit 88cf71d772
10930 changed files with 1708903 additions and 0 deletions

View File

@@ -0,0 +1,112 @@
<?php
/**
* Administration API: Default admin hooks
*
* @package WordPress
* @subpackage Administration
* @since 4.3.0
*/
// Bookmark hooks.
add_action( 'admin_page_access_denied', 'wp_link_manager_disabled_message' );
// Dashboard hooks.
add_action( 'activity_box_end', 'wp_dashboard_quota' );
// Media hooks.
add_action( 'attachment_submitbox_misc_actions', 'attachment_submitbox_metadata' );
add_action( 'media_upload_image', 'wp_media_upload_handler' );
add_action( 'media_upload_audio', 'wp_media_upload_handler' );
add_action( 'media_upload_video', 'wp_media_upload_handler' );
add_action( 'media_upload_file', 'wp_media_upload_handler' );
add_action( 'post-plupload-upload-ui', 'media_upload_flash_bypass' );
add_action( 'post-html-upload-ui', 'media_upload_html_bypass' );
add_filter( 'async_upload_image', 'get_media_item', 10, 2 );
add_filter( 'async_upload_audio', 'get_media_item', 10, 2 );
add_filter( 'async_upload_video', 'get_media_item', 10, 2 );
add_filter( 'async_upload_file', 'get_media_item', 10, 2 );
add_filter( 'attachment_fields_to_save', 'image_attachment_fields_to_save', 10, 2 );
add_filter( 'media_upload_gallery', 'media_upload_gallery' );
add_filter( 'media_upload_library', 'media_upload_library' );
add_filter( 'media_upload_tabs', 'update_gallery_tab' );
// Misc hooks.
add_action( 'admin_head', 'wp_admin_canonical_url' );
add_action( 'admin_head', 'wp_color_scheme_settings' );
add_action( 'admin_head', 'wp_site_icon' );
add_action( 'admin_head', '_ipad_meta' );
add_action( 'post_edit_form_tag', 'post_form_autocomplete_off' );
add_action( 'update_option_home', 'update_home_siteurl', 10, 2 );
add_action( 'update_option_siteurl', 'update_home_siteurl', 10, 2 );
add_action( 'update_option_page_on_front', 'update_home_siteurl', 10, 2 );
add_filter( 'heartbeat_received', 'wp_check_locked_posts', 10, 3 );
add_filter( 'heartbeat_received', 'wp_refresh_post_lock', 10, 3 );
add_filter( 'wp_refresh_nonces', 'wp_refresh_post_nonces', 10, 3 );
add_filter( 'heartbeat_received', 'heartbeat_autosave', 500, 2 );
add_filter( 'heartbeat_settings', 'wp_heartbeat_set_suspension' );
// Nav Menu hooks.
add_action( 'admin_head-nav-menus.php', '_wp_delete_orphaned_draft_menu_items' );
// Plugin hooks.
add_filter( 'whitelist_options', 'option_update_filter' );
// Plugin Install hooks.
add_action( 'install_plugins_featured', 'install_dashboard' );
add_action( 'install_plugins_upload', 'install_plugins_upload' );
add_action( 'install_plugins_search', 'display_plugins_table' );
add_action( 'install_plugins_popular', 'display_plugins_table' );
add_action( 'install_plugins_recommended', 'display_plugins_table' );
add_action( 'install_plugins_new', 'display_plugins_table' );
add_action( 'install_plugins_beta', 'display_plugins_table' );
add_action( 'install_plugins_favorites', 'display_plugins_table' );
add_action( 'install_plugins_pre_plugin-information', 'install_plugin_information' );
// Template hooks.
add_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
add_action( 'user_register', array( 'WP_Internal_Pointers', 'dismiss_pointers_for_new_users' ) );
// Theme hooks.
add_action( 'customize_controls_print_footer_scripts', 'customize_themes_print_templates' );
// Theme Install hooks.
// add_action('install_themes_dashboard', 'install_themes_dashboard');
// add_action('install_themes_upload', 'install_themes_upload', 10, 0);
// add_action('install_themes_search', 'display_themes');
// add_action('install_themes_featured', 'display_themes');
// add_action('install_themes_new', 'display_themes');
// add_action('install_themes_updated', 'display_themes');
add_action( 'install_themes_pre_theme-information', 'install_theme_information' );
// User hooks.
add_action( 'admin_init', 'default_password_nag_handler' );
add_action( 'admin_notices', 'default_password_nag' );
add_action( 'profile_update', 'default_password_nag_edit_user', 10, 2 );
// Update hooks.
add_action( 'admin_init', 'wp_plugin_update_rows' );
add_action( 'admin_init', 'wp_theme_update_rows' );
add_action( 'admin_notices', 'update_nag', 3 );
add_action( 'admin_notices', 'maintenance_nag', 10 );
add_filter( 'update_footer', 'core_update_footer' );
// Update Core hooks.
add_action( '_core_updated_successfully', '_redirect_to_about_wordpress' );
// Upgrade hooks.
add_action( 'upgrader_process_complete', array( 'Language_Pack_Upgrader', 'async_upgrade' ), 20 );

View File

@@ -0,0 +1,86 @@
<?php
/**
* Core Administration API
*
* @package WordPress
* @subpackage Administration
* @since 2.3.0
*/
if ( ! defined('WP_ADMIN') ) {
/*
* This file is being included from a file other than wp-admin/admin.php, so
* some setup was skipped. Make sure the admin message catalog is loaded since
* load_default_textdomain() will not have done so in this context.
*/
load_textdomain( 'default', WP_LANG_DIR . '/admin-' . get_locale() . '.mo' );
}
/** WordPress Administration Hooks */
require_once(ABSPATH . 'wp-admin/includes/admin-filters.php');
/** WordPress Bookmark Administration API */
require_once(ABSPATH . 'wp-admin/includes/bookmark.php');
/** WordPress Comment Administration API */
require_once(ABSPATH . 'wp-admin/includes/comment.php');
/** WordPress Administration File API */
require_once(ABSPATH . 'wp-admin/includes/file.php');
/** WordPress Image Administration API */
require_once(ABSPATH . 'wp-admin/includes/image.php');
/** WordPress Media Administration API */
require_once(ABSPATH . 'wp-admin/includes/media.php');
/** WordPress Import Administration API */
require_once(ABSPATH . 'wp-admin/includes/import.php');
/** WordPress Misc Administration API */
require_once(ABSPATH . 'wp-admin/includes/misc.php');
/** WordPress Options Administration API */
require_once(ABSPATH . 'wp-admin/includes/options.php');
/** WordPress Plugin Administration API */
require_once(ABSPATH . 'wp-admin/includes/plugin.php');
/** WordPress Post Administration API */
require_once(ABSPATH . 'wp-admin/includes/post.php');
/** WordPress Administration Screen API */
require_once(ABSPATH . 'wp-admin/includes/class-wp-screen.php');
require_once(ABSPATH . 'wp-admin/includes/screen.php');
/** WordPress Taxonomy Administration API */
require_once(ABSPATH . 'wp-admin/includes/taxonomy.php');
/** WordPress Template Administration API */
require_once(ABSPATH . 'wp-admin/includes/template.php');
/** WordPress List Table Administration API and base class */
require_once(ABSPATH . 'wp-admin/includes/class-wp-list-table.php');
require_once(ABSPATH . 'wp-admin/includes/list-table.php');
/** WordPress Theme Administration API */
require_once(ABSPATH . 'wp-admin/includes/theme.php');
/** WordPress User Administration API */
require_once(ABSPATH . 'wp-admin/includes/user.php');
/** WordPress Site Icon API */
require_once(ABSPATH . 'wp-admin/includes/class-wp-site-icon.php');
/** WordPress Update Administration API */
require_once(ABSPATH . 'wp-admin/includes/update.php');
/** WordPress Deprecated Administration API */
require_once(ABSPATH . 'wp-admin/includes/deprecated.php');
/** WordPress Multisite support API */
if ( is_multisite() ) {
require_once(ABSPATH . 'wp-admin/includes/ms-admin-filters.php');
require_once(ABSPATH . 'wp-admin/includes/ms.php');
require_once(ABSPATH . 'wp-admin/includes/ms-deprecated.php');
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,316 @@
<?php
/**
* WordPress Bookmark Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Add a link to using values provided in $_POST.
*
* @since 2.0.0
*
* @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
*/
function add_link() {
return edit_link();
}
/**
* Updates or inserts a link using values provided in $_POST.
*
* @since 2.0.0
*
* @param int $link_id Optional. ID of the link to edit. Default 0.
* @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
*/
function edit_link( $link_id = 0 ) {
if ( ! current_user_can( 'manage_links' ) ) {
wp_die(
'<h1>' . __( 'Cheatin&#8217; uh?' ) . '</h1>' .
'<p>' . __( 'You do not have sufficient permissions to edit the links for this site.' ) . '</p>',
403
);
}
$_POST['link_url'] = esc_html( $_POST['link_url'] );
$_POST['link_url'] = esc_url($_POST['link_url']);
$_POST['link_name'] = esc_html( $_POST['link_name'] );
$_POST['link_image'] = esc_html( $_POST['link_image'] );
$_POST['link_rss'] = esc_url($_POST['link_rss']);
if ( !isset($_POST['link_visible']) || 'N' != $_POST['link_visible'] )
$_POST['link_visible'] = 'Y';
if ( !empty( $link_id ) ) {
$_POST['link_id'] = $link_id;
return wp_update_link( $_POST );
} else {
return wp_insert_link( $_POST );
}
}
/**
* Retrieves the default link for editing.
*
* @since 2.0.0
*
* @return stdClass Default link object.
*/
function get_default_link_to_edit() {
$link = new stdClass;
if ( isset( $_GET['linkurl'] ) )
$link->link_url = esc_url( wp_unslash( $_GET['linkurl'] ) );
else
$link->link_url = '';
if ( isset( $_GET['name'] ) )
$link->link_name = esc_attr( wp_unslash( $_GET['name'] ) );
else
$link->link_name = '';
$link->link_visible = 'Y';
return $link;
}
/**
* Deletes a specified link from the database.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $link_id ID of the link to delete
* @return true Always true.
*/
function wp_delete_link( $link_id ) {
global $wpdb;
/**
* Fires before a link is deleted.
*
* @since 2.0.0
*
* @param int $link_id ID of the link to delete.
*/
do_action( 'delete_link', $link_id );
wp_delete_object_term_relationships( $link_id, 'link_category' );
$wpdb->delete( $wpdb->links, array( 'link_id' => $link_id ) );
/**
* Fires after a link has been deleted.
*
* @since 2.2.0
*
* @param int $link_id ID of the deleted link.
*/
do_action( 'deleted_link', $link_id );
clean_bookmark_cache( $link_id );
return true;
}
/**
* Retrieves the link categories associated with the link specified.
*
* @since 2.1.0
*
* @param int $link_id Link ID to look up
* @return array The requested link's categories
*/
function wp_get_link_cats( $link_id = 0 ) {
$cats = wp_get_object_terms( $link_id, 'link_category', array('fields' => 'ids') );
return array_unique( $cats );
}
/**
* Retrieves link data based on its ID.
*
* @since 2.0.0
*
* @param int $link_id ID of link to retrieve.
* @return object Link object for editing.
*/
function get_link_to_edit( $link_id ) {
return get_bookmark( $link_id, OBJECT, 'edit' );
}
/**
* Inserts/updates links into/in the database.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param array $linkdata Elements that make up the link to insert.
* @param bool $wp_error Optional. Whether to return a WP_Error object on failure. Default false.
* @return int|WP_Error Value 0 or WP_Error on failure. The link ID on success.
*/
function wp_insert_link( $linkdata, $wp_error = false ) {
global $wpdb;
$defaults = array( 'link_id' => 0, 'link_name' => '', 'link_url' => '', 'link_rating' => 0 );
$args = wp_parse_args( $linkdata, $defaults );
$r = wp_unslash( sanitize_bookmark( $args, 'db' ) );
$link_id = $r['link_id'];
$link_name = $r['link_name'];
$link_url = $r['link_url'];
$update = false;
if ( ! empty( $link_id ) ) {
$update = true;
}
if ( trim( $link_name ) == '' ) {
if ( trim( $link_url ) != '' ) {
$link_name = $link_url;
} else {
return 0;
}
}
if ( trim( $link_url ) == '' ) {
return 0;
}
$link_rating = ( ! empty( $r['link_rating'] ) ) ? $r['link_rating'] : 0;
$link_image = ( ! empty( $r['link_image'] ) ) ? $r['link_image'] : '';
$link_target = ( ! empty( $r['link_target'] ) ) ? $r['link_target'] : '';
$link_visible = ( ! empty( $r['link_visible'] ) ) ? $r['link_visible'] : 'Y';
$link_owner = ( ! empty( $r['link_owner'] ) ) ? $r['link_owner'] : get_current_user_id();
$link_notes = ( ! empty( $r['link_notes'] ) ) ? $r['link_notes'] : '';
$link_description = ( ! empty( $r['link_description'] ) ) ? $r['link_description'] : '';
$link_rss = ( ! empty( $r['link_rss'] ) ) ? $r['link_rss'] : '';
$link_rel = ( ! empty( $r['link_rel'] ) ) ? $r['link_rel'] : '';
$link_category = ( ! empty( $r['link_category'] ) ) ? $r['link_category'] : array();
// Make sure we set a valid category.
if ( ! is_array( $link_category ) || 0 == count( $link_category ) ) {
$link_category = array( get_option( 'default_link_category' ) );
}
if ( $update ) {
if ( false === $wpdb->update( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_rating', 'link_rel', 'link_notes', 'link_rss' ), compact( 'link_id' ) ) ) {
if ( $wp_error ) {
return new WP_Error( 'db_update_error', __( 'Could not update link in the database' ), $wpdb->last_error );
} else {
return 0;
}
}
} else {
if ( false === $wpdb->insert( $wpdb->links, compact( 'link_url', 'link_name', 'link_image', 'link_target', 'link_description', 'link_visible', 'link_owner', 'link_rating', 'link_rel', 'link_notes', 'link_rss' ) ) ) {
if ( $wp_error ) {
return new WP_Error( 'db_insert_error', __( 'Could not insert link into the database' ), $wpdb->last_error );
} else {
return 0;
}
}
$link_id = (int) $wpdb->insert_id;
}
wp_set_link_cats( $link_id, $link_category );
if ( $update ) {
/**
* Fires after a link was updated in the database.
*
* @since 2.0.0
*
* @param int $link_id ID of the link that was updated.
*/
do_action( 'edit_link', $link_id );
} else {
/**
* Fires after a link was added to the database.
*
* @since 2.0.0
*
* @param int $link_id ID of the link that was added.
*/
do_action( 'add_link', $link_id );
}
clean_bookmark_cache( $link_id );
return $link_id;
}
/**
* Update link with the specified link categories.
*
* @since 2.1.0
*
* @param int $link_id ID of the link to update.
* @param array $link_categories Array of link categories to add the link to.
*/
function wp_set_link_cats( $link_id = 0, $link_categories = array() ) {
// If $link_categories isn't already an array, make it one:
if ( !is_array( $link_categories ) || 0 == count( $link_categories ) )
$link_categories = array( get_option( 'default_link_category' ) );
$link_categories = array_map( 'intval', $link_categories );
$link_categories = array_unique( $link_categories );
wp_set_object_terms( $link_id, $link_categories, 'link_category' );
clean_bookmark_cache( $link_id );
}
/**
* Updates a link in the database.
*
* @since 2.0.0
*
* @param array $linkdata Link data to update.
* @return int|WP_Error Value 0 or WP_Error on failure. The updated link ID on success.
*/
function wp_update_link( $linkdata ) {
$link_id = (int) $linkdata['link_id'];
$link = get_bookmark( $link_id, ARRAY_A );
// Escape data pulled from DB.
$link = wp_slash( $link );
// Passed link category list overwrites existing category list if not empty.
if ( isset( $linkdata['link_category'] ) && is_array( $linkdata['link_category'] )
&& 0 != count( $linkdata['link_category'] ) )
$link_cats = $linkdata['link_category'];
else
$link_cats = $link['link_category'];
// Merge old and new fields with new fields overwriting old ones.
$linkdata = array_merge( $link, $linkdata );
$linkdata['link_category'] = $link_cats;
return wp_insert_link( $linkdata );
}
/**
* Outputs the 'disabled' message for the WordPress Link Manager.
*
* @since 3.5.0
* @access private
*
* @global string $pagenow
*/
function wp_link_manager_disabled_message() {
global $pagenow;
if ( 'link-manager.php' != $pagenow && 'link-add.php' != $pagenow && 'link.php' != $pagenow )
return;
add_filter( 'pre_option_link_manager_enabled', '__return_true', 100 );
$really_can_manage_links = current_user_can( 'manage_links' );
remove_filter( 'pre_option_link_manager_enabled', '__return_true', 100 );
if ( $really_can_manage_links && current_user_can( 'install_plugins' ) ) {
$link = network_admin_url( 'plugin-install.php?tab=search&amp;s=Link+Manager' );
wp_die( sprintf( __( 'If you are looking to use the link manager, please install the <a href="%s">Link Manager</a> plugin.' ), $link ) );
}
wp_die( __( 'You do not have sufficient permissions to edit the links for this site.' ) );
}

View File

@@ -0,0 +1,190 @@
<?php
/**
* PemFTP - A Ftp implementation in pure PHP
*
* @package PemFTP
* @since 2.5.0
*
* @version 1.0
* @copyright Alexey Dotsenko
* @author Alexey Dotsenko
* @link http://www.phpclasses.org/browse/package/1743.html Site
* @license LGPL http://www.opensource.org/licenses/lgpl-license.html
*/
/**
* FTP implementation using fsockopen to connect.
*
* @package PemFTP
* @subpackage Pure
* @since 2.5.0
*
* @version 1.0
* @copyright Alexey Dotsenko
* @author Alexey Dotsenko
* @link http://www.phpclasses.org/browse/package/1743.html Site
* @license LGPL http://www.opensource.org/licenses/lgpl-license.html
*/
class ftp extends ftp_base {
function __construct($verb=FALSE, $le=FALSE) {
parent::__construct(false, $verb, $le);
}
function ftp($verb=FALSE, $le=FALSE) {
$this->__construct($verb, $le);
}
// <!-- --------------------------------------------------------------------------------------- -->
// <!-- Private functions -->
// <!-- --------------------------------------------------------------------------------------- -->
function _settimeout($sock) {
if(!@stream_set_timeout($sock, $this->_timeout)) {
$this->PushError('_settimeout','socket set send timeout');
$this->_quit();
return FALSE;
}
return TRUE;
}
function _connect($host, $port) {
$this->SendMSG("Creating socket");
$sock = @fsockopen($host, $port, $errno, $errstr, $this->_timeout);
if (!$sock) {
$this->PushError('_connect','socket connect failed', $errstr." (".$errno.")");
return FALSE;
}
$this->_connected=true;
return $sock;
}
function _readmsg($fnction="_readmsg"){
if(!$this->_connected) {
$this->PushError($fnction, 'Connect first');
return FALSE;
}
$result=true;
$this->_message="";
$this->_code=0;
$go=true;
do {
$tmp=@fgets($this->_ftp_control_sock, 512);
if($tmp===false) {
$go=$result=false;
$this->PushError($fnction,'Read failed');
} else {
$this->_message.=$tmp;
if(preg_match("/^([0-9]{3})(-(.*[".CRLF."]{1,2})+\\1)? [^".CRLF."]+[".CRLF."]{1,2}$/", $this->_message, $regs)) $go=false;
}
} while($go);
if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF;
$this->_code=(int)$regs[1];
return $result;
}
function _exec($cmd, $fnction="_exec") {
if(!$this->_ready) {
$this->PushError($fnction,'Connect first');
return FALSE;
}
if($this->LocalEcho) echo "PUT > ",$cmd,CRLF;
$status=@fputs($this->_ftp_control_sock, $cmd.CRLF);
if($status===false) {
$this->PushError($fnction,'socket write failed');
return FALSE;
}
$this->_lastaction=time();
if(!$this->_readmsg($fnction)) return FALSE;
return TRUE;
}
function _data_prepare($mode=FTP_ASCII) {
if(!$this->_settype($mode)) return FALSE;
if($this->_passive) {
if(!$this->_exec("PASV", "pasv")) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
$ip_port = explode(",", preg_replace("/^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*$/s", "\\1", $this->_message));
$this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3];
$this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]);
$this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
$this->_ftp_data_sock=@fsockopen($this->_datahost, $this->_dataport, $errno, $errstr, $this->_timeout);
if(!$this->_ftp_data_sock) {
$this->PushError("_data_prepare","fsockopen fails", $errstr." (".$errno.")");
$this->_data_close();
return FALSE;
}
else $this->_ftp_data_sock;
} else {
$this->SendMSG("Only passive connections available!");
return FALSE;
}
return TRUE;
}
function _data_read($mode=FTP_ASCII, $fp=NULL) {
if(is_resource($fp)) $out=0;
else $out="";
if(!$this->_passive) {
$this->SendMSG("Only passive connections available!");
return FALSE;
}
while (!feof($this->_ftp_data_sock)) {
$block=fread($this->_ftp_data_sock, $this->_ftp_buff_size);
if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block);
if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block));
else $out.=$block;
}
return $out;
}
function _data_write($mode=FTP_ASCII, $fp=NULL) {
if(is_resource($fp)) $out=0;
else $out="";
if(!$this->_passive) {
$this->SendMSG("Only passive connections available!");
return FALSE;
}
if(is_resource($fp)) {
while(!feof($fp)) {
$block=fread($fp, $this->_ftp_buff_size);
if(!$this->_data_write_block($mode, $block)) return false;
}
} elseif(!$this->_data_write_block($mode, $fp)) return false;
return TRUE;
}
function _data_write_block($mode, $block) {
if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block);
do {
if(($t=@fwrite($this->_ftp_data_sock, $block))===FALSE) {
$this->PushError("_data_write","Can't write to socket");
return FALSE;
}
$block=substr($block, $t);
} while(!empty($block));
return true;
}
function _data_close() {
@fclose($this->_ftp_data_sock);
$this->SendMSG("Disconnected data from remote host");
return TRUE;
}
function _quit($force=FALSE) {
if($this->_connected or $force) {
@fclose($this->_ftp_control_sock);
$this->_connected=false;
$this->SendMSG("Socket closed");
}
}
}
?>

View File

@@ -0,0 +1,250 @@
<?php
/**
* PemFTP - A Ftp implementation in pure PHP
*
* @package PemFTP
* @since 2.5.0
*
* @version 1.0
* @copyright Alexey Dotsenko
* @author Alexey Dotsenko
* @link http://www.phpclasses.org/browse/package/1743.html Site
* @license LGPL http://www.opensource.org/licenses/lgpl-license.html
*/
/**
* Socket Based FTP implementation
*
* @package PemFTP
* @subpackage Socket
* @since 2.5.0
*
* @version 1.0
* @copyright Alexey Dotsenko
* @author Alexey Dotsenko
* @link http://www.phpclasses.org/browse/package/1743.html Site
* @license LGPL http://www.opensource.org/licenses/lgpl-license.html
*/
class ftp extends ftp_base {
function __construct($verb=FALSE, $le=FALSE) {
parent::__construct(true, $verb, $le);
}
function ftp($verb=FALSE, $le=FALSE) {
$this->__construct($verb, $le);
}
// <!-- --------------------------------------------------------------------------------------- -->
// <!-- Private functions -->
// <!-- --------------------------------------------------------------------------------------- -->
function _settimeout($sock) {
if(!@socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) {
$this->PushError('_connect','socket set receive timeout',socket_strerror(socket_last_error($sock)));
@socket_close($sock);
return FALSE;
}
if(!@socket_set_option($sock, SOL_SOCKET , SO_SNDTIMEO, array("sec"=>$this->_timeout, "usec"=>0))) {
$this->PushError('_connect','socket set send timeout',socket_strerror(socket_last_error($sock)));
@socket_close($sock);
return FALSE;
}
return true;
}
function _connect($host, $port) {
$this->SendMSG("Creating socket");
if(!($sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP))) {
$this->PushError('_connect','socket create failed',socket_strerror(socket_last_error($sock)));
return FALSE;
}
if(!$this->_settimeout($sock)) return FALSE;
$this->SendMSG("Connecting to \"".$host.":".$port."\"");
if (!($res = @socket_connect($sock, $host, $port))) {
$this->PushError('_connect','socket connect failed',socket_strerror(socket_last_error($sock)));
@socket_close($sock);
return FALSE;
}
$this->_connected=true;
return $sock;
}
function _readmsg($fnction="_readmsg"){
if(!$this->_connected) {
$this->PushError($fnction,'Connect first');
return FALSE;
}
$result=true;
$this->_message="";
$this->_code=0;
$go=true;
do {
$tmp=@socket_read($this->_ftp_control_sock, 4096, PHP_BINARY_READ);
if($tmp===false) {
$go=$result=false;
$this->PushError($fnction,'Read failed', socket_strerror(socket_last_error($this->_ftp_control_sock)));
} else {
$this->_message.=$tmp;
$go = !preg_match("/^([0-9]{3})(-.+\\1)? [^".CRLF."]+".CRLF."$/Us", $this->_message, $regs);
}
} while($go);
if($this->LocalEcho) echo "GET < ".rtrim($this->_message, CRLF).CRLF;
$this->_code=(int)$regs[1];
return $result;
}
function _exec($cmd, $fnction="_exec") {
if(!$this->_ready) {
$this->PushError($fnction,'Connect first');
return FALSE;
}
if($this->LocalEcho) echo "PUT > ",$cmd,CRLF;
$status=@socket_write($this->_ftp_control_sock, $cmd.CRLF);
if($status===false) {
$this->PushError($fnction,'socket write failed', socket_strerror(socket_last_error($this->stream)));
return FALSE;
}
$this->_lastaction=time();
if(!$this->_readmsg($fnction)) return FALSE;
return TRUE;
}
function _data_prepare($mode=FTP_ASCII) {
if(!$this->_settype($mode)) return FALSE;
$this->SendMSG("Creating data socket");
$this->_ftp_data_sock = @socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
if ($this->_ftp_data_sock < 0) {
$this->PushError('_data_prepare','socket create failed',socket_strerror(socket_last_error($this->_ftp_data_sock)));
return FALSE;
}
if(!$this->_settimeout($this->_ftp_data_sock)) {
$this->_data_close();
return FALSE;
}
if($this->_passive) {
if(!$this->_exec("PASV", "pasv")) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
$ip_port = explode(",", preg_replace("/^.+ \\(?([0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]{1,3},[0-9]+,[0-9]+)\\)?.*$/s", "\\1", $this->_message));
$this->_datahost=$ip_port[0].".".$ip_port[1].".".$ip_port[2].".".$ip_port[3];
$this->_dataport=(((int)$ip_port[4])<<8) + ((int)$ip_port[5]);
$this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
if(!@socket_connect($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) {
$this->PushError("_data_prepare","socket_connect", socket_strerror(socket_last_error($this->_ftp_data_sock)));
$this->_data_close();
return FALSE;
}
else $this->_ftp_temp_sock=$this->_ftp_data_sock;
} else {
if(!@socket_getsockname($this->_ftp_control_sock, $addr, $port)) {
$this->PushError("_data_prepare","can't get control socket information", socket_strerror(socket_last_error($this->_ftp_control_sock)));
$this->_data_close();
return FALSE;
}
if(!@socket_bind($this->_ftp_data_sock,$addr)){
$this->PushError("_data_prepare","can't bind data socket", socket_strerror(socket_last_error($this->_ftp_data_sock)));
$this->_data_close();
return FALSE;
}
if(!@socket_listen($this->_ftp_data_sock)) {
$this->PushError("_data_prepare","can't listen data socket", socket_strerror(socket_last_error($this->_ftp_data_sock)));
$this->_data_close();
return FALSE;
}
if(!@socket_getsockname($this->_ftp_data_sock, $this->_datahost, $this->_dataport)) {
$this->PushError("_data_prepare","can't get data socket information", socket_strerror(socket_last_error($this->_ftp_data_sock)));
$this->_data_close();
return FALSE;
}
if(!$this->_exec('PORT '.str_replace('.',',',$this->_datahost.'.'.($this->_dataport>>8).'.'.($this->_dataport&0x00FF)), "_port")) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
}
return TRUE;
}
function _data_read($mode=FTP_ASCII, $fp=NULL) {
$NewLine=$this->_eol_code[$this->OS_local];
if(is_resource($fp)) $out=0;
else $out="";
if(!$this->_passive) {
$this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
$this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock);
if($this->_ftp_temp_sock===FALSE) {
$this->PushError("_data_read","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
$this->_data_close();
return FALSE;
}
}
while(($block=@socket_read($this->_ftp_temp_sock, $this->_ftp_buff_size, PHP_BINARY_READ))!==false) {
if($block==="") break;
if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_local], $block);
if(is_resource($fp)) $out+=fwrite($fp, $block, strlen($block));
else $out.=$block;
}
return $out;
}
function _data_write($mode=FTP_ASCII, $fp=NULL) {
$NewLine=$this->_eol_code[$this->OS_local];
if(is_resource($fp)) $out=0;
else $out="";
if(!$this->_passive) {
$this->SendMSG("Connecting to ".$this->_datahost.":".$this->_dataport);
$this->_ftp_temp_sock=socket_accept($this->_ftp_data_sock);
if($this->_ftp_temp_sock===FALSE) {
$this->PushError("_data_write","socket_accept", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
$this->_data_close();
return false;
}
}
if(is_resource($fp)) {
while(!feof($fp)) {
$block=fread($fp, $this->_ftp_buff_size);
if(!$this->_data_write_block($mode, $block)) return false;
}
} elseif(!$this->_data_write_block($mode, $fp)) return false;
return true;
}
function _data_write_block($mode, $block) {
if($mode!=FTP_BINARY) $block=preg_replace("/\r\n|\r|\n/", $this->_eol_code[$this->OS_remote], $block);
do {
if(($t=@socket_write($this->_ftp_temp_sock, $block))===FALSE) {
$this->PushError("_data_write","socket_write", socket_strerror(socket_last_error($this->_ftp_temp_sock)));
$this->_data_close();
return FALSE;
}
$block=substr($block, $t);
} while(!empty($block));
return true;
}
function _data_close() {
@socket_close($this->_ftp_temp_sock);
@socket_close($this->_ftp_data_sock);
$this->SendMSG("Disconnected data from remote host");
return TRUE;
}
function _quit() {
if($this->_connected) {
@socket_close($this->_ftp_control_sock);
$this->_connected=false;
$this->SendMSG("Socket closed");
}
}
}
?>

View File

@@ -0,0 +1,906 @@
<?php
/**
* PemFTP - A Ftp implementation in pure PHP
*
* @package PemFTP
* @since 2.5
*
* @version 1.0
* @copyright Alexey Dotsenko
* @author Alexey Dotsenko
* @link http://www.phpclasses.org/browse/package/1743.html Site
* @license LGPL http://www.opensource.org/licenses/lgpl-license.html
*/
/**
* Defines the newline characters, if not defined already.
*
* This can be redefined.
*
* @since 2.5
* @var string
*/
if(!defined('CRLF')) define('CRLF',"\r\n");
/**
* Sets whatever to autodetect ASCII mode.
*
* This can be redefined.
*
* @since 2.5
* @var int
*/
if(!defined("FTP_AUTOASCII")) define("FTP_AUTOASCII", -1);
/**
*
* This can be redefined.
* @since 2.5
* @var int
*/
if(!defined("FTP_BINARY")) define("FTP_BINARY", 1);
/**
*
* This can be redefined.
* @since 2.5
* @var int
*/
if(!defined("FTP_ASCII")) define("FTP_ASCII", 0);
/**
* Whether to force FTP.
*
* This can be redefined.
*
* @since 2.5
* @var bool
*/
if(!defined('FTP_FORCE')) define('FTP_FORCE', true);
/**
* @since 2.5
* @var string
*/
define('FTP_OS_Unix','u');
/**
* @since 2.5
* @var string
*/
define('FTP_OS_Windows','w');
/**
* @since 2.5
* @var string
*/
define('FTP_OS_Mac','m');
/**
* PemFTP base class
*
*/
class ftp_base {
/* Public variables */
var $LocalEcho;
var $Verbose;
var $OS_local;
var $OS_remote;
/* Private variables */
var $_lastaction;
var $_errors;
var $_type;
var $_umask;
var $_timeout;
var $_passive;
var $_host;
var $_fullhost;
var $_port;
var $_datahost;
var $_dataport;
var $_ftp_control_sock;
var $_ftp_data_sock;
var $_ftp_temp_sock;
var $_ftp_buff_size;
var $_login;
var $_password;
var $_connected;
var $_ready;
var $_code;
var $_message;
var $_can_restore;
var $_port_available;
var $_curtype;
var $_features;
var $_error_array;
var $AuthorizedTransferMode;
var $OS_FullName;
var $_eol_code;
var $AutoAsciiExt;
/* Constructor */
function __construct($port_mode=FALSE, $verb=FALSE, $le=FALSE) {
$this->LocalEcho=$le;
$this->Verbose=$verb;
$this->_lastaction=NULL;
$this->_error_array=array();
$this->_eol_code=array(FTP_OS_Unix=>"\n", FTP_OS_Mac=>"\r", FTP_OS_Windows=>"\r\n");
$this->AuthorizedTransferMode=array(FTP_AUTOASCII, FTP_ASCII, FTP_BINARY);
$this->OS_FullName=array(FTP_OS_Unix => 'UNIX', FTP_OS_Windows => 'WINDOWS', FTP_OS_Mac => 'MACOS');
$this->AutoAsciiExt=array("ASP","BAT","C","CPP","CSS","CSV","JS","H","HTM","HTML","SHTML","INI","LOG","PHP3","PHTML","PL","PERL","SH","SQL","TXT");
$this->_port_available=($port_mode==TRUE);
$this->SendMSG("Staring FTP client class".($this->_port_available?"":" without PORT mode support"));
$this->_connected=FALSE;
$this->_ready=FALSE;
$this->_can_restore=FALSE;
$this->_code=0;
$this->_message="";
$this->_ftp_buff_size=4096;
$this->_curtype=NULL;
$this->SetUmask(0022);
$this->SetType(FTP_AUTOASCII);
$this->SetTimeout(30);
$this->Passive(!$this->_port_available);
$this->_login="anonymous";
$this->_password="anon@ftp.com";
$this->_features=array();
$this->OS_local=FTP_OS_Unix;
$this->OS_remote=FTP_OS_Unix;
$this->features=array();
if(strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') $this->OS_local=FTP_OS_Windows;
elseif(strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') $this->OS_local=FTP_OS_Mac;
}
function ftp_base($port_mode=FALSE) {
$this->__construct($port_mode);
}
// <!-- --------------------------------------------------------------------------------------- -->
// <!-- Public functions -->
// <!-- --------------------------------------------------------------------------------------- -->
function parselisting($line) {
$is_windows = ($this->OS_remote == FTP_OS_Windows);
if ($is_windows && preg_match("/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/",$line,$lucifer)) {
$b = array();
if ($lucifer[3]<70) { $lucifer[3]+=2000; } else { $lucifer[3]+=1900; } // 4digit year fix
$b['isdir'] = ($lucifer[7]=="<DIR>");
if ( $b['isdir'] )
$b['type'] = 'd';
else
$b['type'] = 'f';
$b['size'] = $lucifer[7];
$b['month'] = $lucifer[1];
$b['day'] = $lucifer[2];
$b['year'] = $lucifer[3];
$b['hour'] = $lucifer[4];
$b['minute'] = $lucifer[5];
$b['time'] = @mktime($lucifer[4]+(strcasecmp($lucifer[6],"PM")==0?12:0),$lucifer[5],0,$lucifer[1],$lucifer[2],$lucifer[3]);
$b['am/pm'] = $lucifer[6];
$b['name'] = $lucifer[8];
} else if (!$is_windows && $lucifer=preg_split("/[ ]/",$line,9,PREG_SPLIT_NO_EMPTY)) {
//echo $line."\n";
$lcount=count($lucifer);
if ($lcount<8) return '';
$b = array();
$b['isdir'] = $lucifer[0]{0} === "d";
$b['islink'] = $lucifer[0]{0} === "l";
if ( $b['isdir'] )
$b['type'] = 'd';
elseif ( $b['islink'] )
$b['type'] = 'l';
else
$b['type'] = 'f';
$b['perms'] = $lucifer[0];
$b['number'] = $lucifer[1];
$b['owner'] = $lucifer[2];
$b['group'] = $lucifer[3];
$b['size'] = $lucifer[4];
if ($lcount==8) {
sscanf($lucifer[5],"%d-%d-%d",$b['year'],$b['month'],$b['day']);
sscanf($lucifer[6],"%d:%d",$b['hour'],$b['minute']);
$b['time'] = @mktime($b['hour'],$b['minute'],0,$b['month'],$b['day'],$b['year']);
$b['name'] = $lucifer[7];
} else {
$b['month'] = $lucifer[5];
$b['day'] = $lucifer[6];
if (preg_match("/([0-9]{2}):([0-9]{2})/",$lucifer[7],$l2)) {
$b['year'] = date("Y");
$b['hour'] = $l2[1];
$b['minute'] = $l2[2];
} else {
$b['year'] = $lucifer[7];
$b['hour'] = 0;
$b['minute'] = 0;
}
$b['time'] = strtotime(sprintf("%d %s %d %02d:%02d",$b['day'],$b['month'],$b['year'],$b['hour'],$b['minute']));
$b['name'] = $lucifer[8];
}
}
return $b;
}
function SendMSG($message = "", $crlf=true) {
if ($this->Verbose) {
echo $message.($crlf?CRLF:"");
flush();
}
return TRUE;
}
function SetType($mode=FTP_AUTOASCII) {
if(!in_array($mode, $this->AuthorizedTransferMode)) {
$this->SendMSG("Wrong type");
return FALSE;
}
$this->_type=$mode;
$this->SendMSG("Transfer type: ".($this->_type==FTP_BINARY?"binary":($this->_type==FTP_ASCII?"ASCII":"auto ASCII") ) );
return TRUE;
}
function _settype($mode=FTP_ASCII) {
if($this->_ready) {
if($mode==FTP_BINARY) {
if($this->_curtype!=FTP_BINARY) {
if(!$this->_exec("TYPE I", "SetType")) return FALSE;
$this->_curtype=FTP_BINARY;
}
} elseif($this->_curtype!=FTP_ASCII) {
if(!$this->_exec("TYPE A", "SetType")) return FALSE;
$this->_curtype=FTP_ASCII;
}
} else return FALSE;
return TRUE;
}
function Passive($pasv=NULL) {
if(is_null($pasv)) $this->_passive=!$this->_passive;
else $this->_passive=$pasv;
if(!$this->_port_available and !$this->_passive) {
$this->SendMSG("Only passive connections available!");
$this->_passive=TRUE;
return FALSE;
}
$this->SendMSG("Passive mode ".($this->_passive?"on":"off"));
return TRUE;
}
function SetServer($host, $port=21, $reconnect=true) {
if(!is_long($port)) {
$this->verbose=true;
$this->SendMSG("Incorrect port syntax");
return FALSE;
} else {
$ip=@gethostbyname($host);
$dns=@gethostbyaddr($host);
if(!$ip) $ip=$host;
if(!$dns) $dns=$host;
// Validate the IPAddress PHP4 returns -1 for invalid, PHP5 false
// -1 === "255.255.255.255" which is the broadcast address which is also going to be invalid
$ipaslong = ip2long($ip);
if ( ($ipaslong == false) || ($ipaslong === -1) ) {
$this->SendMSG("Wrong host name/address \"".$host."\"");
return FALSE;
}
$this->_host=$ip;
$this->_fullhost=$dns;
$this->_port=$port;
$this->_dataport=$port-1;
}
$this->SendMSG("Host \"".$this->_fullhost."(".$this->_host."):".$this->_port."\"");
if($reconnect){
if($this->_connected) {
$this->SendMSG("Reconnecting");
if(!$this->quit(FTP_FORCE)) return FALSE;
if(!$this->connect()) return FALSE;
}
}
return TRUE;
}
function SetUmask($umask=0022) {
$this->_umask=$umask;
umask($this->_umask);
$this->SendMSG("UMASK 0".decoct($this->_umask));
return TRUE;
}
function SetTimeout($timeout=30) {
$this->_timeout=$timeout;
$this->SendMSG("Timeout ".$this->_timeout);
if($this->_connected)
if(!$this->_settimeout($this->_ftp_control_sock)) return FALSE;
return TRUE;
}
function connect($server=NULL) {
if(!empty($server)) {
if(!$this->SetServer($server)) return false;
}
if($this->_ready) return true;
$this->SendMsg('Local OS : '.$this->OS_FullName[$this->OS_local]);
if(!($this->_ftp_control_sock = $this->_connect($this->_host, $this->_port))) {
$this->SendMSG("Error : Cannot connect to remote host \"".$this->_fullhost." :".$this->_port."\"");
return FALSE;
}
$this->SendMSG("Connected to remote host \"".$this->_fullhost.":".$this->_port."\". Waiting for greeting.");
do {
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
$this->_lastaction=time();
} while($this->_code<200);
$this->_ready=true;
$syst=$this->systype();
if(!$syst) $this->SendMSG("Can't detect remote OS");
else {
if(preg_match("/win|dos|novell/i", $syst[0])) $this->OS_remote=FTP_OS_Windows;
elseif(preg_match("/os/i", $syst[0])) $this->OS_remote=FTP_OS_Mac;
elseif(preg_match("/(li|u)nix/i", $syst[0])) $this->OS_remote=FTP_OS_Unix;
else $this->OS_remote=FTP_OS_Mac;
$this->SendMSG("Remote OS: ".$this->OS_FullName[$this->OS_remote]);
}
if(!$this->features()) $this->SendMSG("Can't get features list. All supported - disabled");
else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
return TRUE;
}
function quit($force=false) {
if($this->_ready) {
if(!$this->_exec("QUIT") and !$force) return FALSE;
if(!$this->_checkCode() and !$force) return FALSE;
$this->_ready=false;
$this->SendMSG("Session finished");
}
$this->_quit();
return TRUE;
}
function login($user=NULL, $pass=NULL) {
if(!is_null($user)) $this->_login=$user;
else $this->_login="anonymous";
if(!is_null($pass)) $this->_password=$pass;
else $this->_password="anon@anon.com";
if(!$this->_exec("USER ".$this->_login, "login")) return FALSE;
if(!$this->_checkCode()) return FALSE;
if($this->_code!=230) {
if(!$this->_exec((($this->_code==331)?"PASS ":"ACCT ").$this->_password, "login")) return FALSE;
if(!$this->_checkCode()) return FALSE;
}
$this->SendMSG("Authentication succeeded");
if(empty($this->_features)) {
if(!$this->features()) $this->SendMSG("Can't get features list. All supported - disabled");
else $this->SendMSG("Supported features: ".implode(", ", array_keys($this->_features)));
}
return TRUE;
}
function pwd() {
if(!$this->_exec("PWD", "pwd")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return preg_replace("/^[0-9]{3} \"(.+)\".*$/s", "\\1", $this->_message);
}
function cdup() {
if(!$this->_exec("CDUP", "cdup")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return true;
}
function chdir($pathname) {
if(!$this->_exec("CWD ".$pathname, "chdir")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function rmdir($pathname) {
if(!$this->_exec("RMD ".$pathname, "rmdir")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function mkdir($pathname) {
if(!$this->_exec("MKD ".$pathname, "mkdir")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function rename($from, $to) {
if(!$this->_exec("RNFR ".$from, "rename")) return FALSE;
if(!$this->_checkCode()) return FALSE;
if($this->_code==350) {
if(!$this->_exec("RNTO ".$to, "rename")) return FALSE;
if(!$this->_checkCode()) return FALSE;
} else return FALSE;
return TRUE;
}
function filesize($pathname) {
if(!isset($this->_features["SIZE"])) {
$this->PushError("filesize", "not supported by server");
return FALSE;
}
if(!$this->_exec("SIZE ".$pathname, "filesize")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return preg_replace("/^[0-9]{3} ([0-9]+).*$/s", "\\1", $this->_message);
}
function abort() {
if(!$this->_exec("ABOR", "abort")) return FALSE;
if(!$this->_checkCode()) {
if($this->_code!=426) return FALSE;
if(!$this->_readmsg("abort")) return FALSE;
if(!$this->_checkCode()) return FALSE;
}
return true;
}
function mdtm($pathname) {
if(!isset($this->_features["MDTM"])) {
$this->PushError("mdtm", "not supported by server");
return FALSE;
}
if(!$this->_exec("MDTM ".$pathname, "mdtm")) return FALSE;
if(!$this->_checkCode()) return FALSE;
$mdtm = preg_replace("/^[0-9]{3} ([0-9]+).*$/s", "\\1", $this->_message);
$date = sscanf($mdtm, "%4d%2d%2d%2d%2d%2d");
$timestamp = mktime($date[3], $date[4], $date[5], $date[1], $date[2], $date[0]);
return $timestamp;
}
function systype() {
if(!$this->_exec("SYST", "systype")) return FALSE;
if(!$this->_checkCode()) return FALSE;
$DATA = explode(" ", $this->_message);
return array($DATA[1], $DATA[3]);
}
function delete($pathname) {
if(!$this->_exec("DELE ".$pathname, "delete")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function site($command, $fnction="site") {
if(!$this->_exec("SITE ".$command, $fnction)) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function chmod($pathname, $mode) {
if(!$this->site( sprintf('CHMOD %o %s', $mode, $pathname), "chmod")) return FALSE;
return TRUE;
}
function restore($from) {
if(!isset($this->_features["REST"])) {
$this->PushError("restore", "not supported by server");
return FALSE;
}
if($this->_curtype!=FTP_BINARY) {
$this->PushError("restore", "can't restore in ASCII mode");
return FALSE;
}
if(!$this->_exec("REST ".$from, "resore")) return FALSE;
if(!$this->_checkCode()) return FALSE;
return TRUE;
}
function features() {
if(!$this->_exec("FEAT", "features")) return FALSE;
if(!$this->_checkCode()) return FALSE;
$f=preg_split("/[".CRLF."]+/", preg_replace("/[0-9]{3}[ -].*[".CRLF."]+/", "", $this->_message), -1, PREG_SPLIT_NO_EMPTY);
$this->_features=array();
foreach($f as $k=>$v) {
$v=explode(" ", trim($v));
$this->_features[array_shift($v)]=$v;
}
return true;
}
function rawlist($pathname="", $arg="") {
return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "LIST", "rawlist");
}
function nlist($pathname="", $arg="") {
return $this->_list(($arg?" ".$arg:"").($pathname?" ".$pathname:""), "NLST", "nlist");
}
function is_exists($pathname) {
return $this->file_exists($pathname);
}
function file_exists($pathname) {
$exists=true;
if(!$this->_exec("RNFR ".$pathname, "rename")) $exists=FALSE;
else {
if(!$this->_checkCode()) $exists=FALSE;
$this->abort();
}
if($exists) $this->SendMSG("Remote file ".$pathname." exists");
else $this->SendMSG("Remote file ".$pathname." does not exist");
return $exists;
}
function fget($fp, $remotefile,$rest=0) {
if($this->_can_restore and $rest!=0) fseek($fp, $rest);
$pi=pathinfo($remotefile);
if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
else $mode=FTP_BINARY;
if(!$this->_data_prepare($mode)) {
return FALSE;
}
if($this->_can_restore and $rest!=0) $this->restore($rest);
if(!$this->_exec("RETR ".$remotefile, "get")) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
$out=$this->_data_read($mode, $fp);
$this->_data_close();
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
return $out;
}
function get($remotefile, $localfile=NULL, $rest=0) {
if(is_null($localfile)) $localfile=$remotefile;
if (@file_exists($localfile)) $this->SendMSG("Warning : local file will be overwritten");
$fp = @fopen($localfile, "w");
if (!$fp) {
$this->PushError("get","can't open local file", "Cannot create \"".$localfile."\"");
return FALSE;
}
if($this->_can_restore and $rest!=0) fseek($fp, $rest);
$pi=pathinfo($remotefile);
if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
else $mode=FTP_BINARY;
if(!$this->_data_prepare($mode)) {
fclose($fp);
return FALSE;
}
if($this->_can_restore and $rest!=0) $this->restore($rest);
if(!$this->_exec("RETR ".$remotefile, "get")) {
$this->_data_close();
fclose($fp);
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
fclose($fp);
return FALSE;
}
$out=$this->_data_read($mode, $fp);
fclose($fp);
$this->_data_close();
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
return $out;
}
function fput($remotefile, $fp) {
if($this->_can_restore and $rest!=0) fseek($fp, $rest);
$pi=pathinfo($remotefile);
if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
else $mode=FTP_BINARY;
if(!$this->_data_prepare($mode)) {
return FALSE;
}
if($this->_can_restore and $rest!=0) $this->restore($rest);
if(!$this->_exec("STOR ".$remotefile, "put")) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
$ret=$this->_data_write($mode, $fp);
$this->_data_close();
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
return $ret;
}
function put($localfile, $remotefile=NULL, $rest=0) {
if(is_null($remotefile)) $remotefile=$localfile;
if (!file_exists($localfile)) {
$this->PushError("put","can't open local file", "No such file or directory \"".$localfile."\"");
return FALSE;
}
$fp = @fopen($localfile, "r");
if (!$fp) {
$this->PushError("put","can't open local file", "Cannot read file \"".$localfile."\"");
return FALSE;
}
if($this->_can_restore and $rest!=0) fseek($fp, $rest);
$pi=pathinfo($localfile);
if($this->_type==FTP_ASCII or ($this->_type==FTP_AUTOASCII and in_array(strtoupper($pi["extension"]), $this->AutoAsciiExt))) $mode=FTP_ASCII;
else $mode=FTP_BINARY;
if(!$this->_data_prepare($mode)) {
fclose($fp);
return FALSE;
}
if($this->_can_restore and $rest!=0) $this->restore($rest);
if(!$this->_exec("STOR ".$remotefile, "put")) {
$this->_data_close();
fclose($fp);
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
fclose($fp);
return FALSE;
}
$ret=$this->_data_write($mode, $fp);
fclose($fp);
$this->_data_close();
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
return $ret;
}
function mput($local=".", $remote=NULL, $continious=false) {
$local=realpath($local);
if(!@file_exists($local)) {
$this->PushError("mput","can't open local folder", "Cannot stat folder \"".$local."\"");
return FALSE;
}
if(!is_dir($local)) return $this->put($local, $remote);
if(empty($remote)) $remote=".";
elseif(!$this->file_exists($remote) and !$this->mkdir($remote)) return FALSE;
if($handle = opendir($local)) {
$list=array();
while (false !== ($file = readdir($handle))) {
if ($file != "." && $file != "..") $list[]=$file;
}
closedir($handle);
} else {
$this->PushError("mput","can't open local folder", "Cannot read folder \"".$local."\"");
return FALSE;
}
if(empty($list)) return TRUE;
$ret=true;
foreach($list as $el) {
if(is_dir($local."/".$el)) $t=$this->mput($local."/".$el, $remote."/".$el);
else $t=$this->put($local."/".$el, $remote."/".$el);
if(!$t) {
$ret=FALSE;
if(!$continious) break;
}
}
return $ret;
}
function mget($remote, $local=".", $continious=false) {
$list=$this->rawlist($remote, "-lA");
if($list===false) {
$this->PushError("mget","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
return FALSE;
}
if(empty($list)) return true;
if(!@file_exists($local)) {
if(!@mkdir($local)) {
$this->PushError("mget","can't create local folder", "Cannot create folder \"".$local."\"");
return FALSE;
}
}
foreach($list as $k=>$v) {
$list[$k]=$this->parselisting($v);
if( ! $list[$k] or $list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
}
$ret=true;
foreach($list as $el) {
if($el["type"]=="d") {
if(!$this->mget($remote."/".$el["name"], $local."/".$el["name"], $continious)) {
$this->PushError("mget", "can't copy folder", "Can't copy remote folder \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
$ret=false;
if(!$continious) break;
}
} else {
if(!$this->get($remote."/".$el["name"], $local."/".$el["name"])) {
$this->PushError("mget", "can't copy file", "Can't copy remote file \"".$remote."/".$el["name"]."\" to local \"".$local."/".$el["name"]."\"");
$ret=false;
if(!$continious) break;
}
}
@chmod($local."/".$el["name"], $el["perms"]);
$t=strtotime($el["date"]);
if($t!==-1 and $t!==false) @touch($local."/".$el["name"], $t);
}
return $ret;
}
function mdel($remote, $continious=false) {
$list=$this->rawlist($remote, "-la");
if($list===false) {
$this->PushError("mdel","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
return false;
}
foreach($list as $k=>$v) {
$list[$k]=$this->parselisting($v);
if( ! $list[$k] or $list[$k]["name"]=="." or $list[$k]["name"]=="..") unset($list[$k]);
}
$ret=true;
foreach($list as $el) {
if ( empty($el) )
continue;
if($el["type"]=="d") {
if(!$this->mdel($remote."/".$el["name"], $continious)) {
$ret=false;
if(!$continious) break;
}
} else {
if (!$this->delete($remote."/".$el["name"])) {
$this->PushError("mdel", "can't delete file", "Can't delete remote file \"".$remote."/".$el["name"]."\"");
$ret=false;
if(!$continious) break;
}
}
}
if(!$this->rmdir($remote)) {
$this->PushError("mdel", "can't delete folder", "Can't delete remote folder \"".$remote."/".$el["name"]."\"");
$ret=false;
}
return $ret;
}
function mmkdir($dir, $mode = 0777) {
if(empty($dir)) return FALSE;
if($this->is_exists($dir) or $dir == "/" ) return TRUE;
if(!$this->mmkdir(dirname($dir), $mode)) return false;
$r=$this->mkdir($dir, $mode);
$this->chmod($dir,$mode);
return $r;
}
function glob($pattern, $handle=NULL) {
$path=$output=null;
if(PHP_OS=='WIN32') $slash='\\';
else $slash='/';
$lastpos=strrpos($pattern,$slash);
if(!($lastpos===false)) {
$path=substr($pattern,0,-$lastpos-1);
$pattern=substr($pattern,$lastpos);
} else $path=getcwd();
if(is_array($handle) and !empty($handle)) {
while($dir=each($handle)) {
if($this->glob_pattern_match($pattern,$dir))
$output[]=$dir;
}
} else {
$handle=@opendir($path);
if($handle===false) return false;
while($dir=readdir($handle)) {
if($this->glob_pattern_match($pattern,$dir))
$output[]=$dir;
}
closedir($handle);
}
if(is_array($output)) return $output;
return false;
}
function glob_pattern_match($pattern,$string) {
$out=null;
$chunks=explode(';',$pattern);
foreach($chunks as $pattern) {
$escape=array('$','^','.','{','}','(',')','[',']','|');
while(strpos($pattern,'**')!==false)
$pattern=str_replace('**','*',$pattern);
foreach($escape as $probe)
$pattern=str_replace($probe,"\\$probe",$pattern);
$pattern=str_replace('?*','*',
str_replace('*?','*',
str_replace('*',".*",
str_replace('?','.{1,1}',$pattern))));
$out[]=$pattern;
}
if(count($out)==1) return($this->glob_regexp("^$out[0]$",$string));
else {
foreach($out as $tester)
if($this->my_regexp("^$tester$",$string)) return true;
}
return false;
}
function glob_regexp($pattern,$probe) {
$sensitive=(PHP_OS!='WIN32');
return ($sensitive?
preg_match( '/' . preg_quote( $pattern, '/' ) . '/', $probe ) :
preg_match( '/' . preg_quote( $pattern, '/' ) . '/i', $probe )
);
}
function dirlist($remote) {
$list=$this->rawlist($remote, "-la");
if($list===false) {
$this->PushError("dirlist","can't read remote folder list", "Can't read remote folder \"".$remote."\" contents");
return false;
}
$dirlist = array();
foreach($list as $k=>$v) {
$entry=$this->parselisting($v);
if ( empty($entry) )
continue;
if($entry["name"]=="." or $entry["name"]=="..")
continue;
$dirlist[$entry['name']] = $entry;
}
return $dirlist;
}
// <!-- --------------------------------------------------------------------------------------- -->
// <!-- Private functions -->
// <!-- --------------------------------------------------------------------------------------- -->
function _checkCode() {
return ($this->_code<400 and $this->_code>0);
}
function _list($arg="", $cmd="LIST", $fnction="_list") {
if(!$this->_data_prepare()) return false;
if(!$this->_exec($cmd.$arg, $fnction)) {
$this->_data_close();
return FALSE;
}
if(!$this->_checkCode()) {
$this->_data_close();
return FALSE;
}
$out="";
if($this->_code<200) {
$out=$this->_data_read();
$this->_data_close();
if(!$this->_readmsg()) return FALSE;
if(!$this->_checkCode()) return FALSE;
if($out === FALSE ) return FALSE;
$out=preg_split("/[".CRLF."]+/", $out, -1, PREG_SPLIT_NO_EMPTY);
// $this->SendMSG(implode($this->_eol_code[$this->OS_local], $out));
}
return $out;
}
// <!-- --------------------------------------------------------------------------------------- -->
// <!-- Partie : gestion des erreurs -->
// <!-- --------------------------------------------------------------------------------------- -->
// Gnre une erreur pour traitement externe la classe
function PushError($fctname,$msg,$desc=false){
$error=array();
$error['time']=time();
$error['fctname']=$fctname;
$error['msg']=$msg;
$error['desc']=$desc;
if($desc) $tmp=' ('.$desc.')'; else $tmp='';
$this->SendMSG($fctname.': '.$msg.$tmp);
return(array_push($this->_error_array,$error));
}
// Rcupre une erreur externe
function PopError(){
if(count($this->_error_array)) return(array_pop($this->_error_array));
else return(false);
}
}
$mod_sockets = extension_loaded( 'sockets' );
if ( ! $mod_sockets && function_exists( 'dl' ) && is_callable( 'dl' ) ) {
$prefix = ( PHP_SHLIB_SUFFIX == 'dll' ) ? 'php_' : '';
@dl( $prefix . 'sockets.' . PHP_SHLIB_SUFFIX );
$mod_sockets = extension_loaded( 'sockets' );
}
require_once dirname( __FILE__ ) . "/class-ftp-" . ( $mod_sockets ? "sockets" : "pure" ) . ".php";

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,125 @@
<?php
/**
* Taxonomy API: Walker_Category_Checklist class
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Core walker class to output an unordered list of category checkbox input elements.
*
* @since 2.5.1
*
* @see Walker
* @see wp_category_checklist()
* @see wp_terms_checklist()
*/
class Walker_Category_Checklist extends Walker {
public $tree_type = 'category';
public $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this
/**
* Starts the list before the elements are added.
*
* @see Walker:start_lvl()
*
* @since 2.5.1
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of category. Used for tab indentation.
* @param array $args An array of arguments. @see wp_terms_checklist()
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent<ul class='children'>\n";
}
/**
* Ends the list of after the elements are added.
*
* @see Walker::end_lvl()
*
* @since 2.5.1
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of category. Used for tab indentation.
* @param array $args An array of arguments. @see wp_terms_checklist()
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat("\t", $depth);
$output .= "$indent</ul>\n";
}
/**
* Start the element output.
*
* @see Walker::start_el()
*
* @since 2.5.1
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $category The current term object.
* @param int $depth Depth of the term in reference to parents. Default 0.
* @param array $args An array of arguments. @see wp_terms_checklist()
* @param int $id ID of the current term.
*/
public function start_el( &$output, $category, $depth = 0, $args = array(), $id = 0 ) {
if ( empty( $args['taxonomy'] ) ) {
$taxonomy = 'category';
} else {
$taxonomy = $args['taxonomy'];
}
if ( $taxonomy == 'category' ) {
$name = 'post_category';
} else {
$name = 'tax_input[' . $taxonomy . ']';
}
$args['popular_cats'] = empty( $args['popular_cats'] ) ? array() : $args['popular_cats'];
$class = in_array( $category->term_id, $args['popular_cats'] ) ? ' class="popular-category"' : '';
$args['selected_cats'] = empty( $args['selected_cats'] ) ? array() : $args['selected_cats'];
if ( ! empty( $args['list_only'] ) ) {
$aria_cheched = 'false';
$inner_class = 'category';
if ( in_array( $category->term_id, $args['selected_cats'] ) ) {
$inner_class .= ' selected';
$aria_cheched = 'true';
}
/** This filter is documented in wp-includes/category-template.php */
$output .= "\n" . '<li' . $class . '>' .
'<div class="' . $inner_class . '" data-term-id=' . $category->term_id .
' tabindex="0" role="checkbox" aria-checked="' . $aria_cheched . '">' .
esc_html( apply_filters( 'the_category', $category->name ) ) . '</div>';
} else {
/** This filter is documented in wp-includes/category-template.php */
$output .= "\n<li id='{$taxonomy}-{$category->term_id}'$class>" .
'<label class="selectit"><input value="' . $category->term_id . '" type="checkbox" name="'.$name.'[]" id="in-'.$taxonomy.'-' . $category->term_id . '"' .
checked( in_array( $category->term_id, $args['selected_cats'] ), true, false ) .
disabled( empty( $args['disabled'] ), false, false ) . ' /> ' .
esc_html( apply_filters( 'the_category', $category->name ) ) . '</label>';
}
}
/**
* Ends the element output, if needed.
*
* @see Walker::end_el()
*
* @since 2.5.1
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $category The current term object.
* @param int $depth Depth of the term in reference to parents. Default 0.
* @param array $args An array of arguments. @see wp_terms_checklist()
*/
public function end_el( &$output, $category, $depth = 0, $args = array() ) {
$output .= "</li>\n";
}
}

View File

@@ -0,0 +1,117 @@
<?php
/**
* Navigation Menu API: Walker_Nav_Menu_Checklist class
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Create HTML list of nav menu input items.
*
* @since 3.0.0
* @uses Walker_Nav_Menu
*/
class Walker_Nav_Menu_Checklist extends Walker_Nav_Menu {
/**
*
* @param array $fields
*/
public function __construct( $fields = false ) {
if ( $fields ) {
$this->db_fields = $fields;
}
}
/**
* Starts the list before the elements are added.
*
* @see Walker_Nav_Menu::start_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
* @param array $args Not used.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent<ul class='children'>\n";
}
/**
* Ends the list of after the elements are added.
*
* @see Walker_Nav_Menu::end_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference. Used to append additional content.
* @param int $depth Depth of page. Used for padding.
* @param array $args Not used.
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {
$indent = str_repeat( "\t", $depth );
$output .= "\n$indent</ul>";
}
/**
* Start the element output.
*
* @see Walker_Nav_Menu::start_el()
*
* @since 3.0.0
*
* @global int $_nav_menu_placeholder
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args Not used.
* @param int $id Not used.
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
global $_nav_menu_placeholder;
$_nav_menu_placeholder = ( 0 > $_nav_menu_placeholder ) ? intval($_nav_menu_placeholder) - 1 : -1;
$possible_object_id = isset( $item->post_type ) && 'nav_menu_item' == $item->post_type ? $item->object_id : $_nav_menu_placeholder;
$possible_db_id = ( ! empty( $item->ID ) ) && ( 0 < $possible_object_id ) ? (int) $item->ID : 0;
$indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
$output .= $indent . '<li>';
$output .= '<label class="menu-item-title">';
$output .= '<input type="checkbox" class="menu-item-checkbox';
if ( ! empty( $item->front_or_home ) )
$output .= ' add-to-top';
$output .= '" name="menu-item[' . $possible_object_id . '][menu-item-object-id]" value="'. esc_attr( $item->object_id ) .'" /> ';
if ( ! empty( $item->label ) ) {
$title = $item->label;
} elseif ( isset( $item->post_type ) ) {
/** This filter is documented in wp-includes/post-template.php */
$title = apply_filters( 'the_title', $item->post_title, $item->ID );
if ( ! empty( $item->front_or_home ) && _x( 'Home', 'nav menu home label' ) !== $title )
$title = sprintf( _x( 'Home: %s', 'nav menu front page title' ), $title );
}
$output .= isset( $title ) ? esc_html( $title ) : esc_html( $item->title );
$output .= '</label>';
// Menu item hidden fields
$output .= '<input type="hidden" class="menu-item-db-id" name="menu-item[' . $possible_object_id . '][menu-item-db-id]" value="' . $possible_db_id . '" />';
$output .= '<input type="hidden" class="menu-item-object" name="menu-item[' . $possible_object_id . '][menu-item-object]" value="'. esc_attr( $item->object ) .'" />';
$output .= '<input type="hidden" class="menu-item-parent-id" name="menu-item[' . $possible_object_id . '][menu-item-parent-id]" value="'. esc_attr( $item->menu_item_parent ) .'" />';
$output .= '<input type="hidden" class="menu-item-type" name="menu-item[' . $possible_object_id . '][menu-item-type]" value="'. esc_attr( $item->type ) .'" />';
$output .= '<input type="hidden" class="menu-item-title" name="menu-item[' . $possible_object_id . '][menu-item-title]" value="'. esc_attr( $item->title ) .'" />';
$output .= '<input type="hidden" class="menu-item-url" name="menu-item[' . $possible_object_id . '][menu-item-url]" value="'. esc_attr( $item->url ) .'" />';
$output .= '<input type="hidden" class="menu-item-target" name="menu-item[' . $possible_object_id . '][menu-item-target]" value="'. esc_attr( $item->target ) .'" />';
$output .= '<input type="hidden" class="menu-item-attr_title" name="menu-item[' . $possible_object_id . '][menu-item-attr_title]" value="'. esc_attr( $item->attr_title ) .'" />';
$output .= '<input type="hidden" class="menu-item-classes" name="menu-item[' . $possible_object_id . '][menu-item-classes]" value="'. esc_attr( implode( ' ', $item->classes ) ) .'" />';
$output .= '<input type="hidden" class="menu-item-xfn" name="menu-item[' . $possible_object_id . '][menu-item-xfn]" value="'. esc_attr( $item->xfn ) .'" />';
}
} // Walker_Nav_Menu_Checklist

View File

@@ -0,0 +1,243 @@
<?php
/**
* Navigation Menu API: Walker_Nav_Menu_Edit class
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Create HTML list of nav menu input items.
*
* @package WordPress
* @since 3.0.0
* @uses Walker_Nav_Menu
*/
class Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
/**
* Starts the list before the elements are added.
*
* @see Walker_Nav_Menu::start_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args Not used.
*/
public function start_lvl( &$output, $depth = 0, $args = array() ) {}
/**
* Ends the list of after the elements are added.
*
* @see Walker_Nav_Menu::end_lvl()
*
* @since 3.0.0
*
* @param string $output Passed by reference.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args Not used.
*/
public function end_lvl( &$output, $depth = 0, $args = array() ) {}
/**
* Start the element output.
*
* @see Walker_Nav_Menu::start_el()
* @since 3.0.0
*
* @global int $_wp_nav_menu_max_depth
*
* @param string $output Passed by reference. Used to append additional content.
* @param object $item Menu item data object.
* @param int $depth Depth of menu item. Used for padding.
* @param array $args Not used.
* @param int $id Not used.
*/
public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
global $_wp_nav_menu_max_depth;
$_wp_nav_menu_max_depth = $depth > $_wp_nav_menu_max_depth ? $depth : $_wp_nav_menu_max_depth;
ob_start();
$item_id = esc_attr( $item->ID );
$removed_args = array(
'action',
'customlink-tab',
'edit-menu-item',
'menu-item',
'page-tab',
'_wpnonce',
);
$original_title = '';
if ( 'taxonomy' == $item->type ) {
$original_title = get_term_field( 'name', $item->object_id, $item->object, 'raw' );
if ( is_wp_error( $original_title ) )
$original_title = false;
} elseif ( 'post_type' == $item->type ) {
$original_object = get_post( $item->object_id );
$original_title = get_the_title( $original_object->ID );
} elseif ( 'post_type_archive' == $item->type ) {
$original_object = get_post_type_object( $item->object );
if ( $original_object ) {
$original_title = $original_object->labels->archives;
}
}
$classes = array(
'menu-item menu-item-depth-' . $depth,
'menu-item-' . esc_attr( $item->object ),
'menu-item-edit-' . ( ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? 'active' : 'inactive'),
);
$title = $item->title;
if ( ! empty( $item->_invalid ) ) {
$classes[] = 'menu-item-invalid';
/* translators: %s: title of menu item which is invalid */
$title = sprintf( __( '%s (Invalid)' ), $item->title );
} elseif ( isset( $item->post_status ) && 'draft' == $item->post_status ) {
$classes[] = 'pending';
/* translators: %s: title of menu item in draft status */
$title = sprintf( __('%s (Pending)'), $item->title );
}
$title = ( ! isset( $item->label ) || '' == $item->label ) ? $title : $item->label;
$submenu_text = '';
if ( 0 == $depth )
$submenu_text = 'style="display: none;"';
?>
<li id="menu-item-<?php echo $item_id; ?>" class="<?php echo implode(' ', $classes ); ?>">
<div class="menu-item-bar">
<div class="menu-item-handle">
<span class="item-title"><span class="menu-item-title"><?php echo esc_html( $title ); ?></span> <span class="is-submenu" <?php echo $submenu_text; ?>><?php _e( 'sub item' ); ?></span></span>
<span class="item-controls">
<span class="item-type"><?php echo esc_html( $item->type_label ); ?></span>
<span class="item-order hide-if-js">
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-up-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-up" aria-label="<?php esc_attr_e( 'Move up' ) ?>">&#8593;</a>
|
<a href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'move-down-menu-item',
'menu-item' => $item_id,
),
remove_query_arg($removed_args, admin_url( 'nav-menus.php' ) )
),
'move-menu_item'
);
?>" class="item-move-down" aria-label="<?php esc_attr_e( 'Move down' ) ?>">&#8595;</a>
</span>
<a class="item-edit" id="edit-<?php echo $item_id; ?>" href="<?php
echo ( isset( $_GET['edit-menu-item'] ) && $item_id == $_GET['edit-menu-item'] ) ? admin_url( 'nav-menus.php' ) : add_query_arg( 'edit-menu-item', $item_id, remove_query_arg( $removed_args, admin_url( 'nav-menus.php#menu-item-settings-' . $item_id ) ) );
?>" aria-label="<?php esc_attr_e( 'Edit menu item' ); ?>"><?php _e( 'Edit' ); ?></a>
</span>
</div>
</div>
<div class="menu-item-settings wp-clearfix" id="menu-item-settings-<?php echo $item_id; ?>">
<?php if ( 'custom' == $item->type ) : ?>
<p class="field-url description description-wide">
<label for="edit-menu-item-url-<?php echo $item_id; ?>">
<?php _e( 'URL' ); ?><br />
<input type="text" id="edit-menu-item-url-<?php echo $item_id; ?>" class="widefat code edit-menu-item-url" name="menu-item-url[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->url ); ?>" />
</label>
</p>
<?php endif; ?>
<p class="description description-wide">
<label for="edit-menu-item-title-<?php echo $item_id; ?>">
<?php _e( 'Navigation Label' ); ?><br />
<input type="text" id="edit-menu-item-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-title" name="menu-item-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->title ); ?>" />
</label>
</p>
<p class="field-title-attribute field-attr-title description description-wide">
<label for="edit-menu-item-attr-title-<?php echo $item_id; ?>">
<?php _e( 'Title Attribute' ); ?><br />
<input type="text" id="edit-menu-item-attr-title-<?php echo $item_id; ?>" class="widefat edit-menu-item-attr-title" name="menu-item-attr-title[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->post_excerpt ); ?>" />
</label>
</p>
<p class="field-link-target description">
<label for="edit-menu-item-target-<?php echo $item_id; ?>">
<input type="checkbox" id="edit-menu-item-target-<?php echo $item_id; ?>" value="_blank" name="menu-item-target[<?php echo $item_id; ?>]"<?php checked( $item->target, '_blank' ); ?> />
<?php _e( 'Open link in a new tab' ); ?>
</label>
</p>
<p class="field-css-classes description description-thin">
<label for="edit-menu-item-classes-<?php echo $item_id; ?>">
<?php _e( 'CSS Classes (optional)' ); ?><br />
<input type="text" id="edit-menu-item-classes-<?php echo $item_id; ?>" class="widefat code edit-menu-item-classes" name="menu-item-classes[<?php echo $item_id; ?>]" value="<?php echo esc_attr( implode(' ', $item->classes ) ); ?>" />
</label>
</p>
<p class="field-xfn description description-thin">
<label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
<?php _e( 'Link Relationship (XFN)' ); ?><br />
<input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
</label>
</p>
<p class="field-description description description-wide">
<label for="edit-menu-item-description-<?php echo $item_id; ?>">
<?php _e( 'Description' ); ?><br />
<textarea id="edit-menu-item-description-<?php echo $item_id; ?>" class="widefat edit-menu-item-description" rows="3" cols="20" name="menu-item-description[<?php echo $item_id; ?>]"><?php echo esc_html( $item->description ); // textarea_escaped ?></textarea>
<span class="description"><?php _e('The description will be displayed in the menu if the current theme supports it.'); ?></span>
</label>
</p>
<p class="field-move hide-if-no-js description description-wide">
<label>
<span><?php _e( 'Move' ); ?></span>
<a href="#" class="menus-move menus-move-up" data-dir="up"><?php _e( 'Up one' ); ?></a>
<a href="#" class="menus-move menus-move-down" data-dir="down"><?php _e( 'Down one' ); ?></a>
<a href="#" class="menus-move menus-move-left" data-dir="left"></a>
<a href="#" class="menus-move menus-move-right" data-dir="right"></a>
<a href="#" class="menus-move menus-move-top" data-dir="top"><?php _e( 'To the top' ); ?></a>
</label>
</p>
<div class="menu-item-actions description-wide submitbox">
<?php if ( 'custom' != $item->type && $original_title !== false ) : ?>
<p class="link-to-original">
<?php printf( __('Original: %s'), '<a href="' . esc_attr( $item->url ) . '">' . esc_html( $original_title ) . '</a>' ); ?>
</p>
<?php endif; ?>
<a class="item-delete submitdelete deletion" id="delete-<?php echo $item_id; ?>" href="<?php
echo wp_nonce_url(
add_query_arg(
array(
'action' => 'delete-menu-item',
'menu-item' => $item_id,
),
admin_url( 'nav-menus.php' )
),
'delete-menu_item_' . $item_id
); ?>"><?php _e( 'Remove' ); ?></a> <span class="meta-sep hide-if-no-js"> | </span> <a class="item-cancel submitcancel hide-if-no-js" id="cancel-<?php echo $item_id; ?>" href="<?php echo esc_url( add_query_arg( array( 'edit-menu-item' => $item_id, 'cancel' => time() ), admin_url( 'nav-menus.php' ) ) );
?>#menu-item-settings-<?php echo $item_id; ?>"><?php _e('Cancel'); ?></a>
</div>
<input class="menu-item-data-db-id" type="hidden" name="menu-item-db-id[<?php echo $item_id; ?>]" value="<?php echo $item_id; ?>" />
<input class="menu-item-data-object-id" type="hidden" name="menu-item-object-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object_id ); ?>" />
<input class="menu-item-data-object" type="hidden" name="menu-item-object[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->object ); ?>" />
<input class="menu-item-data-parent-id" type="hidden" name="menu-item-parent-id[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_item_parent ); ?>" />
<input class="menu-item-data-position" type="hidden" name="menu-item-position[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->menu_order ); ?>" />
<input class="menu-item-data-type" type="hidden" name="menu-item-type[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->type ); ?>" />
</div><!-- .menu-item-settings-->
<ul class="menu-item-transport"></ul>
<?php
$output .= ob_get_clean();
}
} // Walker_Nav_Menu_Edit

View File

@@ -0,0 +1,794 @@
<?php
/**
* List Table API: WP_Comments_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying comments in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Comments_List_Table extends WP_List_Table {
public $checkbox = true;
public $pending_count = array();
public $extra_items;
private $user_can;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @global int $post_id
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
global $post_id;
$post_id = isset( $_REQUEST['p'] ) ? absint( $_REQUEST['p'] ) : 0;
if ( get_option( 'show_avatars' ) ) {
add_filter( 'comment_author', array( $this, 'floated_admin_avatar' ), 10, 2 );
}
parent::__construct( array(
'plural' => 'comments',
'singular' => 'comment',
'ajax' => true,
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
}
public function floated_admin_avatar( $name, $comment_ID ) {
$comment = get_comment( $comment_ID );
$avatar = get_avatar( $comment, 32, 'mystery' );
return "$avatar $name";
}
/**
* @return bool
*/
public function ajax_user_can() {
return current_user_can('edit_posts');
}
/**
*
* @global int $post_id
* @global string $comment_status
* @global string $search
* @global string $comment_type
*/
public function prepare_items() {
global $post_id, $comment_status, $search, $comment_type;
$comment_status = isset( $_REQUEST['comment_status'] ) ? $_REQUEST['comment_status'] : 'all';
if ( !in_array( $comment_status, array( 'all', 'moderated', 'approved', 'spam', 'trash' ) ) )
$comment_status = 'all';
$comment_type = !empty( $_REQUEST['comment_type'] ) ? $_REQUEST['comment_type'] : '';
$search = ( isset( $_REQUEST['s'] ) ) ? $_REQUEST['s'] : '';
$post_type = ( isset( $_REQUEST['post_type'] ) ) ? sanitize_key( $_REQUEST['post_type'] ) : '';
$user_id = ( isset( $_REQUEST['user_id'] ) ) ? $_REQUEST['user_id'] : '';
$orderby = ( isset( $_REQUEST['orderby'] ) ) ? $_REQUEST['orderby'] : '';
$order = ( isset( $_REQUEST['order'] ) ) ? $_REQUEST['order'] : '';
$comments_per_page = $this->get_per_page( $comment_status );
$doing_ajax = defined( 'DOING_AJAX' ) && DOING_AJAX;
if ( isset( $_REQUEST['number'] ) ) {
$number = (int) $_REQUEST['number'];
}
else {
$number = $comments_per_page + min( 8, $comments_per_page ); // Grab a few extra
}
$page = $this->get_pagenum();
if ( isset( $_REQUEST['start'] ) ) {
$start = $_REQUEST['start'];
} else {
$start = ( $page - 1 ) * $comments_per_page;
}
if ( $doing_ajax && isset( $_REQUEST['offset'] ) ) {
$start += $_REQUEST['offset'];
}
$status_map = array(
'moderated' => 'hold',
'approved' => 'approve',
'all' => '',
);
$args = array(
'status' => isset( $status_map[$comment_status] ) ? $status_map[$comment_status] : $comment_status,
'search' => $search,
'user_id' => $user_id,
'offset' => $start,
'number' => $number,
'post_id' => $post_id,
'type' => $comment_type,
'orderby' => $orderby,
'order' => $order,
'post_type' => $post_type,
);
$_comments = get_comments( $args );
if ( is_array( $_comments ) ) {
update_comment_cache( $_comments );
$this->items = array_slice( $_comments, 0, $comments_per_page );
$this->extra_items = array_slice( $_comments, $comments_per_page );
$_comment_post_ids = array_unique( wp_list_pluck( $_comments, 'comment_post_ID' ) );
$this->pending_count = get_pending_comments_num( $_comment_post_ids );
}
$total_comments = get_comments( array_merge( $args, array(
'count' => true,
'offset' => 0,
'number' => 0
) ) );
$this->set_pagination_args( array(
'total_items' => $total_comments,
'per_page' => $comments_per_page,
) );
}
/**
*
* @param string $comment_status
* @return int
*/
public function get_per_page( $comment_status = 'all' ) {
$comments_per_page = $this->get_items_per_page( 'edit_comments_per_page' );
/**
* Filter the number of comments listed per page in the comments list table.
*
* @since 2.6.0
*
* @param int $comments_per_page The number of comments to list per page.
* @param string $comment_status The comment status name. Default 'All'.
*/
return apply_filters( 'comments_per_page', $comments_per_page, $comment_status );
}
/**
*
* @global string $comment_status
*/
public function no_items() {
global $comment_status;
if ( 'moderated' === $comment_status ) {
_e( 'No comments awaiting moderation.' );
} else {
_e( 'No comments found.' );
}
}
/**
*
* @global int $post_id
* @global string $comment_status
* @global string $comment_type
*/
protected function get_views() {
global $post_id, $comment_status, $comment_type;
$status_links = array();
$num_comments = ( $post_id ) ? wp_count_comments( $post_id ) : wp_count_comments();
//, number_format_i18n($num_comments->moderated) ), "<span class='comment-count'>" . number_format_i18n($num_comments->moderated) . "</span>"),
//, number_format_i18n($num_comments->spam) ), "<span class='spam-comment-count'>" . number_format_i18n($num_comments->spam) . "</span>")
$stati = array(
/* translators: %s: all comments count */
'all' => _nx_noop(
'All <span class="count">(%s)</span>',
'All <span class="count">(%s)</span>',
'comments'
), // singular not used
/* translators: %s: pending comments count */
'moderated' => _nx_noop(
'Pending <span class="count">(%s)</span>',
'Pending <span class="count">(%s)</span>',
'comments'
),
/* translators: %s: approved comments count */
'approved' => _nx_noop(
'Approved <span class="count">(%s)</span>',
'Approved <span class="count">(%s)</span>',
'comments'
),
/* translators: %s: spam comments count */
'spam' => _nx_noop(
'Spam <span class="count">(%s)</span>',
'Spam <span class="count">(%s)</span>',
'comments'
),
/* translators: %s: trashed comments count */
'trash' => _nx_noop(
'Trash <span class="count">(%s)</span>',
'Trash <span class="count">(%s)</span>',
'comments'
)
);
if ( !EMPTY_TRASH_DAYS )
unset($stati['trash']);
$link = admin_url( 'edit-comments.php' );
if ( !empty($comment_type) && 'all' != $comment_type )
$link = add_query_arg( 'comment_type', $comment_type, $link );
foreach ( $stati as $status => $label ) {
$class = ( $status === $comment_status ) ? ' class="current"' : '';
if ( !isset( $num_comments->$status ) )
$num_comments->$status = 10;
$link = add_query_arg( 'comment_status', $status, $link );
if ( $post_id )
$link = add_query_arg( 'p', absint( $post_id ), $link );
/*
// I toyed with this, but decided against it. Leaving it in here in case anyone thinks it is a good idea. ~ Mark
if ( !empty( $_REQUEST['s'] ) )
$link = add_query_arg( 's', esc_attr( wp_unslash( $_REQUEST['s'] ) ), $link );
*/
$status_links[ $status ] = "<a href='$link'$class>" . sprintf(
translate_nooped_plural( $label, $num_comments->$status ),
sprintf( '<span class="%s-count">%s</span>',
( 'moderated' === $status ) ? 'pending' : $status,
number_format_i18n( $num_comments->$status )
)
) . '</a>';
}
/**
* Filter the comment status links.
*
* @since 2.5.0
*
* @param array $status_links An array of fully-formed status links. Default 'All'.
* Accepts 'All', 'Pending', 'Approved', 'Spam', and 'Trash'.
*/
return apply_filters( 'comment_status_links', $status_links );
}
/**
*
* @global string $comment_status
*
* @return array
*/
protected function get_bulk_actions() {
global $comment_status;
$actions = array();
if ( in_array( $comment_status, array( 'all', 'approved' ) ) )
$actions['unapprove'] = __( 'Unapprove' );
if ( in_array( $comment_status, array( 'all', 'moderated' ) ) )
$actions['approve'] = __( 'Approve' );
if ( in_array( $comment_status, array( 'all', 'moderated', 'approved', 'trash' ) ) )
$actions['spam'] = _x( 'Mark as Spam', 'comment' );
if ( 'trash' === $comment_status ) {
$actions['untrash'] = __( 'Restore' );
} elseif ( 'spam' === $comment_status ) {
$actions['unspam'] = _x( 'Not Spam', 'comment' );
}
if ( in_array( $comment_status, array( 'trash', 'spam' ) ) || !EMPTY_TRASH_DAYS )
$actions['delete'] = __( 'Delete Permanently' );
else
$actions['trash'] = __( 'Move to Trash' );
return $actions;
}
/**
*
* @global string $comment_status
* @global string $comment_type
*
* @param string $which
*/
protected function extra_tablenav( $which ) {
global $comment_status, $comment_type;
?>
<div class="alignleft actions">
<?php
if ( 'top' === $which ) {
?>
<label class="screen-reader-text" for="filter-by-comment-type"><?php _e( 'Filter by comment type' ); ?></label>
<select id="filter-by-comment-type" name="comment_type">
<option value=""><?php _e( 'All comment types' ); ?></option>
<?php
/**
* Filter the comment types dropdown menu.
*
* @since 2.7.0
*
* @param array $comment_types An array of comment types. Accepts 'Comments', 'Pings'.
*/
$comment_types = apply_filters( 'admin_comment_types_dropdown', array(
'comment' => __( 'Comments' ),
'pings' => __( 'Pings' ),
) );
foreach ( $comment_types as $type => $label )
echo "\t" . '<option value="' . esc_attr( $type ) . '"' . selected( $comment_type, $type, false ) . ">$label</option>\n";
?>
</select>
<?php
/**
* Fires just before the Filter submit button for comment types.
*
* @since 3.5.0
*/
do_action( 'restrict_manage_comments' );
submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
}
if ( ( 'spam' === $comment_status || 'trash' === $comment_status ) && current_user_can( 'moderate_comments' ) ) {
wp_nonce_field( 'bulk-destroy', '_destroy_nonce' );
$title = ( 'spam' === $comment_status ) ? esc_attr__( 'Empty Spam' ) : esc_attr__( 'Empty Trash' );
submit_button( $title, 'apply', 'delete_all', false );
}
/**
* Fires after the Filter submit button for comment types.
*
* @since 2.5.0
*
* @param string $comment_status The comment status name. Default 'All'.
*/
do_action( 'manage_comments_nav', $comment_status );
echo '</div>';
}
/**
* @return string|false
*/
public function current_action() {
if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
return 'delete_all';
return parent::current_action();
}
/**
*
* @global int $post_id
*
* @return array
*/
public function get_columns() {
global $post_id;
$columns = array();
if ( $this->checkbox )
$columns['cb'] = '<input type="checkbox" />';
$columns['author'] = __( 'Author' );
$columns['comment'] = _x( 'Comment', 'column name' );
if ( ! $post_id ) {
/* translators: column name or table row header */
$columns['response'] = __( 'In Response To' );
}
$columns['date'] = _x( 'Submitted On', 'column name' );
return $columns;
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'author' => 'comment_author',
'response' => 'comment_post_ID',
'date' => 'comment_date'
);
}
/**
* Get the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'comment'.
*/
protected function get_default_primary_column_name() {
return 'comment';
}
/**
* @access public
*/
public function display() {
wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
$this->display_tablenav( 'top' );
$this->screen->render_screen_reader_content( 'heading_list' );
?>
<table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
<thead>
<tr>
<?php $this->print_column_headers(); ?>
</tr>
</thead>
<tbody id="the-comment-list" data-wp-lists="list:comment">
<?php $this->display_rows_or_placeholder(); ?>
</tbody>
<tbody id="the-extra-comment-list" data-wp-lists="list:comment" style="display: none;">
<?php
$this->items = $this->extra_items;
$this->display_rows_or_placeholder();
?>
</tbody>
<tfoot>
<tr>
<?php $this->print_column_headers( false ); ?>
</tr>
</tfoot>
</table>
<?php
$this->display_tablenav( 'bottom' );
}
/**
* @global WP_Post $post
* @global WP_Comment $comment
*
* @param WP_Comment $item
*/
public function single_row( $item ) {
global $post, $comment;
$comment = $item;
$the_comment_class = wp_get_comment_status( $comment );
if ( ! $the_comment_class ) {
$the_comment_class = '';
}
$the_comment_class = join( ' ', get_comment_class( $the_comment_class, $comment, $comment->comment_post_ID ) );
if ( $comment->comment_post_ID > 0 ) {
$post = get_post( $comment->comment_post_ID );
}
$this->user_can = current_user_can( 'edit_comment', $comment->comment_ID );
echo "<tr id='comment-$comment->comment_ID' class='$the_comment_class'>";
$this->single_row_columns( $comment );
echo "</tr>\n";
unset( $GLOBALS['post'], $GLOBALS['comment'] );
}
/**
* Generate and display row actions links.
*
* @since 4.3.0
* @access protected
*
* @global string $comment_status Status for the current listed comments.
*
* @param WP_Comment $comment The comment object.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string|void Comment row actions output.
*/
protected function handle_row_actions( $comment, $column_name, $primary ) {
global $comment_status;
if ( $primary !== $column_name ) {
return '';
}
if ( ! $this->user_can ) {
return;
}
$the_comment_status = wp_get_comment_status( $comment );
$out = '';
$del_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "delete-comment_$comment->comment_ID" ) );
$approve_nonce = esc_html( '_wpnonce=' . wp_create_nonce( "approve-comment_$comment->comment_ID" ) );
$url = "comment.php?c=$comment->comment_ID";
$approve_url = esc_url( $url . "&action=approvecomment&$approve_nonce" );
$unapprove_url = esc_url( $url . "&action=unapprovecomment&$approve_nonce" );
$spam_url = esc_url( $url . "&action=spamcomment&$del_nonce" );
$unspam_url = esc_url( $url . "&action=unspamcomment&$del_nonce" );
$trash_url = esc_url( $url . "&action=trashcomment&$del_nonce" );
$untrash_url = esc_url( $url . "&action=untrashcomment&$del_nonce" );
$delete_url = esc_url( $url . "&action=deletecomment&$del_nonce" );
// Preorder it: Approve | Reply | Quick Edit | Edit | Spam | Trash.
$actions = array(
'approve' => '', 'unapprove' => '',
'reply' => '',
'quickedit' => '',
'edit' => '',
'spam' => '', 'unspam' => '',
'trash' => '', 'untrash' => '', 'delete' => ''
);
// Not looking at all comments.
if ( $comment_status && 'all' != $comment_status ) {
if ( 'approved' === $the_comment_status ) {
$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=unapproved' class='vim-u vim-destructive' aria-label='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
} elseif ( 'unapproved' === $the_comment_status ) {
$actions['approve'] = "<a href='$approve_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:e7e7d3:action=dim-comment&amp;new=approved' class='vim-a vim-destructive' aria-label='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
}
} else {
$actions['approve'] = "<a href='$approve_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=approved' class='vim-a' aria-label='" . esc_attr__( 'Approve this comment' ) . "'>" . __( 'Approve' ) . '</a>';
$actions['unapprove'] = "<a href='$unapprove_url' data-wp-lists='dim:the-comment-list:comment-$comment->comment_ID:unapproved:e7e7d3:e7e7d3:new=unapproved' class='vim-u' aria-label='" . esc_attr__( 'Unapprove this comment' ) . "'>" . __( 'Unapprove' ) . '</a>';
}
if ( 'spam' !== $the_comment_status ) {
$actions['spam'] = "<a href='$spam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::spam=1' class='vim-s vim-destructive' aria-label='" . esc_attr__( 'Mark this comment as spam' ) . "'>" . /* translators: mark as spam link */ _x( 'Spam', 'verb' ) . '</a>';
} elseif ( 'spam' === $the_comment_status ) {
$actions['unspam'] = "<a href='$unspam_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:unspam=1' class='vim-z vim-destructive' aria-label='" . esc_attr__( 'Restore this comment from the spam' ) . "'>" . _x( 'Not Spam', 'comment' ) . '</a>';
}
if ( 'trash' === $the_comment_status ) {
$actions['untrash'] = "<a href='$untrash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID:66cc66:untrash=1' class='vim-z vim-destructive' aria-label='" . esc_attr__( 'Restore this comment from the Trash' ) . "'>" . __( 'Restore' ) . '</a>';
}
if ( 'spam' === $the_comment_status || 'trash' === $the_comment_status || !EMPTY_TRASH_DAYS ) {
$actions['delete'] = "<a href='$delete_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::delete=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Delete this comment permanently' ) . "'>" . __( 'Delete Permanently' ) . '</a>';
} else {
$actions['trash'] = "<a href='$trash_url' data-wp-lists='delete:the-comment-list:comment-$comment->comment_ID::trash=1' class='delete vim-d vim-destructive' aria-label='" . esc_attr__( 'Move this comment to the Trash' ) . "'>" . _x( 'Trash', 'verb' ) . '</a>';
}
if ( 'spam' !== $the_comment_status && 'trash' !== $the_comment_status ) {
$actions['edit'] = "<a href='comment.php?action=editcomment&amp;c={$comment->comment_ID}' aria-label='" . esc_attr__( 'Edit this comment' ) . "'>". __( 'Edit' ) . '</a>';
$format = '<a data-comment-id="%d" data-post-id="%d" data-action="%s" class="%s" aria-label="%s" href="#">%s</a>';
$actions['quickedit'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'edit', 'vim-q comment-inline', esc_attr__( 'Quick edit this comment inline' ), __( 'Quick&nbsp;Edit' ) );
$actions['reply'] = sprintf( $format, $comment->comment_ID, $comment->comment_post_ID, 'replyto', 'vim-r comment-inline', esc_attr__( 'Reply to this comment' ), __( 'Reply' ) );
}
/** This filter is documented in wp-admin/includes/dashboard.php */
$actions = apply_filters( 'comment_row_actions', array_filter( $actions ), $comment );
$i = 0;
$out .= '<div class="row-actions">';
foreach ( $actions as $action => $link ) {
++$i;
( ( ( 'approve' === $action || 'unapprove' === $action ) && 2 === $i ) || 1 === $i ) ? $sep = '' : $sep = ' | ';
// Reply and quickedit need a hide-if-no-js span when not added with ajax
if ( ( 'reply' === $action || 'quickedit' === $action ) && ! defined('DOING_AJAX') )
$action .= ' hide-if-no-js';
elseif ( ( $action === 'untrash' && $the_comment_status === 'trash' ) || ( $action === 'unspam' && $the_comment_status === 'spam' ) ) {
if ( '1' == get_comment_meta( $comment->comment_ID, '_wp_trash_meta_status', true ) )
$action .= ' approve';
else
$action .= ' unapprove';
}
$out .= "<span class='$action'>$sep$link</span>";
}
$out .= '</div>';
$out .= '<button type="button" class="toggle-row"><span class="screen-reader-text">' . __( 'Show more details' ) . '</span></button>';
return $out;
}
/**
*
* @param WP_Comment $comment The comment object.
*/
public function column_cb( $comment ) {
if ( $this->user_can ) { ?>
<label class="screen-reader-text" for="cb-select-<?php echo $comment->comment_ID; ?>"><?php _e( 'Select comment' ); ?></label>
<input id="cb-select-<?php echo $comment->comment_ID; ?>" type="checkbox" name="delete_comments[]" value="<?php echo $comment->comment_ID; ?>" />
<?php
}
}
/**
* @param WP_Comment $comment The comment object.
*/
public function column_comment( $comment ) {
echo '<div class="comment-author">';
$this->column_author( $comment );
echo '</div>';
if ( $comment->comment_parent ) {
$parent = get_comment( $comment->comment_parent );
if ( $parent ) {
$parent_link = esc_url( get_comment_link( $parent ) );
$name = get_comment_author( $parent );
printf(
/* translators: %s: comment link */
__( 'In reply to %s.' ),
'<a href="' . $parent_link . '">' . $name . '</a>'
);
}
}
comment_text( $comment );
if ( $this->user_can ) { ?>
<div id="inline-<?php echo $comment->comment_ID; ?>" class="hidden">
<textarea class="comment" rows="1" cols="1"><?php
/** This filter is documented in wp-admin/includes/comment.php */
echo esc_textarea( apply_filters( 'comment_edit_pre', $comment->comment_content ) );
?></textarea>
<div class="author-email"><?php echo esc_attr( $comment->comment_author_email ); ?></div>
<div class="author"><?php echo esc_attr( $comment->comment_author ); ?></div>
<div class="author-url"><?php echo esc_attr( $comment->comment_author_url ); ?></div>
<div class="comment_status"><?php echo $comment->comment_approved; ?></div>
</div>
<?php
}
}
/**
*
* @global string $comment_status
*
* @param WP_Comment $comment The comment object.
*/
public function column_author( $comment ) {
global $comment_status;
$author_url = get_comment_author_url( $comment );
$author_url_display = untrailingslashit( preg_replace( '|^http(s)?://(www\.)?|i', '', $author_url ) );
if ( strlen( $author_url_display ) > 50 ) {
$author_url_display = wp_html_excerpt( $author_url_display, 49, '&hellip;' );
}
echo "<strong>"; comment_author( $comment ); echo '</strong><br />';
if ( ! empty( $author_url_display ) ) {
printf( '<a href="%s">%s</a><br />', esc_url( $author_url ), esc_html( $author_url_display ) );
}
if ( $this->user_can ) {
if ( ! empty( $comment->comment_author_email ) ) {
/* This filter is documented in wp-includes/comment-template.php */
$email = apply_filters( 'comment_email', $comment->comment_author_email, $comment );
if ( ! empty( $email ) && '@' !== $email ) {
printf( '<a href="%1$s">%2$s</a><br />', esc_url( 'mailto:' . $email ), esc_html( $email ) );
}
}
$author_ip = get_comment_author_IP( $comment );
if ( $author_ip ) {
$author_ip_url = add_query_arg( array( 's' => $author_ip, 'mode' => 'detail' ), admin_url( 'edit-comments.php' ) );
if ( 'spam' === $comment_status ) {
$author_ip_url = add_query_arg( 'comment_status', 'spam', $author_ip_url );
}
printf( '<a href="%1$s">%2$s</a>', esc_url( $author_ip_url ), esc_html( $author_ip ) );
}
}
}
/**
* @access public
*
* @param WP_Comment $comment The comment object.
*/
public function column_date( $comment ) {
/* translators: 1: comment date, 2: comment time */
$submitted = sprintf( __( '%1$s at %2$s' ),
/* translators: comment date format. See http://php.net/date */
get_comment_date( __( 'Y/m/d' ), $comment ),
get_comment_date( __( 'g:i a' ), $comment )
);
echo '<div class="submitted-on">';
if ( 'approved' === wp_get_comment_status( $comment ) && ! empty ( $comment->comment_post_ID ) ) {
printf(
'<a href="%s">%s</a>',
esc_url( get_comment_link( $comment ) ),
$submitted
);
} else {
echo $submitted;
}
echo '</div>';
}
/**
* @access public
*
* @param WP_Comment $comment The comment object.
*/
public function column_response( $comment ) {
$post = get_post();
if ( ! $post ) {
return;
}
if ( isset( $this->pending_count[$post->ID] ) ) {
$pending_comments = $this->pending_count[$post->ID];
} else {
$_pending_count_temp = get_pending_comments_num( array( $post->ID ) );
$pending_comments = $this->pending_count[$post->ID] = $_pending_count_temp[$post->ID];
}
if ( current_user_can( 'edit_post', $post->ID ) ) {
$post_link = "<a href='" . get_edit_post_link( $post->ID ) . "' class='comments-edit-item-link'>";
$post_link .= esc_html( get_the_title( $post->ID ) ) . '</a>';
} else {
$post_link = esc_html( get_the_title( $post->ID ) );
}
echo '<div class="response-links">';
if ( 'attachment' === $post->post_type && ( $thumb = wp_get_attachment_image( $post->ID, array( 80, 60 ), true ) ) ) {
echo $thumb;
}
echo $post_link;
$post_type_object = get_post_type_object( $post->post_type );
echo "<a href='" . get_permalink( $post->ID ) . "' class='comments-view-item-link'>" . $post_type_object->labels->view_item . '</a>';
echo '<span class="post-com-count-wrapper post-com-count-', $post->ID, '">';
$this->comments_bubble( $post->ID, $pending_comments );
echo '</span> ';
echo '</div>';
}
/**
*
* @param WP_Comment $comment The comment object.
* @param string $column_name The custom column's name.
*/
public function column_default( $comment, $column_name ) {
/**
* Fires when the default column output is displayed for a single row.
*
* @since 2.8.0
*
* @param string $column_name The custom column's name.
* @param int $comment->comment_ID The custom column's unique ID number.
*/
do_action( 'manage_comments_custom_column', $column_name, $comment->comment_ID );
}
}

View File

@@ -0,0 +1,844 @@
<?php
/**
* Base WordPress Filesystem
*
* @package WordPress
* @subpackage Filesystem
*/
/**
* Base WordPress Filesystem class for which Filesystem implementations extend
*
* @since 2.5.0
*/
class WP_Filesystem_Base {
/**
* Whether to display debug data for the connection.
*
* @access public
* @since 2.5.0
* @var bool
*/
public $verbose = false;
/**
* Cached list of local filepaths to mapped remote filepaths.
*
* @access public
* @since 2.7.0
* @var array
*/
public $cache = array();
/**
* The Access method of the current connection, Set automatically.
*
* @access public
* @since 2.5.0
* @var string
*/
public $method = '';
/**
* @access public
*/
public $errors = null;
/**
* @access public
*/
public $options = array();
/**
* Return the path on the remote filesystem of ABSPATH.
*
* @access public
* @since 2.7.0
*
* @return string The location of the remote path.
*/
public function abspath() {
$folder = $this->find_folder(ABSPATH);
// Perhaps the FTP folder is rooted at the WordPress install, Check for wp-includes folder in root, Could have some false positives, but rare.
if ( ! $folder && $this->is_dir( '/' . WPINC ) )
$folder = '/';
return $folder;
}
/**
* Return the path on the remote filesystem of WP_CONTENT_DIR.
*
* @access public
* @since 2.7.0
*
* @return string The location of the remote path.
*/
public function wp_content_dir() {
return $this->find_folder(WP_CONTENT_DIR);
}
/**
* Return the path on the remote filesystem of WP_PLUGIN_DIR.
*
* @access public
* @since 2.7.0
*
* @return string The location of the remote path.
*/
public function wp_plugins_dir() {
return $this->find_folder(WP_PLUGIN_DIR);
}
/**
* Return the path on the remote filesystem of the Themes Directory.
*
* @access public
* @since 2.7.0
*
* @param string $theme The Theme stylesheet or template for the directory.
* @return string The location of the remote path.
*/
public function wp_themes_dir( $theme = false ) {
$theme_root = get_theme_root( $theme );
// Account for relative theme roots
if ( '/themes' == $theme_root || ! is_dir( $theme_root ) )
$theme_root = WP_CONTENT_DIR . $theme_root;
return $this->find_folder( $theme_root );
}
/**
* Return the path on the remote filesystem of WP_LANG_DIR.
*
* @access public
* @since 3.2.0
*
* @return string The location of the remote path.
*/
public function wp_lang_dir() {
return $this->find_folder(WP_LANG_DIR);
}
/**
* Locate a folder on the remote filesystem.
*
* @access public
* @since 2.5.0
* @deprecated 2.7.0 use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() instead.
* @see WP_Filesystem::abspath()
* @see WP_Filesystem::wp_content_dir()
* @see WP_Filesystem::wp_plugins_dir()
* @see WP_Filesystem::wp_themes_dir()
* @see WP_Filesystem::wp_lang_dir()
*
* @param string $base The folder to start searching from.
* @param bool $echo True to display debug information.
* Default false.
* @return string The location of the remote path.
*/
public function find_base_dir( $base = '.', $echo = false ) {
_deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
$this->verbose = $echo;
return $this->abspath();
}
/**
* Locate a folder on the remote filesystem.
*
* @access public
* @since 2.5.0
* @deprecated 2.7.0 use WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir() methods instead.
* @see WP_Filesystem::abspath()
* @see WP_Filesystem::wp_content_dir()
* @see WP_Filesystem::wp_plugins_dir()
* @see WP_Filesystem::wp_themes_dir()
* @see WP_Filesystem::wp_lang_dir()
*
* @param string $base The folder to start searching from.
* @param bool $echo True to display debug information.
* @return string The location of the remote path.
*/
public function get_base_dir( $base = '.', $echo = false ) {
_deprecated_function(__FUNCTION__, '2.7', 'WP_Filesystem::abspath() or WP_Filesystem::wp_*_dir()' );
$this->verbose = $echo;
return $this->abspath();
}
/**
* Locate a folder on the remote filesystem.
*
* Assumes that on Windows systems, Stripping off the Drive
* letter is OK Sanitizes \\ to / in windows filepaths.
*
* @access public
* @since 2.7.0
*
* @param string $folder the folder to locate.
* @return string|false The location of the remote path, false on failure.
*/
public function find_folder( $folder ) {
if ( isset( $this->cache[ $folder ] ) )
return $this->cache[ $folder ];
if ( stripos($this->method, 'ftp') !== false ) {
$constant_overrides = array(
'FTP_BASE' => ABSPATH,
'FTP_CONTENT_DIR' => WP_CONTENT_DIR,
'FTP_PLUGIN_DIR' => WP_PLUGIN_DIR,
'FTP_LANG_DIR' => WP_LANG_DIR
);
// Direct matches ( folder = CONSTANT/ )
foreach ( $constant_overrides as $constant => $dir ) {
if ( ! defined( $constant ) )
continue;
if ( $folder === $dir )
return trailingslashit( constant( $constant ) );
}
// Prefix Matches ( folder = CONSTANT/subdir )
foreach ( $constant_overrides as $constant => $dir ) {
if ( ! defined( $constant ) )
continue;
if ( 0 === stripos( $folder, $dir ) ) { // $folder starts with $dir
$potential_folder = preg_replace( '#^' . preg_quote( $dir, '#' ) . '/#i', trailingslashit( constant( $constant ) ), $folder );
$potential_folder = trailingslashit( $potential_folder );
if ( $this->is_dir( $potential_folder ) ) {
$this->cache[ $folder ] = $potential_folder;
return $potential_folder;
}
}
}
} elseif ( 'direct' == $this->method ) {
$folder = str_replace('\\', '/', $folder); // Windows path sanitisation
return trailingslashit($folder);
}
$folder = preg_replace('|^([a-z]{1}):|i', '', $folder); // Strip out windows drive letter if it's there.
$folder = str_replace('\\', '/', $folder); // Windows path sanitisation
if ( isset($this->cache[ $folder ] ) )
return $this->cache[ $folder ];
if ( $this->exists($folder) ) { // Folder exists at that absolute path.
$folder = trailingslashit($folder);
$this->cache[ $folder ] = $folder;
return $folder;
}
if ( $return = $this->search_for_folder($folder) )
$this->cache[ $folder ] = $return;
return $return;
}
/**
* Locate a folder on the remote filesystem.
*
* Expects Windows sanitized path.
*
* @access public
* @since 2.7.0
*
* @param string $folder The folder to locate.
* @param string $base The folder to start searching from.
* @param bool $loop If the function has recursed, Internal use only.
* @return string|false The location of the remote path, false to cease looping.
*/
public function search_for_folder( $folder, $base = '.', $loop = false ) {
if ( empty( $base ) || '.' == $base )
$base = trailingslashit($this->cwd());
$folder = untrailingslashit($folder);
if ( $this->verbose ) {
/* translators: 1: folder to locate, 2: folder to start searching from */
printf( "\n" . __( 'Looking for %1$s in %2$s' ) . "<br/>\n", $folder, $base );
}
$folder_parts = explode('/', $folder);
$folder_part_keys = array_keys( $folder_parts );
$last_index = array_pop( $folder_part_keys );
$last_path = $folder_parts[ $last_index ];
$files = $this->dirlist( $base );
foreach ( $folder_parts as $index => $key ) {
if ( $index == $last_index )
continue; // We want this to be caught by the next code block.
/*
* Working from /home/ to /user/ to /wordpress/ see if that file exists within
* the current folder, If it's found, change into it and follow through looking
* for it. If it cant find WordPress down that route, it'll continue onto the next
* folder level, and see if that matches, and so on. If it reaches the end, and still
* cant find it, it'll return false for the entire function.
*/
if ( isset($files[ $key ]) ){
// Let's try that folder:
$newdir = trailingslashit(path_join($base, $key));
if ( $this->verbose ) {
/* translators: %s: directory name */
printf( "\n" . __( 'Changing to %s' ) . "<br/>\n", $newdir );
}
// Only search for the remaining path tokens in the directory, not the full path again.
$newfolder = implode( '/', array_slice( $folder_parts, $index + 1 ) );
if ( $ret = $this->search_for_folder( $newfolder, $newdir, $loop) )
return $ret;
}
}
// Only check this as a last resort, to prevent locating the incorrect install.
// All above procedures will fail quickly if this is the right branch to take.
if (isset( $files[ $last_path ] ) ) {
if ( $this->verbose ) {
/* translators: %s: directory name */
printf( "\n" . __( 'Found %s' ) . "<br/>\n", $base . $last_path );
}
return trailingslashit($base . $last_path);
}
// Prevent this function from looping again.
// No need to proceed if we've just searched in /
if ( $loop || '/' == $base )
return false;
// As an extra last resort, Change back to / if the folder wasn't found.
// This comes into effect when the CWD is /home/user/ but WP is at /var/www/....
return $this->search_for_folder( $folder, '/', true );
}
/**
* Return the *nix-style file permissions for a file.
*
* From the PHP documentation page for fileperms().
*
* @link http://docs.php.net/fileperms
*
* @access public
* @since 2.5.0
*
* @param string $file String filename.
* @return string The *nix-style representation of permissions.
*/
public function gethchmod( $file ){
$perms = intval( $this->getchmod( $file ), 8 );
if (($perms & 0xC000) == 0xC000) // Socket
$info = 's';
elseif (($perms & 0xA000) == 0xA000) // Symbolic Link
$info = 'l';
elseif (($perms & 0x8000) == 0x8000) // Regular
$info = '-';
elseif (($perms & 0x6000) == 0x6000) // Block special
$info = 'b';
elseif (($perms & 0x4000) == 0x4000) // Directory
$info = 'd';
elseif (($perms & 0x2000) == 0x2000) // Character special
$info = 'c';
elseif (($perms & 0x1000) == 0x1000) // FIFO pipe
$info = 'p';
else // Unknown
$info = 'u';
// Owner
$info .= (($perms & 0x0100) ? 'r' : '-');
$info .= (($perms & 0x0080) ? 'w' : '-');
$info .= (($perms & 0x0040) ?
(($perms & 0x0800) ? 's' : 'x' ) :
(($perms & 0x0800) ? 'S' : '-'));
// Group
$info .= (($perms & 0x0020) ? 'r' : '-');
$info .= (($perms & 0x0010) ? 'w' : '-');
$info .= (($perms & 0x0008) ?
(($perms & 0x0400) ? 's' : 'x' ) :
(($perms & 0x0400) ? 'S' : '-'));
// World
$info .= (($perms & 0x0004) ? 'r' : '-');
$info .= (($perms & 0x0002) ? 'w' : '-');
$info .= (($perms & 0x0001) ?
(($perms & 0x0200) ? 't' : 'x' ) :
(($perms & 0x0200) ? 'T' : '-'));
return $info;
}
/**
* Gets the permissions of the specified file or filepath in their octal format
*
* @access public
* @since 2.5.0
* @param string $file
* @return string the last 3 characters of the octal number
*/
public function getchmod( $file ) {
return '777';
}
/**
* Convert *nix-style file permissions to a octal number.
*
* Converts '-rw-r--r--' to 0644
* From "info at rvgate dot nl"'s comment on the PHP documentation for chmod()
*
* @link http://docs.php.net/manual/en/function.chmod.php#49614
*
* @access public
* @since 2.5.0
*
* @param string $mode string The *nix-style file permission.
* @return int octal representation
*/
public function getnumchmodfromh( $mode ) {
$realmode = '';
$legal = array('', 'w', 'r', 'x', '-');
$attarray = preg_split('//', $mode);
for ( $i = 0, $c = count( $attarray ); $i < $c; $i++ ) {
if ($key = array_search($attarray[$i], $legal)) {
$realmode .= $legal[$key];
}
}
$mode = str_pad($realmode, 10, '-', STR_PAD_LEFT);
$trans = array('-'=>'0', 'r'=>'4', 'w'=>'2', 'x'=>'1');
$mode = strtr($mode,$trans);
$newmode = $mode[0];
$newmode .= $mode[1] + $mode[2] + $mode[3];
$newmode .= $mode[4] + $mode[5] + $mode[6];
$newmode .= $mode[7] + $mode[8] + $mode[9];
return $newmode;
}
/**
* Determine if the string provided contains binary characters.
*
* @access public
* @since 2.7.0
*
* @param string $text String to test against.
* @return bool true if string is binary, false otherwise.
*/
public function is_binary( $text ) {
return (bool) preg_match( '|[^\x20-\x7E]|', $text ); // chr(32)..chr(127)
}
/**
* Change the ownership of a file / folder.
*
* Default behavior is to do nothing, override this in your subclass, if desired.
*
* @access public
* @since 2.5.0
*
* @param string $file Path to the file.
* @param mixed $owner A user name or number.
* @param bool $recursive Optional. If set True changes file owner recursivly. Defaults to False.
* @return bool Returns true on success or false on failure.
*/
public function chown( $file, $owner, $recursive = false ) {
return false;
}
/**
* Connect filesystem.
*
* @access public
* @since 2.5.0
* @abstract
*
* @return bool True on success or false on failure (always true for WP_Filesystem_Direct).
*/
public function connect() {
return true;
}
/**
* Read entire file into a string.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Name of the file to read.
* @return mixed|bool Returns the read data or false on failure.
*/
public function get_contents( $file ) {
return false;
}
/**
* Read entire file into an array.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @return array|bool the file contents in an array or false on failure.
*/
public function get_contents_array( $file ) {
return false;
}
/**
* Write a string to a file.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Remote path to the file where to write the data.
* @param string $contents The data to write.
* @param int $mode Optional. The file permissions as octal number, usually 0644.
* @return bool False on failure.
*/
public function put_contents( $file, $contents, $mode = false ) {
return false;
}
/**
* Get the current working directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @return string|bool The current working directory on success, or false on failure.
*/
public function cwd() {
return false;
}
/**
* Change current directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $dir The new current directory.
* @return bool|string
*/
public function chdir( $dir ) {
return false;
}
/**
* Change the file group.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @param mixed $group A group name or number.
* @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
* @return bool|string
*/
public function chgrp( $file, $group, $recursive = false ) {
return false;
}
/**
* Change filesystem permissions.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @param int $mode Optional. The permissions as octal number, usually 0644 for files, 0755 for dirs.
* @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
* @return bool|string
*/
public function chmod( $file, $mode = false, $recursive = false ) {
return false;
}
/**
* Get the file owner.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @return string|bool Username of the user or false on error.
*/
public function owner( $file ) {
return false;
}
/**
* Get the file's group.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @return string|bool The group or false on error.
*/
public function group( $file ) {
return false;
}
/**
* Copy a file.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $source Path to the source file.
* @param string $destination Path to the destination file.
* @param bool $overwrite Optional. Whether to overwrite the destination file if it exists.
* Default false.
* @param int $mode Optional. The permissions as octal number, usually 0644 for files, 0755 for dirs.
* Default false.
* @return bool True if file copied successfully, False otherwise.
*/
public function copy( $source, $destination, $overwrite = false, $mode = false ) {
return false;
}
/**
* Move a file.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $source Path to the source file.
* @param string $destination Path to the destination file.
* @param bool $overwrite Optional. Whether to overwrite the destination file if it exists.
* Default false.
* @return bool True if file copied successfully, False otherwise.
*/
public function move( $source, $destination, $overwrite = false ) {
return false;
}
/**
* Delete a file or directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to the file.
* @param bool $recursive Optional. If set True changes file group recursively. Defaults to False.
* Default false.
* @param bool $type Type of resource. 'f' for file, 'd' for directory.
* Default false.
* @return bool True if the file or directory was deleted, false on failure.
*/
public function delete( $file, $recursive = false, $type = false ) {
return false;
}
/**
* Check if a file or directory exists.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file/directory.
* @return bool Whether $file exists or not.
*/
public function exists( $file ) {
return false;
}
/**
* Check if resource is a file.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file File path.
* @return bool Whether $file is a file.
*/
public function is_file( $file ) {
return false;
}
/**
* Check if resource is a directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $path Directory path.
* @return bool Whether $path is a directory.
*/
public function is_dir( $path ) {
return false;
}
/**
* Check if a file is readable.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @return bool Whether $file is readable.
*/
public function is_readable( $file ) {
return false;
}
/**
* Check if a file or directory is writable.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @return bool Whether $file is writable.
*/
public function is_writable( $file ) {
return false;
}
/**
* Gets the file's last access time.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @return int|bool Unix timestamp representing last access time.
*/
public function atime( $file ) {
return false;
}
/**
* Gets the file modification time.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @return int|bool Unix timestamp representing modification time.
*/
public function mtime( $file ) {
return false;
}
/**
* Gets the file size (in bytes).
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @return int|bool Size of the file in bytes.
*/
public function size( $file ) {
return false;
}
/**
* Set the access and modification times of a file.
*
* Note: If $file doesn't exist, it will be created.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $file Path to file.
* @param int $time Optional. Modified time to set for file.
* Default 0.
* @param int $atime Optional. Access time to set for file.
* Default 0.
* @return bool Whether operation was successful or not.
*/
public function touch( $file, $time = 0, $atime = 0 ) {
return false;
}
/**
* Create a directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $path Path for new directory.
* @param mixed $chmod Optional. The permissions as octal number, (or False to skip chmod)
* Default false.
* @param mixed $chown Optional. A user name or number (or False to skip chown)
* Default false.
* @param mixed $chgrp Optional. A group name or number (or False to skip chgrp).
* Default false.
* @return bool False if directory cannot be created, true otherwise.
*/
public function mkdir( $path, $chmod = false, $chown = false, $chgrp = false ) {
return false;
}
/**
* Delete a directory.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $path Path to directory.
* @param bool $recursive Optional. Whether to recursively remove files/directories.
* Default false.
* @return bool Whether directory is deleted successfully or not.
*/
public function rmdir( $path, $recursive = false ) {
return false;
}
/**
* Get details for files in a directory or a specific file.
*
* @access public
* @since 2.5.0
* @abstract
*
* @param string $path Path to directory or file.
* @param bool $include_hidden Optional. Whether to include details of hidden ("." prefixed) files.
* Default true.
* @param bool $recursive Optional. Whether to recursively include file details in nested directories.
* Default false.
* @return array|bool {
* Array of files. False if unable to list directory contents.
*
* @type string $name Name of the file/directory.
* @type string $perms *nix representation of permissions.
* @type int $permsn Octal representation of permissions.
* @type string $owner Owner name or ID.
* @type int $size Size of file in bytes.
* @type int $lastmodunix Last modified unix timestamp.
* @type mixed $lastmod Last modified month (3 letter) and day (without leading 0).
* @type int $time Last modified time.
* @type string $type Type of resource. 'f' for file, 'd' for directory.
* @type mixed $files If a directory and $recursive is true, contains another array of files.
* }
*/
public function dirlist( $path, $include_hidden = true, $recursive = false ) {
return false;
}
} // WP_Filesystem_Base

View File

@@ -0,0 +1,517 @@
<?php
/**
* WordPress Direct Filesystem.
*
* @package WordPress
* @subpackage Filesystem
*/
/**
* WordPress Filesystem Class for direct PHP file and folder manipulation.
*
* @since 2.5.0
* @package WordPress
* @subpackage Filesystem
* @uses WP_Filesystem_Base Extends class
*/
class WP_Filesystem_Direct extends WP_Filesystem_Base {
/**
* constructor
*
* @access public
*
* @param mixed $arg ignored argument
*/
public function __construct($arg) {
$this->method = 'direct';
$this->errors = new WP_Error();
}
/**
* Reads entire file into a string
*
* @access public
*
* @param string $file Name of the file to read.
* @return string|bool The function returns the read data or false on failure.
*/
public function get_contents($file) {
return @file_get_contents($file);
}
/**
* Reads entire file into an array
*
* @access public
*
* @param string $file Path to the file.
* @return array|bool the file contents in an array or false on failure.
*/
public function get_contents_array($file) {
return @file($file);
}
/**
* Write a string to a file
*
* @access public
*
* @param string $file Remote path to the file where to write the data.
* @param string $contents The data to write.
* @param int $mode Optional. The file permissions as octal number, usually 0644.
* Default false.
* @return bool False upon failure, true otherwise.
*/
public function put_contents( $file, $contents, $mode = false ) {
$fp = @fopen( $file, 'wb' );
if ( ! $fp )
return false;
mbstring_binary_safe_encoding();
$data_length = strlen( $contents );
$bytes_written = fwrite( $fp, $contents );
reset_mbstring_encoding();
fclose( $fp );
if ( $data_length !== $bytes_written )
return false;
$this->chmod( $file, $mode );
return true;
}
/**
* Gets the current working directory
*
* @access public
*
* @return string|bool the current working directory on success, or false on failure.
*/
public function cwd() {
return @getcwd();
}
/**
* Change directory
*
* @access public
*
* @param string $dir The new current directory.
* @return bool Returns true on success or false on failure.
*/
public function chdir($dir) {
return @chdir($dir);
}
/**
* Changes file group
*
* @access public
*
* @param string $file Path to the file.
* @param mixed $group A group name or number.
* @param bool $recursive Optional. If set True changes file group recursively. Default false.
* @return bool Returns true on success or false on failure.
*/
public function chgrp($file, $group, $recursive = false) {
if ( ! $this->exists($file) )
return false;
if ( ! $recursive )
return @chgrp($file, $group);
if ( ! $this->is_dir($file) )
return @chgrp($file, $group);
// Is a directory, and we want recursive
$file = trailingslashit($file);
$filelist = $this->dirlist($file);
foreach ($filelist as $filename)
$this->chgrp($file . $filename, $group, $recursive);
return true;
}
/**
* Changes filesystem permissions
*
* @access public
*
* @param string $file Path to the file.
* @param int $mode Optional. The permissions as octal number, usually 0644 for files,
* 0755 for dirs. Default false.
* @param bool $recursive Optional. If set True changes file group recursively. Default false.
* @return bool Returns true on success or false on failure.
*/
public function chmod($file, $mode = false, $recursive = false) {
if ( ! $mode ) {
if ( $this->is_file($file) )
$mode = FS_CHMOD_FILE;
elseif ( $this->is_dir($file) )
$mode = FS_CHMOD_DIR;
else
return false;
}
if ( ! $recursive || ! $this->is_dir($file) )
return @chmod($file, $mode);
// Is a directory, and we want recursive
$file = trailingslashit($file);
$filelist = $this->dirlist($file);
foreach ( (array)$filelist as $filename => $filemeta)
$this->chmod($file . $filename, $mode, $recursive);
return true;
}
/**
* Changes file owner
*
* @access public
*
* @param string $file Path to the file.
* @param mixed $owner A user name or number.
* @param bool $recursive Optional. If set True changes file owner recursively.
* Default false.
* @return bool Returns true on success or false on failure.
*/
public function chown($file, $owner, $recursive = false) {
if ( ! $this->exists($file) )
return false;
if ( ! $recursive )
return @chown($file, $owner);
if ( ! $this->is_dir($file) )
return @chown($file, $owner);
// Is a directory, and we want recursive
$filelist = $this->dirlist($file);
foreach ($filelist as $filename) {
$this->chown($file . '/' . $filename, $owner, $recursive);
}
return true;
}
/**
* Gets file owner
*
* @access public
*
* @param string $file Path to the file.
* @return string|bool Username of the user or false on error.
*/
public function owner($file) {
$owneruid = @fileowner($file);
if ( ! $owneruid )
return false;
if ( ! function_exists('posix_getpwuid') )
return $owneruid;
$ownerarray = posix_getpwuid($owneruid);
return $ownerarray['name'];
}
/**
* Gets file permissions
*
* FIXME does not handle errors in fileperms()
*
* @access public
*
* @param string $file Path to the file.
* @return string Mode of the file (last 3 digits).
*/
public function getchmod($file) {
return substr( decoct( @fileperms( $file ) ), -3 );
}
/**
* @access public
*
* @param string $file
* @return string|false
*/
public function group($file) {
$gid = @filegroup($file);
if ( ! $gid )
return false;
if ( ! function_exists('posix_getgrgid') )
return $gid;
$grouparray = posix_getgrgid($gid);
return $grouparray['name'];
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @param int $mode
* @return bool
*/
public function copy($source, $destination, $overwrite = false, $mode = false) {
if ( ! $overwrite && $this->exists($destination) )
return false;
$rtval = copy($source, $destination);
if ( $mode )
$this->chmod($destination, $mode);
return $rtval;
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @return bool
*/
public function move($source, $destination, $overwrite = false) {
if ( ! $overwrite && $this->exists($destination) )
return false;
// Try using rename first. if that fails (for example, source is read only) try copy.
if ( @rename($source, $destination) )
return true;
if ( $this->copy($source, $destination, $overwrite) && $this->exists($destination) ) {
$this->delete($source);
return true;
} else {
return false;
}
}
/**
* @access public
*
* @param string $file
* @param bool $recursive
* @param string $type
* @return bool
*/
public function delete($file, $recursive = false, $type = false) {
if ( empty( $file ) ) // Some filesystems report this as /, which can cause non-expected recursive deletion of all files in the filesystem.
return false;
$file = str_replace( '\\', '/', $file ); // for win32, occasional problems deleting files otherwise
if ( 'f' == $type || $this->is_file($file) )
return @unlink($file);
if ( ! $recursive && $this->is_dir($file) )
return @rmdir($file);
// At this point it's a folder, and we're in recursive mode
$file = trailingslashit($file);
$filelist = $this->dirlist($file, true);
$retval = true;
if ( is_array( $filelist ) ) {
foreach ( $filelist as $filename => $fileinfo ) {
if ( ! $this->delete($file . $filename, $recursive, $fileinfo['type']) )
$retval = false;
}
}
if ( file_exists($file) && ! @rmdir($file) )
$retval = false;
return $retval;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function exists($file) {
return @file_exists($file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_file($file) {
return @is_file($file);
}
/**
* @access public
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return @is_dir($path);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_readable($file) {
return @is_readable($file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_writable($file) {
return @is_writable($file);
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function atime($file) {
return @fileatime($file);
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function mtime($file) {
return @filemtime($file);
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function size($file) {
return @filesize($file);
}
/**
* @access public
*
* @param string $file
* @param int $time
* @param int $atime
* @return bool
*/
public function touch($file, $time = 0, $atime = 0) {
if ($time == 0)
$time = time();
if ($atime == 0)
$atime = time();
return @touch($file, $time, $atime);
}
/**
* @access public
*
* @param string $path
* @param mixed $chmod
* @param mixed $chown
* @param mixed $chgrp
* @return bool
*/
public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
// Safe mode fails with a trailing slash under certain PHP versions.
$path = untrailingslashit($path);
if ( empty($path) )
return false;
if ( ! $chmod )
$chmod = FS_CHMOD_DIR;
if ( ! @mkdir($path) )
return false;
$this->chmod($path, $chmod);
if ( $chown )
$this->chown($path, $chown);
if ( $chgrp )
$this->chgrp($path, $chgrp);
return true;
}
/**
* @access public
*
* @param string $path
* @param bool $recursive
* @return bool
*/
public function rmdir($path, $recursive = false) {
return $this->delete($path, $recursive);
}
/**
* @access public
*
* @param string $path
* @param bool $include_hidden
* @param bool $recursive
* @return bool|array
*/
public function dirlist($path, $include_hidden = true, $recursive = false) {
if ( $this->is_file($path) ) {
$limit_file = basename($path);
$path = dirname($path);
} else {
$limit_file = false;
}
if ( ! $this->is_dir($path) )
return false;
$dir = @dir($path);
if ( ! $dir )
return false;
$ret = array();
while (false !== ($entry = $dir->read()) ) {
$struc = array();
$struc['name'] = $entry;
if ( '.' == $struc['name'] || '..' == $struc['name'] )
continue;
if ( ! $include_hidden && '.' == $struc['name'][0] )
continue;
if ( $limit_file && $struc['name'] != $limit_file)
continue;
$struc['perms'] = $this->gethchmod($path.'/'.$entry);
$struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
$struc['number'] = false;
$struc['owner'] = $this->owner($path.'/'.$entry);
$struc['group'] = $this->group($path.'/'.$entry);
$struc['size'] = $this->size($path.'/'.$entry);
$struc['lastmodunix']= $this->mtime($path.'/'.$entry);
$struc['lastmod'] = date('M j',$struc['lastmodunix']);
$struc['time'] = date('h:i:s',$struc['lastmodunix']);
$struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
if ( 'd' == $struc['type'] ) {
if ( $recursive )
$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
else
$struc['files'] = array();
}
$ret[ $struc['name'] ] = $struc;
}
$dir->close();
unset($dir);
return $ret;
}
}

View File

@@ -0,0 +1,607 @@
<?php
/**
* WordPress FTP Filesystem.
*
* @package WordPress
* @subpackage Filesystem
*/
/**
* WordPress Filesystem Class for implementing FTP.
*
* @since 2.5.0
* @package WordPress
* @subpackage Filesystem
* @uses WP_Filesystem_Base Extends class
*/
class WP_Filesystem_FTPext extends WP_Filesystem_Base {
public $link;
/**
* @access public
*
* @param array $opt
*/
public function __construct( $opt = '' ) {
$this->method = 'ftpext';
$this->errors = new WP_Error();
// Check if possible to use ftp functions.
if ( ! extension_loaded('ftp') ) {
$this->errors->add('no_ftp_ext', __('The ftp PHP extension is not available'));
return;
}
// This Class uses the timeout on a per-connection basis, Others use it on a per-action basis.
if ( ! defined('FS_TIMEOUT') )
define('FS_TIMEOUT', 240);
if ( empty($opt['port']) )
$this->options['port'] = 21;
else
$this->options['port'] = $opt['port'];
if ( empty($opt['hostname']) )
$this->errors->add('empty_hostname', __('FTP hostname is required'));
else
$this->options['hostname'] = $opt['hostname'];
// Check if the options provided are OK.
if ( empty($opt['username']) )
$this->errors->add('empty_username', __('FTP username is required'));
else
$this->options['username'] = $opt['username'];
if ( empty($opt['password']) )
$this->errors->add('empty_password', __('FTP password is required'));
else
$this->options['password'] = $opt['password'];
$this->options['ssl'] = false;
if ( isset($opt['connection_type']) && 'ftps' == $opt['connection_type'] )
$this->options['ssl'] = true;
}
/**
* @access public
*
* @return bool
*/
public function connect() {
if ( isset($this->options['ssl']) && $this->options['ssl'] && function_exists('ftp_ssl_connect') )
$this->link = @ftp_ssl_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
else
$this->link = @ftp_connect($this->options['hostname'], $this->options['port'], FS_CONNECT_TIMEOUT);
if ( ! $this->link ) {
$this->errors->add( 'connect',
/* translators: %s: hostname:port */
sprintf( __( 'Failed to connect to FTP Server %s' ),
$this->options['hostname'] . ':' . $this->options['port']
)
);
return false;
}
if ( ! @ftp_login( $this->link,$this->options['username'], $this->options['password'] ) ) {
$this->errors->add( 'auth',
/* translators: %s: username */
sprintf( __( 'Username/Password incorrect for %s' ),
$this->options['username']
)
);
return false;
}
// Set the Connection to use Passive FTP
@ftp_pasv( $this->link, true );
if ( @ftp_get_option($this->link, FTP_TIMEOUT_SEC) < FS_TIMEOUT )
@ftp_set_option($this->link, FTP_TIMEOUT_SEC, FS_TIMEOUT);
return true;
}
/**
* Retrieves the file contents.
*
* @since 2.5.0
* @access public
*
* @param string $file Filename.
* @return string|false File contents on success, false if no temp file could be opened,
* or if the file couldn't be retrieved.
*/
public function get_contents( $file ) {
$tempfile = wp_tempnam($file);
$temp = fopen($tempfile, 'w+');
if ( ! $temp ) {
unlink( $tempfile );
return false;
}
if ( ! @ftp_fget( $this->link, $temp, $file, FTP_BINARY ) ) {
fclose( $temp );
unlink( $tempfile );
return false;
}
fseek( $temp, 0 ); // Skip back to the start of the file being written to
$contents = '';
while ( ! feof($temp) )
$contents .= fread($temp, 8192);
fclose($temp);
unlink($tempfile);
return $contents;
}
/**
* @access public
*
* @param string $file
* @return array
*/
public function get_contents_array($file) {
return explode("\n", $this->get_contents($file));
}
/**
* @access public
*
* @param string $file
* @param string $contents
* @param bool|int $mode
* @return bool
*/
public function put_contents($file, $contents, $mode = false ) {
$tempfile = wp_tempnam($file);
$temp = fopen( $tempfile, 'wb+' );
if ( ! $temp )
return false;
mbstring_binary_safe_encoding();
$data_length = strlen( $contents );
$bytes_written = fwrite( $temp, $contents );
reset_mbstring_encoding();
if ( $data_length !== $bytes_written ) {
fclose( $temp );
unlink( $tempfile );
return false;
}
fseek( $temp, 0 ); // Skip back to the start of the file being written to
$ret = @ftp_fput( $this->link, $file, $temp, FTP_BINARY );
fclose($temp);
unlink($tempfile);
$this->chmod($file, $mode);
return $ret;
}
/**
* @access public
*
* @return string
*/
public function cwd() {
$cwd = @ftp_pwd($this->link);
if ( $cwd )
$cwd = trailingslashit($cwd);
return $cwd;
}
/**
* @access public
*
* @param string $dir
* @return bool
*/
public function chdir($dir) {
return @ftp_chdir($this->link, $dir);
}
/**
* @access public
*
* @param string $file
* @param int $mode
* @param bool $recursive
* @return bool
*/
public function chmod($file, $mode = false, $recursive = false) {
if ( ! $mode ) {
if ( $this->is_file($file) )
$mode = FS_CHMOD_FILE;
elseif ( $this->is_dir($file) )
$mode = FS_CHMOD_DIR;
else
return false;
}
// chmod any sub-objects if recursive.
if ( $recursive && $this->is_dir($file) ) {
$filelist = $this->dirlist($file);
foreach ( (array)$filelist as $filename => $filemeta )
$this->chmod($file . '/' . $filename, $mode, $recursive);
}
// chmod the file or directory
if ( ! function_exists('ftp_chmod') )
return (bool)@ftp_site($this->link, sprintf('CHMOD %o %s', $mode, $file));
return (bool)@ftp_chmod($this->link, $mode, $file);
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function owner($file) {
$dir = $this->dirlist($file);
return $dir[$file]['owner'];
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function getchmod($file) {
$dir = $this->dirlist($file);
return $dir[$file]['permsn'];
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function group($file) {
$dir = $this->dirlist($file);
return $dir[$file]['group'];
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @param string|bool $mode
* @return bool
*/
public function copy($source, $destination, $overwrite = false, $mode = false) {
if ( ! $overwrite && $this->exists($destination) )
return false;
$content = $this->get_contents($source);
if ( false === $content )
return false;
return $this->put_contents($destination, $content, $mode);
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @return bool
*/
public function move($source, $destination, $overwrite = false) {
return ftp_rename($this->link, $source, $destination);
}
/**
* @access public
*
* @param string $file
* @param bool $recursive
* @param string $type
* @return bool
*/
public function delete($file, $recursive = false, $type = false) {
if ( empty($file) )
return false;
if ( 'f' == $type || $this->is_file($file) )
return @ftp_delete($this->link, $file);
if ( !$recursive )
return @ftp_rmdir($this->link, $file);
$filelist = $this->dirlist( trailingslashit($file) );
if ( !empty($filelist) )
foreach ( $filelist as $delete_file )
$this->delete( trailingslashit($file) . $delete_file['name'], $recursive, $delete_file['type'] );
return @ftp_rmdir($this->link, $file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function exists($file) {
$list = @ftp_nlist($this->link, $file);
if ( empty( $list ) && $this->is_dir( $file ) ) {
return true; // File is an empty directory.
}
return !empty($list); //empty list = no file, so invert.
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_file($file) {
return $this->exists($file) && !$this->is_dir($file);
}
/**
* @access public
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
$cwd = $this->cwd();
$result = @ftp_chdir($this->link, trailingslashit($path) );
if ( $result && $path == $this->cwd() || $this->cwd() != $cwd ) {
@ftp_chdir($this->link, $cwd);
return true;
}
return false;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_readable($file) {
return true;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_writable($file) {
return true;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function atime($file) {
return false;
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function mtime($file) {
return ftp_mdtm($this->link, $file);
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function size($file) {
return ftp_size($this->link, $file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function touch($file, $time = 0, $atime = 0) {
return false;
}
/**
* @access public
*
* @param string $path
* @param mixed $chmod
* @param mixed $chown
* @param mixed $chgrp
* @return bool
*/
public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
$path = untrailingslashit($path);
if ( empty($path) )
return false;
if ( !@ftp_mkdir($this->link, $path) )
return false;
$this->chmod($path, $chmod);
return true;
}
/**
* @access public
*
* @param string $path
* @param bool $recursive
* @return bool
*/
public function rmdir($path, $recursive = false) {
return $this->delete($path, $recursive);
}
/**
* @access public
*
* @staticvar bool $is_windows
* @param string $line
* @return array
*/
public function parselisting($line) {
static $is_windows = null;
if ( is_null($is_windows) )
$is_windows = stripos( ftp_systype($this->link), 'win') !== false;
if ( $is_windows && preg_match('/([0-9]{2})-([0-9]{2})-([0-9]{2}) +([0-9]{2}):([0-9]{2})(AM|PM) +([0-9]+|<DIR>) +(.+)/', $line, $lucifer) ) {
$b = array();
if ( $lucifer[3] < 70 )
$lucifer[3] +=2000;
else
$lucifer[3] += 1900; // 4digit year fix
$b['isdir'] = ( $lucifer[7] == '<DIR>');
if ( $b['isdir'] )
$b['type'] = 'd';
else
$b['type'] = 'f';
$b['size'] = $lucifer[7];
$b['month'] = $lucifer[1];
$b['day'] = $lucifer[2];
$b['year'] = $lucifer[3];
$b['hour'] = $lucifer[4];
$b['minute'] = $lucifer[5];
$b['time'] = @mktime($lucifer[4] + (strcasecmp($lucifer[6], "PM") == 0 ? 12 : 0), $lucifer[5], 0, $lucifer[1], $lucifer[2], $lucifer[3]);
$b['am/pm'] = $lucifer[6];
$b['name'] = $lucifer[8];
} elseif ( !$is_windows && $lucifer = preg_split('/[ ]/', $line, 9, PREG_SPLIT_NO_EMPTY)) {
//echo $line."\n";
$lcount = count($lucifer);
if ( $lcount < 8 )
return '';
$b = array();
$b['isdir'] = $lucifer[0]{0} === 'd';
$b['islink'] = $lucifer[0]{0} === 'l';
if ( $b['isdir'] )
$b['type'] = 'd';
elseif ( $b['islink'] )
$b['type'] = 'l';
else
$b['type'] = 'f';
$b['perms'] = $lucifer[0];
$b['permsn'] = $this->getnumchmodfromh( $b['perms'] );
$b['number'] = $lucifer[1];
$b['owner'] = $lucifer[2];
$b['group'] = $lucifer[3];
$b['size'] = $lucifer[4];
if ( $lcount == 8 ) {
sscanf($lucifer[5], '%d-%d-%d', $b['year'], $b['month'], $b['day']);
sscanf($lucifer[6], '%d:%d', $b['hour'], $b['minute']);
$b['time'] = @mktime($b['hour'], $b['minute'], 0, $b['month'], $b['day'], $b['year']);
$b['name'] = $lucifer[7];
} else {
$b['month'] = $lucifer[5];
$b['day'] = $lucifer[6];
if ( preg_match('/([0-9]{2}):([0-9]{2})/', $lucifer[7], $l2) ) {
$b['year'] = date("Y");
$b['hour'] = $l2[1];
$b['minute'] = $l2[2];
} else {
$b['year'] = $lucifer[7];
$b['hour'] = 0;
$b['minute'] = 0;
}
$b['time'] = strtotime( sprintf('%d %s %d %02d:%02d', $b['day'], $b['month'], $b['year'], $b['hour'], $b['minute']) );
$b['name'] = $lucifer[8];
}
}
// Replace symlinks formatted as "source -> target" with just the source name
if ( isset( $b['islink'] ) && $b['islink'] ) {
$b['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $b['name'] );
}
return $b;
}
/**
* @access public
*
* @param string $path
* @param bool $include_hidden
* @param bool $recursive
* @return bool|array
*/
public function dirlist($path = '.', $include_hidden = true, $recursive = false) {
if ( $this->is_file($path) ) {
$limit_file = basename($path);
$path = dirname($path) . '/';
} else {
$limit_file = false;
}
$pwd = @ftp_pwd($this->link);
if ( ! @ftp_chdir($this->link, $path) ) // Cant change to folder = folder doesn't exist
return false;
$list = @ftp_rawlist($this->link, '-a', false);
@ftp_chdir($this->link, $pwd);
if ( empty($list) ) // Empty array = non-existent folder (real folder will show . at least)
return false;
$dirlist = array();
foreach ( $list as $k => $v ) {
$entry = $this->parselisting($v);
if ( empty($entry) )
continue;
if ( '.' == $entry['name'] || '..' == $entry['name'] )
continue;
if ( ! $include_hidden && '.' == $entry['name'][0] )
continue;
if ( $limit_file && $entry['name'] != $limit_file)
continue;
$dirlist[ $entry['name'] ] = $entry;
}
$ret = array();
foreach ( (array)$dirlist as $struc ) {
if ( 'd' == $struc['type'] ) {
if ( $recursive )
$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
else
$struc['files'] = array();
}
$ret[ $struc['name'] ] = $struc;
}
return $ret;
}
/**
* @access public
*/
public function __destruct() {
if ( $this->link )
ftp_close($this->link);
}
}

View File

@@ -0,0 +1,542 @@
<?php
/**
* WordPress FTP Sockets Filesystem.
*
* @package WordPress
* @subpackage Filesystem
*/
/**
* WordPress Filesystem Class for implementing FTP Sockets.
*
* @since 2.5.0
* @package WordPress
* @subpackage Filesystem
* @uses WP_Filesystem_Base Extends class
*/
class WP_Filesystem_ftpsockets extends WP_Filesystem_Base {
/**
* @access public
* @var ftp
*/
public $ftp;
/**
* @access public
*
* @param array $opt
*/
public function __construct( $opt = '' ) {
$this->method = 'ftpsockets';
$this->errors = new WP_Error();
// Check if possible to use ftp functions.
if ( ! @include_once( ABSPATH . 'wp-admin/includes/class-ftp.php' ) ) {
return;
}
$this->ftp = new ftp();
if ( empty($opt['port']) )
$this->options['port'] = 21;
else
$this->options['port'] = (int) $opt['port'];
if ( empty($opt['hostname']) )
$this->errors->add('empty_hostname', __('FTP hostname is required'));
else
$this->options['hostname'] = $opt['hostname'];
// Check if the options provided are OK.
if ( empty ($opt['username']) )
$this->errors->add('empty_username', __('FTP username is required'));
else
$this->options['username'] = $opt['username'];
if ( empty ($opt['password']) )
$this->errors->add('empty_password', __('FTP password is required'));
else
$this->options['password'] = $opt['password'];
}
/**
* @access public
*
* @return bool
*/
public function connect() {
if ( ! $this->ftp )
return false;
$this->ftp->setTimeout(FS_CONNECT_TIMEOUT);
if ( ! $this->ftp->SetServer( $this->options['hostname'], $this->options['port'] ) ) {
$this->errors->add( 'connect',
/* translators: %s: hostname:port */
sprintf( __( 'Failed to connect to FTP Server %s' ),
$this->options['hostname'] . ':' . $this->options['port']
)
);
return false;
}
if ( ! $this->ftp->connect() ) {
$this->errors->add( 'connect',
/* translators: %s: hostname:port */
sprintf( __( 'Failed to connect to FTP Server %s' ),
$this->options['hostname'] . ':' . $this->options['port']
)
);
return false;
}
if ( ! $this->ftp->login( $this->options['username'], $this->options['password'] ) ) {
$this->errors->add( 'auth',
/* translators: %s: username */
sprintf( __( 'Username/Password incorrect for %s' ),
$this->options['username']
)
);
return false;
}
$this->ftp->SetType( FTP_BINARY );
$this->ftp->Passive( true );
$this->ftp->setTimeout( FS_TIMEOUT );
return true;
}
/**
* Retrieves the file contents.
*
* @since 2.5.0
* @access public
*
* @param string $file Filename.
* @return string|false File contents on success, false if no temp file could be opened,
* or if the file doesn't exist.
*/
public function get_contents( $file ) {
if ( ! $this->exists($file) )
return false;
$temp = wp_tempnam( $file );
if ( ! $temphandle = fopen($temp, 'w+') )
return false;
mbstring_binary_safe_encoding();
if ( ! $this->ftp->fget($temphandle, $file) ) {
fclose($temphandle);
unlink($temp);
reset_mbstring_encoding();
return ''; // Blank document, File does exist, It's just blank.
}
reset_mbstring_encoding();
fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
$contents = '';
while ( ! feof($temphandle) )
$contents .= fread($temphandle, 8192);
fclose($temphandle);
unlink($temp);
return $contents;
}
/**
* @access public
*
* @param string $file
* @return array
*/
public function get_contents_array($file) {
return explode("\n", $this->get_contents($file) );
}
/**
* @access public
*
* @param string $file
* @param string $contents
* @param int|bool $mode
* @return bool
*/
public function put_contents($file, $contents, $mode = false ) {
$temp = wp_tempnam( $file );
if ( ! $temphandle = @fopen($temp, 'w+') ) {
unlink($temp);
return false;
}
// The FTP class uses string functions internally during file download/upload
mbstring_binary_safe_encoding();
$bytes_written = fwrite( $temphandle, $contents );
if ( false === $bytes_written || $bytes_written != strlen( $contents ) ) {
fclose( $temphandle );
unlink( $temp );
reset_mbstring_encoding();
return false;
}
fseek( $temphandle, 0 ); // Skip back to the start of the file being written to
$ret = $this->ftp->fput($file, $temphandle);
reset_mbstring_encoding();
fclose($temphandle);
unlink($temp);
$this->chmod($file, $mode);
return $ret;
}
/**
* @access public
*
* @return string
*/
public function cwd() {
$cwd = $this->ftp->pwd();
if ( $cwd )
$cwd = trailingslashit($cwd);
return $cwd;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function chdir($file) {
return $this->ftp->chdir($file);
}
/**
* @access public
*
* @param string $file
* @param int|bool $mode
* @param bool $recursive
* @return bool
*/
public function chmod($file, $mode = false, $recursive = false ) {
if ( ! $mode ) {
if ( $this->is_file($file) )
$mode = FS_CHMOD_FILE;
elseif ( $this->is_dir($file) )
$mode = FS_CHMOD_DIR;
else
return false;
}
// chmod any sub-objects if recursive.
if ( $recursive && $this->is_dir($file) ) {
$filelist = $this->dirlist($file);
foreach ( (array)$filelist as $filename => $filemeta )
$this->chmod($file . '/' . $filename, $mode, $recursive);
}
// chmod the file or directory
return $this->ftp->chmod($file, $mode);
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function owner($file) {
$dir = $this->dirlist($file);
return $dir[$file]['owner'];
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function getchmod($file) {
$dir = $this->dirlist($file);
return $dir[$file]['permsn'];
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function group($file) {
$dir = $this->dirlist($file);
return $dir[$file]['group'];
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @param int|bool $mode
* @return bool
*/
public function copy($source, $destination, $overwrite = false, $mode = false) {
if ( ! $overwrite && $this->exists($destination) )
return false;
$content = $this->get_contents($source);
if ( false === $content )
return false;
return $this->put_contents($destination, $content, $mode);
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @return bool
*/
public function move($source, $destination, $overwrite = false ) {
return $this->ftp->rename($source, $destination);
}
/**
* @access public
*
* @param string $file
* @param bool $recursive
* @param string $type
* @return bool
*/
public function delete($file, $recursive = false, $type = false) {
if ( empty($file) )
return false;
if ( 'f' == $type || $this->is_file($file) )
return $this->ftp->delete($file);
if ( !$recursive )
return $this->ftp->rmdir($file);
return $this->ftp->mdel($file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function exists( $file ) {
$list = $this->ftp->nlist( $file );
if ( empty( $list ) && $this->is_dir( $file ) ) {
return true; // File is an empty directory.
}
return !empty( $list ); //empty list = no file, so invert.
// Return $this->ftp->is_exists($file); has issues with ABOR+426 responses on the ncFTPd server.
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_file($file) {
if ( $this->is_dir($file) )
return false;
if ( $this->exists($file) )
return true;
return false;
}
/**
* @access public
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
$cwd = $this->cwd();
if ( $this->chdir($path) ) {
$this->chdir($cwd);
return true;
}
return false;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_readable($file) {
return true;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_writable($file) {
return true;
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function atime($file) {
return false;
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function mtime($file) {
return $this->ftp->mdtm($file);
}
/**
* @param string $file
* @return int
*/
public function size($file) {
return $this->ftp->filesize($file);
}
/**
* @access public
*
* @param string $file
* @param int $time
* @param int $atime
* @return bool
*/
public function touch($file, $time = 0, $atime = 0 ) {
return false;
}
/**
* @access public
*
* @param string $path
* @param mixed $chmod
* @param mixed $chown
* @param mixed $chgrp
* @return bool
*/
public function mkdir($path, $chmod = false, $chown = false, $chgrp = false ) {
$path = untrailingslashit($path);
if ( empty($path) )
return false;
if ( ! $this->ftp->mkdir($path) )
return false;
if ( ! $chmod )
$chmod = FS_CHMOD_DIR;
$this->chmod($path, $chmod);
return true;
}
/**
* @access public
*
* @param string $path
* @param bool $recursive
*/
public function rmdir($path, $recursive = false ) {
$this->delete($path, $recursive);
}
/**
* @access public
*
* @param string $path
* @param bool $include_hidden
* @param bool $recursive
* @return bool|array
*/
public function dirlist($path = '.', $include_hidden = true, $recursive = false ) {
if ( $this->is_file($path) ) {
$limit_file = basename($path);
$path = dirname($path) . '/';
} else {
$limit_file = false;
}
mbstring_binary_safe_encoding();
$list = $this->ftp->dirlist($path);
if ( empty( $list ) && ! $this->exists( $path ) ) {
reset_mbstring_encoding();
return false;
}
$ret = array();
foreach ( $list as $struc ) {
if ( '.' == $struc['name'] || '..' == $struc['name'] )
continue;
if ( ! $include_hidden && '.' == $struc['name'][0] )
continue;
if ( $limit_file && $struc['name'] != $limit_file )
continue;
if ( 'd' == $struc['type'] ) {
if ( $recursive )
$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
else
$struc['files'] = array();
}
// Replace symlinks formatted as "source -> target" with just the source name
if ( $struc['islink'] )
$struc['name'] = preg_replace( '/(\s*->\s*.*)$/', '', $struc['name'] );
// Add the Octal representation of the file permissions
$struc['permsn'] = $this->getnumchmodfromh( $struc['perms'] );
$ret[ $struc['name'] ] = $struc;
}
reset_mbstring_encoding();
return $ret;
}
/**
* @access public
*/
public function __destruct() {
$this->ftp->quit();
}
}

View File

@@ -0,0 +1,630 @@
<?php
/**
* WordPress Filesystem Class for implementing SSH2
*
* To use this class you must follow these steps for PHP 5.2.6+
*
* @contrib http://kevin.vanzonneveld.net/techblog/article/make_ssh_connections_with_php/ - Installation Notes
*
* Complie libssh2 (Note: Only 0.14 is officaly working with PHP 5.2.6+ right now, But many users have found the latest versions work)
*
* cd /usr/src
* wget http://surfnet.dl.sourceforge.net/sourceforge/libssh2/libssh2-0.14.tar.gz
* tar -zxvf libssh2-0.14.tar.gz
* cd libssh2-0.14/
* ./configure
* make all install
*
* Note: Do not leave the directory yet!
*
* Enter: pecl install -f ssh2
*
* Copy the ssh.so file it creates to your PHP Module Directory.
* Open up your PHP.INI file and look for where extensions are placed.
* Add in your PHP.ini file: extension=ssh2.so
*
* Restart Apache!
* Check phpinfo() streams to confirm that: ssh2.shell, ssh2.exec, ssh2.tunnel, ssh2.scp, ssh2.sftp exist.
*
* Note: as of WordPress 2.8, This utilises the PHP5+ function 'stream_get_contents'
*
* @since 2.7.0
*
* @package WordPress
* @subpackage Filesystem
*/
class WP_Filesystem_SSH2 extends WP_Filesystem_Base {
/**
* @access public
*/
public $link = false;
/**
* @access public
* @var resource
*/
public $sftp_link;
public $keys = false;
/**
* @access public
*
* @param array $opt
*/
public function __construct( $opt = '' ) {
$this->method = 'ssh2';
$this->errors = new WP_Error();
//Check if possible to use ssh2 functions.
if ( ! extension_loaded('ssh2') ) {
$this->errors->add('no_ssh2_ext', __('The ssh2 PHP extension is not available'));
return;
}
if ( !function_exists('stream_get_contents') ) {
$this->errors->add(
'ssh2_php_requirement',
sprintf(
/* translators: %s: stream_get_contents() */
__( 'The ssh2 PHP extension is available, however, we require the PHP5 function %s' ),
'<code>stream_get_contents()</code>'
)
);
return;
}
// Set defaults:
if ( empty($opt['port']) )
$this->options['port'] = 22;
else
$this->options['port'] = $opt['port'];
if ( empty($opt['hostname']) )
$this->errors->add('empty_hostname', __('SSH2 hostname is required'));
else
$this->options['hostname'] = $opt['hostname'];
// Check if the options provided are OK.
if ( !empty ($opt['public_key']) && !empty ($opt['private_key']) ) {
$this->options['public_key'] = $opt['public_key'];
$this->options['private_key'] = $opt['private_key'];
$this->options['hostkey'] = array('hostkey' => 'ssh-rsa');
$this->keys = true;
} elseif ( empty ($opt['username']) ) {
$this->errors->add('empty_username', __('SSH2 username is required'));
}
if ( !empty($opt['username']) )
$this->options['username'] = $opt['username'];
if ( empty ($opt['password']) ) {
// Password can be blank if we are using keys.
if ( !$this->keys )
$this->errors->add('empty_password', __('SSH2 password is required'));
} else {
$this->options['password'] = $opt['password'];
}
}
/**
* @access public
*
* @return bool
*/
public function connect() {
if ( ! $this->keys ) {
$this->link = @ssh2_connect($this->options['hostname'], $this->options['port']);
} else {
$this->link = @ssh2_connect($this->options['hostname'], $this->options['port'], $this->options['hostkey']);
}
if ( ! $this->link ) {
$this->errors->add( 'connect',
/* translators: %s: hostname:port */
sprintf( __( 'Failed to connect to SSH2 Server %s' ),
$this->options['hostname'] . ':' . $this->options['port']
)
);
return false;
}
if ( !$this->keys ) {
if ( ! @ssh2_auth_password($this->link, $this->options['username'], $this->options['password']) ) {
$this->errors->add( 'auth',
/* translators: %s: username */
sprintf( __( 'Username/Password incorrect for %s' ),
$this->options['username']
)
);
return false;
}
} else {
if ( ! @ssh2_auth_pubkey_file($this->link, $this->options['username'], $this->options['public_key'], $this->options['private_key'], $this->options['password'] ) ) {
$this->errors->add( 'auth',
/* translators: %s: username */
sprintf( __( 'Public and Private keys incorrect for %s' ),
$this->options['username']
)
);
return false;
}
}
$this->sftp_link = ssh2_sftp( $this->link );
if ( ! $this->sftp_link ) {
$this->errors->add( 'connect',
/* translators: %s: hostname:port */
sprintf( __( 'Failed to initialize a SFTP subsystem session with the SSH2 Server %s' ),
$this->options['hostname'] . ':' . $this->options['port']
)
);
return false;
}
return true;
}
/**
* Gets the ssh2.sftp PHP stream wrapper path to open for the given file.
*
* This method also works around a PHP bug where the root directory (/) cannot
* be opened by PHP functions, causing a false failure. In order to work around
* this, the path is converted to /./ which is semantically the same as /
* See https://bugs.php.net/bug.php?id=64169 for more details.
*
* @access public
*
* @since 4.4.0
*
* @param string $path The File/Directory path on the remote server to return
* @return string The ssh2.sftp:// wrapped path to use.
*/
public function sftp_path( $path ) {
if ( '/' === $path ) {
$path = '/./';
}
return 'ssh2.sftp://' . $this->sftp_link . '/' . ltrim( $path, '/' );
}
/**
* @access public
*
* @param string $command
* @param bool $returnbool
* @return bool|string
*/
public function run_command( $command, $returnbool = false ) {
if ( ! $this->link )
return false;
if ( ! ($stream = ssh2_exec($this->link, $command)) ) {
$this->errors->add( 'command',
/* translators: %s: command */
sprintf( __( 'Unable to perform command: %s'),
$command
)
);
} else {
stream_set_blocking( $stream, true );
stream_set_timeout( $stream, FS_TIMEOUT );
$data = stream_get_contents( $stream );
fclose( $stream );
if ( $returnbool )
return ( $data === false ) ? false : '' != trim($data);
else
return $data;
}
return false;
}
/**
* @access public
*
* @param string $file
* @return string|false
*/
public function get_contents( $file ) {
return file_get_contents( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @return array
*/
public function get_contents_array($file) {
return file( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @param string $contents
* @param bool|int $mode
* @return bool
*/
public function put_contents($file, $contents, $mode = false ) {
$ret = file_put_contents( $this->sftp_path( $file ), $contents );
if ( $ret !== strlen( $contents ) )
return false;
$this->chmod($file, $mode);
return true;
}
/**
* @access public
*
* @return bool
*/
public function cwd() {
$cwd = ssh2_sftp_realpath( $this->sftp_link, '.' );
if ( $cwd ) {
$cwd = trailingslashit( trim( $cwd ) );
}
return $cwd;
}
/**
* @access public
*
* @param string $dir
* @return bool|string
*/
public function chdir($dir) {
return $this->run_command('cd ' . $dir, true);
}
/**
* @access public
*
* @param string $file
* @param string $group
* @param bool $recursive
*
* @return bool
*/
public function chgrp($file, $group, $recursive = false ) {
if ( ! $this->exists($file) )
return false;
if ( ! $recursive || ! $this->is_dir($file) )
return $this->run_command(sprintf('chgrp %s %s', escapeshellarg($group), escapeshellarg($file)), true);
return $this->run_command(sprintf('chgrp -R %s %s', escapeshellarg($group), escapeshellarg($file)), true);
}
/**
* @access public
*
* @param string $file
* @param int $mode
* @param bool $recursive
* @return bool|string
*/
public function chmod($file, $mode = false, $recursive = false) {
if ( ! $this->exists($file) )
return false;
if ( ! $mode ) {
if ( $this->is_file($file) )
$mode = FS_CHMOD_FILE;
elseif ( $this->is_dir($file) )
$mode = FS_CHMOD_DIR;
else
return false;
}
if ( ! $recursive || ! $this->is_dir($file) )
return $this->run_command(sprintf('chmod %o %s', $mode, escapeshellarg($file)), true);
return $this->run_command(sprintf('chmod -R %o %s', $mode, escapeshellarg($file)), true);
}
/**
* Change the ownership of a file / folder.
*
* @access public
*
* @param string $file Path to the file.
* @param string|int $owner A user name or number.
* @param bool $recursive Optional. If set True changes file owner recursivly. Defaults to False.
* @return bool|string Returns true on success or false on failure.
*/
public function chown( $file, $owner, $recursive = false ) {
if ( ! $this->exists($file) )
return false;
if ( ! $recursive || ! $this->is_dir($file) )
return $this->run_command(sprintf('chown %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
return $this->run_command(sprintf('chown -R %s %s', escapeshellarg($owner), escapeshellarg($file)), true);
}
/**
* @access public
*
* @param string $file
* @return string|false
*/
public function owner($file) {
$owneruid = @fileowner( $this->sftp_path( $file ) );
if ( ! $owneruid )
return false;
if ( ! function_exists('posix_getpwuid') )
return $owneruid;
$ownerarray = posix_getpwuid($owneruid);
return $ownerarray['name'];
}
/**
* @access public
*
* @param string $file
* @return string
*/
public function getchmod($file) {
return substr( decoct( @fileperms( $this->sftp_path( $file ) ) ), -3 );
}
/**
* @access public
*
* @param string $file
* @return string|false
*/
public function group($file) {
$gid = @filegroup( $this->sftp_path( $file ) );
if ( ! $gid )
return false;
if ( ! function_exists('posix_getgrgid') )
return $gid;
$grouparray = posix_getgrgid($gid);
return $grouparray['name'];
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @param int|bool $mode
* @return bool
*/
public function copy($source, $destination, $overwrite = false, $mode = false) {
if ( ! $overwrite && $this->exists($destination) )
return false;
$content = $this->get_contents($source);
if ( false === $content)
return false;
return $this->put_contents($destination, $content, $mode);
}
/**
* @access public
*
* @param string $source
* @param string $destination
* @param bool $overwrite
* @return bool
*/
public function move($source, $destination, $overwrite = false) {
return @ssh2_sftp_rename( $this->sftp_link, $source, $destination );
}
/**
* @access public
*
* @param string $file
* @param bool $recursive
* @param string|bool $type
* @return bool
*/
public function delete($file, $recursive = false, $type = false) {
if ( 'f' == $type || $this->is_file($file) )
return ssh2_sftp_unlink($this->sftp_link, $file);
if ( ! $recursive )
return ssh2_sftp_rmdir($this->sftp_link, $file);
$filelist = $this->dirlist($file);
if ( is_array($filelist) ) {
foreach ( $filelist as $filename => $fileinfo) {
$this->delete($file . '/' . $filename, $recursive, $fileinfo['type']);
}
}
return ssh2_sftp_rmdir($this->sftp_link, $file);
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function exists($file) {
return file_exists( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_file($file) {
return is_file( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $path
* @return bool
*/
public function is_dir($path) {
return is_dir( $this->sftp_path( $path ) );
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_readable($file) {
return is_readable( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @return bool
*/
public function is_writable($file) {
// PHP will base it's writable checks on system_user === file_owner, not ssh_user === file_owner
return true;
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function atime($file) {
return fileatime( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function mtime($file) {
return filemtime( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @return int
*/
public function size($file) {
return filesize( $this->sftp_path( $file ) );
}
/**
* @access public
*
* @param string $file
* @param int $time
* @param int $atime
*/
public function touch($file, $time = 0, $atime = 0) {
//Not implemented.
}
/**
* @access public
*
* @param string $path
* @param mixed $chmod
* @param mixed $chown
* @param mixed $chgrp
* @return bool
*/
public function mkdir($path, $chmod = false, $chown = false, $chgrp = false) {
$path = untrailingslashit($path);
if ( empty($path) )
return false;
if ( ! $chmod )
$chmod = FS_CHMOD_DIR;
if ( ! ssh2_sftp_mkdir($this->sftp_link, $path, $chmod, true) )
return false;
if ( $chown )
$this->chown($path, $chown);
if ( $chgrp )
$this->chgrp($path, $chgrp);
return true;
}
/**
* @access public
*
* @param string $path
* @param bool $recursive
* @return bool
*/
public function rmdir($path, $recursive = false) {
return $this->delete($path, $recursive);
}
/**
* @access public
*
* @param string $path
* @param bool $include_hidden
* @param bool $recursive
* @return bool|array
*/
public function dirlist($path, $include_hidden = true, $recursive = false) {
if ( $this->is_file($path) ) {
$limit_file = basename($path);
$path = dirname($path);
} else {
$limit_file = false;
}
if ( ! $this->is_dir($path) )
return false;
$ret = array();
$dir = @dir( $this->sftp_path( $path ) );
if ( ! $dir )
return false;
while (false !== ($entry = $dir->read()) ) {
$struc = array();
$struc['name'] = $entry;
if ( '.' == $struc['name'] || '..' == $struc['name'] )
continue; //Do not care about these folders.
if ( ! $include_hidden && '.' == $struc['name'][0] )
continue;
if ( $limit_file && $struc['name'] != $limit_file )
continue;
$struc['perms'] = $this->gethchmod($path.'/'.$entry);
$struc['permsn'] = $this->getnumchmodfromh($struc['perms']);
$struc['number'] = false;
$struc['owner'] = $this->owner($path.'/'.$entry);
$struc['group'] = $this->group($path.'/'.$entry);
$struc['size'] = $this->size($path.'/'.$entry);
$struc['lastmodunix']= $this->mtime($path.'/'.$entry);
$struc['lastmod'] = date('M j',$struc['lastmodunix']);
$struc['time'] = date('h:i:s',$struc['lastmodunix']);
$struc['type'] = $this->is_dir($path.'/'.$entry) ? 'd' : 'f';
if ( 'd' == $struc['type'] ) {
if ( $recursive )
$struc['files'] = $this->dirlist($path . '/' . $struc['name'], $include_hidden, $recursive);
else
$struc['files'] = array();
}
$ret[ $struc['name'] ] = $struc;
}
$dir->close();
unset($dir);
return $ret;
}
}

View File

@@ -0,0 +1,319 @@
<?php
/**
* WP_Importer base class
*/
class WP_Importer {
/**
* Class Constructor
*
*/
public function __construct() {}
/**
* Returns array with imported permalinks from WordPress database
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $importer_name
* @param string $bid
* @return array
*/
public function get_imported_posts( $importer_name, $bid ) {
global $wpdb;
$hashtable = array();
$limit = 100;
$offset = 0;
// Grab all posts in chunks
do {
$meta_key = $importer_name . '_' . $bid . '_permalink';
$sql = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE meta_key = '%s' LIMIT %d,%d", $meta_key, $offset, $limit );
$results = $wpdb->get_results( $sql );
// Increment offset
$offset = ( $limit + $offset );
if ( !empty( $results ) ) {
foreach ( $results as $r ) {
// Set permalinks into array
$hashtable[$r->meta_value] = intval( $r->post_id );
}
}
} while ( count( $results ) == $limit );
// Unset to save memory.
unset( $results, $r );
return $hashtable;
}
/**
* Return count of imported permalinks from WordPress database
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $importer_name
* @param string $bid
* @return int
*/
public function count_imported_posts( $importer_name, $bid ) {
global $wpdb;
$count = 0;
// Get count of permalinks
$meta_key = $importer_name . '_' . $bid . '_permalink';
$sql = $wpdb->prepare( "SELECT COUNT( post_id ) AS cnt FROM $wpdb->postmeta WHERE meta_key = '%s'", $meta_key );
$result = $wpdb->get_results( $sql );
if ( !empty( $result ) )
$count = intval( $result[0]->cnt );
// Unset to save memory.
unset( $results );
return $count;
}
/**
* Set array with imported comments from WordPress database
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $bid
* @return array
*/
public function get_imported_comments( $bid ) {
global $wpdb;
$hashtable = array();
$limit = 100;
$offset = 0;
// Grab all comments in chunks
do {
$sql = $wpdb->prepare( "SELECT comment_ID, comment_agent FROM $wpdb->comments LIMIT %d,%d", $offset, $limit );
$results = $wpdb->get_results( $sql );
// Increment offset
$offset = ( $limit + $offset );
if ( !empty( $results ) ) {
foreach ( $results as $r ) {
// Explode comment_agent key
list ( $ca_bid, $source_comment_id ) = explode( '-', $r->comment_agent );
$source_comment_id = intval( $source_comment_id );
// Check if this comment came from this blog
if ( $bid == $ca_bid ) {
$hashtable[$source_comment_id] = intval( $r->comment_ID );
}
}
}
} while ( count( $results ) == $limit );
// Unset to save memory.
unset( $results, $r );
return $hashtable;
}
/**
*
* @param int $blog_id
* @return int|void
*/
public function set_blog( $blog_id ) {
if ( is_numeric( $blog_id ) ) {
$blog_id = (int) $blog_id;
} else {
$blog = 'http://' . preg_replace( '#^https?://#', '', $blog_id );
if ( ( !$parsed = parse_url( $blog ) ) || empty( $parsed['host'] ) ) {
fwrite( STDERR, "Error: can not determine blog_id from $blog_id\n" );
exit();
}
if ( empty( $parsed['path'] ) )
$parsed['path'] = '/';
$blog = get_blog_details( array( 'domain' => $parsed['host'], 'path' => $parsed['path'] ) );
if ( !$blog ) {
fwrite( STDERR, "Error: Could not find blog\n" );
exit();
}
$blog_id = (int) $blog->blog_id;
}
if ( function_exists( 'is_multisite' ) ) {
if ( is_multisite() )
switch_to_blog( $blog_id );
}
return $blog_id;
}
/**
*
* @param int $user_id
* @return int|void
*/
public function set_user( $user_id ) {
if ( is_numeric( $user_id ) ) {
$user_id = (int) $user_id;
} else {
$user_id = (int) username_exists( $user_id );
}
if ( !$user_id || !wp_set_current_user( $user_id ) ) {
fwrite( STDERR, "Error: can not find user\n" );
exit();
}
return $user_id;
}
/**
* Sort by strlen, longest string first
*
* @param string $a
* @param string $b
* @return int
*/
public function cmpr_strlen( $a, $b ) {
return strlen( $b ) - strlen( $a );
}
/**
* GET URL
*
* @param string $url
* @param string $username
* @param string $password
* @param bool $head
* @return array
*/
public function get_page( $url, $username = '', $password = '', $head = false ) {
// Increase the timeout
add_filter( 'http_request_timeout', array( $this, 'bump_request_timeout' ) );
$headers = array();
$args = array();
if ( true === $head )
$args['method'] = 'HEAD';
if ( !empty( $username ) && !empty( $password ) )
$headers['Authorization'] = 'Basic ' . base64_encode( "$username:$password" );
$args['headers'] = $headers;
return wp_safe_remote_request( $url, $args );
}
/**
* Bump up the request timeout for http requests
*
* @param int $val
* @return int
*/
public function bump_request_timeout( $val ) {
return 60;
}
/**
* Check if user has exceeded disk quota
*
* @return bool
*/
public function is_user_over_quota() {
if ( function_exists( 'upload_is_user_over_quota' ) ) {
if ( upload_is_user_over_quota() ) {
return true;
}
}
return false;
}
/**
* Replace newlines, tabs, and multiple spaces with a single space
*
* @param string $string
* @return string
*/
public function min_whitespace( $string ) {
return preg_replace( '|[\r\n\t ]+|', ' ', $string );
}
/**
* Reset global variables that grow out of control during imports
*
* @global wpdb $wpdb
* @global array $wp_actions
*/
public function stop_the_insanity() {
global $wpdb, $wp_actions;
// Or define( 'WP_IMPORTING', true );
$wpdb->queries = array();
// Reset $wp_actions to keep it from growing out of control
$wp_actions = array();
}
}
/**
* Returns value of command line params.
* Exits when a required param is not set.
*
* @param string $param
* @param bool $required
* @return mixed
*/
function get_cli_args( $param, $required = false ) {
$args = $_SERVER['argv'];
$out = array();
$last_arg = null;
$return = null;
$il = sizeof( $args );
for ( $i = 1, $il; $i < $il; $i++ ) {
if ( (bool) preg_match( "/^--(.+)/", $args[$i], $match ) ) {
$parts = explode( "=", $match[1] );
$key = preg_replace( "/[^a-z0-9]+/", "", $parts[0] );
if ( isset( $parts[1] ) ) {
$out[$key] = $parts[1];
} else {
$out[$key] = true;
}
$last_arg = $key;
} elseif ( (bool) preg_match( "/^-([a-zA-Z0-9]+)/", $args[$i], $match ) ) {
for ( $j = 0, $jl = strlen( $match[1] ); $j < $jl; $j++ ) {
$key = $match[1]{$j};
$out[$key] = true;
}
$last_arg = $key;
} elseif ( $last_arg !== null ) {
$out[$last_arg] = $args[$i];
}
}
// Check array for specified param
if ( isset( $out[$param] ) ) {
// Set return value
$return = $out[$param];
}
// Check for missing required param
if ( !isset( $out[$param] ) && $required ) {
// Display message and exit
echo "\"$param\" parameter is required but was not specified\n";
exit();
}
return $return;
}

View File

@@ -0,0 +1,166 @@
<?php
/**
* Administration API: WP_Internal_Pointers class
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Core class used to implement an internal admin pointers API.
*
* @since 3.3.0
*/
final class WP_Internal_Pointers {
/**
* Initializes the new feature pointers.
*
* @since 3.3.0
*
* All pointers can be disabled using the following:
* remove_action( 'admin_enqueue_scripts', array( 'WP_Internal_Pointers', 'enqueue_scripts' ) );
*
* Individual pointers (e.g. wp390_widgets) can be disabled using the following:
* remove_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_wp390_widgets' ) );
*
* @static
*
* @param string $hook_suffix The current admin page.
*/
public static function enqueue_scripts( $hook_suffix ) {
/*
* Register feature pointers
*
* Format:
* array(
* hook_suffix => pointer callback
* )
*
* Example:
* array(
* 'themes.php' => 'wp390_widgets'
* )
*/
$registered_pointers = array(
// None currently
);
// Check if screen related pointer is registered
if ( empty( $registered_pointers[ $hook_suffix ] ) )
return;
$pointers = (array) $registered_pointers[ $hook_suffix ];
/*
* Specify required capabilities for feature pointers
*
* Format:
* array(
* pointer callback => Array of required capabilities
* )
*
* Example:
* array(
* 'wp390_widgets' => array( 'edit_theme_options' )
* )
*/
$caps_required = array(
// None currently
);
// Get dismissed pointers
$dismissed = explode( ',', (string) get_user_meta( get_current_user_id(), 'dismissed_wp_pointers', true ) );
$got_pointers = false;
foreach ( array_diff( $pointers, $dismissed ) as $pointer ) {
if ( isset( $caps_required[ $pointer ] ) ) {
foreach ( $caps_required[ $pointer ] as $cap ) {
if ( ! current_user_can( $cap ) )
continue 2;
}
}
// Bind pointer print function
add_action( 'admin_print_footer_scripts', array( 'WP_Internal_Pointers', 'pointer_' . $pointer ) );
$got_pointers = true;
}
if ( ! $got_pointers )
return;
// Add pointers script and style to queue
wp_enqueue_style( 'wp-pointer' );
wp_enqueue_script( 'wp-pointer' );
}
/**
* Print the pointer JavaScript data.
*
* @since 3.3.0
*
* @static
*
* @param string $pointer_id The pointer ID.
* @param string $selector The HTML elements, on which the pointer should be attached.
* @param array $args Arguments to be passed to the pointer JS (see wp-pointer.js).
*/
private static function print_js( $pointer_id, $selector, $args ) {
if ( empty( $pointer_id ) || empty( $selector ) || empty( $args ) || empty( $args['content'] ) )
return;
?>
<script type="text/javascript">
(function($){
var options = <?php echo wp_json_encode( $args ); ?>, setup;
if ( ! options )
return;
options = $.extend( options, {
close: function() {
$.post( ajaxurl, {
pointer: '<?php echo $pointer_id; ?>',
action: 'dismiss-wp-pointer'
});
}
});
setup = function() {
$('<?php echo $selector; ?>').first().pointer( options ).pointer('open');
};
if ( options.position && options.position.defer_loading )
$(window).bind( 'load.wp-pointers', setup );
else
$(document).ready( setup );
})( jQuery );
</script>
<?php
}
public static function pointer_wp330_toolbar() {}
public static function pointer_wp330_media_uploader() {}
public static function pointer_wp330_saving_widgets() {}
public static function pointer_wp340_customize_current_theme_link() {}
public static function pointer_wp340_choose_image_from_library() {}
public static function pointer_wp350_media() {}
public static function pointer_wp360_revisions() {}
public static function pointer_wp360_locks() {}
public static function pointer_wp390_widgets() {}
public static function pointer_wp410_dfw() {}
/**
* Prevents new users from seeing existing 'new feature' pointers.
*
* @since 3.3.0
*
* @static
*
* @param int $user_id User ID.
*/
public static function dismiss_pointers_for_new_users( $user_id ) {
add_user_meta( $user_id, 'dismissed_wp_pointers', '' );
}
}

View File

@@ -0,0 +1,333 @@
<?php
/**
* List Table API: WP_Links_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying links in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Tsble
*/
class WP_Links_List_Table extends WP_List_Table {
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
parent::__construct( array(
'plural' => 'bookmarks',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
}
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can( 'manage_links' );
}
/**
*
* @global int $cat_id
* @global string $s
* @global string $orderby
* @global string $order
*/
public function prepare_items() {
global $cat_id, $s, $orderby, $order;
wp_reset_vars( array( 'action', 'cat_id', 'link_id', 'orderby', 'order', 's' ) );
$args = array( 'hide_invisible' => 0, 'hide_empty' => 0 );
if ( 'all' != $cat_id )
$args['category'] = $cat_id;
if ( !empty( $s ) )
$args['search'] = $s;
if ( !empty( $orderby ) )
$args['orderby'] = $orderby;
if ( !empty( $order ) )
$args['order'] = $order;
$this->items = get_bookmarks( $args );
}
/**
* @access public
*/
public function no_items() {
_e( 'No links found.' );
}
/**
*
* @return array
*/
protected function get_bulk_actions() {
$actions = array();
$actions['delete'] = __( 'Delete' );
return $actions;
}
/**
*
* @global int $cat_id
* @param string $which
*/
protected function extra_tablenav( $which ) {
global $cat_id;
if ( 'top' != $which )
return;
?>
<div class="alignleft actions">
<?php
$dropdown_options = array(
'selected' => $cat_id,
'name' => 'cat_id',
'taxonomy' => 'link_category',
'show_option_all' => get_taxonomy( 'link_category' )->labels->all_items,
'hide_empty' => true,
'hierarchical' => 1,
'show_count' => 0,
'orderby' => 'name',
);
echo '<label class="screen-reader-text" for="cat_id">' . __( 'Filter by category' ) . '</label>';
wp_dropdown_categories( $dropdown_options );
submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
?>
</div>
<?php
}
/**
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'name' => _x( 'Name', 'link name' ),
'url' => __( 'URL' ),
'categories' => __( 'Categories' ),
'rel' => __( 'Relationship' ),
'visible' => __( 'Visible' ),
'rating' => __( 'Rating' )
);
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'name' => 'name',
'url' => 'url',
'visible' => 'visible',
'rating' => 'rating'
);
}
/**
* Get the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'name'.
*/
protected function get_default_primary_column_name() {
return 'name';
}
/**
* Handles the checkbox column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_cb( $link ) {
?>
<label class="screen-reader-text" for="cb-select-<?php echo $link->link_id; ?>"><?php echo sprintf( __( 'Select %s' ), $link->link_name ); ?></label>
<input type="checkbox" name="linkcheck[]" id="cb-select-<?php echo $link->link_id; ?>" value="<?php echo esc_attr( $link->link_id ); ?>" />
<?php
}
/**
* Handles the link name column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_name( $link ) {
$edit_link = get_edit_bookmark_link( $link );
printf( '<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong>',
$edit_link,
/* translators: %s: link name */
esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $link->link_name ) ),
$link->link_name
);
}
/**
* Handles the link URL column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_url( $link ) {
$short_url = url_shorten( $link->link_url );
echo "<a href='$link->link_url'>$short_url</a>";
}
/**
* Handles the link categories column output.
*
* @since 4.3.0
* @access public
*
* @global $cat_id
*
* @param object $link The current link object.
*/
public function column_categories( $link ) {
global $cat_id;
$cat_names = array();
foreach ( $link->link_category as $category ) {
$cat = get_term( $category, 'link_category', OBJECT, 'display' );
if ( is_wp_error( $cat ) ) {
echo $cat->get_error_message();
}
$cat_name = $cat->name;
if ( $cat_id != $category ) {
$cat_name = "<a href='link-manager.php?cat_id=$category'>$cat_name</a>";
}
$cat_names[] = $cat_name;
}
echo implode( ', ', $cat_names );
}
/**
* Handles the link relation column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_rel( $link ) {
echo empty( $link->link_rel ) ? '<br />' : $link->link_rel;
}
/**
* Handles the link visibility column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_visible( $link ) {
if ( 'Y' === $link->link_visible ) {
_e( 'Yes' );
} else {
_e( 'No' );
}
}
/**
* Handles the link rating column output.
*
* @since 4.3.0
* @access public
*
* @param object $link The current link object.
*/
public function column_rating( $link ) {
echo $link->link_rating;
}
/**
* Handles the default column output.
*
* @since 4.3.0
* @access public
*
* @param object $link Link object.
* @param string $column_name Current column name.
*/
public function column_default( $link, $column_name ) {
/**
* Fires for each registered custom link column.
*
* @since 2.1.0
*
* @param string $column_name Name of the custom column.
* @param int $link_id Link ID.
*/
do_action( 'manage_link_custom_column', $column_name, $link->link_id );
}
public function display_rows() {
foreach ( $this->items as $link ) {
$link = sanitize_bookmark( $link );
$link->link_name = esc_attr( $link->link_name );
$link->link_category = wp_get_link_cats( $link->link_id );
?>
<tr id="link-<?php echo $link->link_id; ?>">
<?php $this->single_row_columns( $link ) ?>
</tr>
<?php
}
}
/**
* Generates and displays row action links.
*
* @since 4.3.0
* @access protected
*
* @param object $link Link being acted upon.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string Row action output for links.
*/
protected function handle_row_actions( $link, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$edit_link = get_edit_bookmark_link( $link );
$actions = array();
$actions['edit'] = '<a href="' . $edit_link . '">' . __('Edit') . '</a>';
$actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url("link.php?action=delete&amp;link_id=$link->link_id", 'delete-bookmark_' . $link->link_id) . "' onclick=\"if ( confirm( '" . esc_js(sprintf(__("You are about to delete this link '%s'\n 'Cancel' to stop, 'OK' to delete."), $link->link_name)) . "' ) ) { return true;}return false;\">" . __('Delete') . "</a>";
return $this->row_actions( $actions );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,780 @@
<?php
/**
* List Table API: WP_Media_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying media items in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Media_List_Table extends WP_List_Table {
/**
* Holds the number of pending comments for each post.
*
* @since 4.4.0
* @var array
* @access protected
*/
protected $comment_pending_count = array();
private $detached;
private $is_trash;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
$this->detached = ( isset( $_REQUEST['attachment-filter'] ) && 'detached' === $_REQUEST['attachment-filter'] );
$this->modes = array(
'list' => __( 'List View' ),
'grid' => __( 'Grid View' )
);
parent::__construct( array(
'plural' => 'media',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
}
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can('upload_files');
}
/**
*
* @global WP_Query $wp_query
* @global array $post_mime_types
* @global array $avail_post_mime_types
* @global string $mode
*/
public function prepare_items() {
global $wp_query, $post_mime_types, $avail_post_mime_types, $mode;
list( $post_mime_types, $avail_post_mime_types ) = wp_edit_attachments_query( $_REQUEST );
$this->is_trash = isset( $_REQUEST['attachment-filter'] ) && 'trash' === $_REQUEST['attachment-filter'];
$mode = empty( $_REQUEST['mode'] ) ? 'list' : $_REQUEST['mode'];
$this->set_pagination_args( array(
'total_items' => $wp_query->found_posts,
'total_pages' => $wp_query->max_num_pages,
'per_page' => $wp_query->query_vars['posts_per_page'],
) );
}
/**
* @global array $post_mime_types
* @global array $avail_post_mime_types
* @return array
*/
protected function get_views() {
global $post_mime_types, $avail_post_mime_types;
$type_links = array();
$filter = empty( $_GET['attachment-filter'] ) ? '' : $_GET['attachment-filter'];
$type_links['all'] = sprintf(
'<option value=""%s>%s</option>',
selected( $filter, true, false ),
__( 'All media items' )
);
foreach ( $post_mime_types as $mime_type => $label ) {
if ( ! wp_match_mime_types( $mime_type, $avail_post_mime_types ) ) {
continue;
}
$selected = selected(
$filter && 0 === strpos( $filter, 'post_mime_type:' ) &&
wp_match_mime_types( $mime_type, str_replace( 'post_mime_type:', '', $filter ) ),
true,
false
);
$type_links[$mime_type] = sprintf(
'<option value="post_mime_type:%s"%s>%s</option>',
esc_attr( $mime_type ),
$selected,
$label[0]
);
}
$type_links['detached'] = '<option value="detached"' . ( $this->detached ? ' selected="selected"' : '' ) . '>' . __( 'Unattached' ) . '</option>';
if ( $this->is_trash || ( defined( 'MEDIA_TRASH') && MEDIA_TRASH ) ) {
$type_links['trash'] = sprintf(
'<option value="trash"%s>%s</option>',
selected( 'trash' === $filter, true, false ),
_x( 'Trash', 'attachment filter' )
);
}
return $type_links;
}
/**
*
* @return array
*/
protected function get_bulk_actions() {
$actions = array();
if ( MEDIA_TRASH ) {
if ( $this->is_trash ) {
$actions['untrash'] = __( 'Restore' );
$actions['delete'] = __( 'Delete Permanently' );
} else {
$actions['trash'] = _x( 'Trash', 'verb' );
}
} else {
$actions['delete'] = __( 'Delete Permanently' );
}
if ( $this->detached )
$actions['attach'] = __( 'Attach' );
return $actions;
}
/**
* @param string $which
*/
protected function extra_tablenav( $which ) {
if ( 'bar' !== $which ) {
return;
}
?>
<div class="actions">
<?php
if ( ! is_singular() ) {
if ( ! $this->is_trash ) {
$this->months_dropdown( 'attachment' );
}
/** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
do_action( 'restrict_manage_posts', $this->screen->post_type );
submit_button( __( 'Filter' ), 'button', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
}
if ( $this->is_trash && current_user_can( 'edit_others_posts' ) ) {
submit_button( __( 'Empty Trash' ), 'apply', 'delete_all', false );
} ?>
</div>
<?php
}
/**
*
* @return string
*/
public function current_action() {
if ( isset( $_REQUEST['found_post_id'] ) && isset( $_REQUEST['media'] ) )
return 'attach';
if ( isset( $_REQUEST['parent_post_id'] ) && isset( $_REQUEST['media'] ) )
return 'detach';
if ( isset( $_REQUEST['delete_all'] ) || isset( $_REQUEST['delete_all2'] ) )
return 'delete_all';
return parent::current_action();
}
/**
*
* @return bool
*/
public function has_items() {
return have_posts();
}
/**
* @access public
*/
public function no_items() {
_e( 'No media files found.' );
}
/**
* Override parent views so we can use the filter bar display.
*
* @global string $mode
*/
public function views() {
global $mode;
$views = $this->get_views();
$this->screen->render_screen_reader_content( 'heading_views' );
?>
<div class="wp-filter">
<div class="filter-items">
<?php $this->view_switcher( $mode ); ?>
<label for="attachment-filter" class="screen-reader-text"><?php _e( 'Filter by type' ); ?></label>
<select class="attachment-filters" name="attachment-filter" id="attachment-filter">
<?php
if ( ! empty( $views ) ) {
foreach ( $views as $class => $view ) {
echo "\t$view\n";
}
}
?>
</select>
<?php
$this->extra_tablenav( 'bar' );
/** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
$views = apply_filters( "views_{$this->screen->id}", array() );
// Back compat for pre-4.0 view links.
if ( ! empty( $views ) ) {
echo '<ul class="filter-links">';
foreach ( $views as $class => $view ) {
echo "<li class='$class'>$view</li>";
}
echo '</ul>';
}
?>
</div>
<div class="search-form">
<label for="media-search-input" class="screen-reader-text"><?php esc_html_e( 'Search Media' ); ?></label>
<input type="search" placeholder="<?php esc_attr_e( 'Search' ) ?>" id="media-search-input" class="search" name="s" value="<?php _admin_search_query(); ?>"></div>
</div>
<?php
}
/**
*
* @return array
*/
public function get_columns() {
$posts_columns = array();
$posts_columns['cb'] = '<input type="checkbox" />';
/* translators: column name */
$posts_columns['title'] = _x( 'File', 'column name' );
$posts_columns['author'] = __( 'Author' );
$taxonomies = get_taxonomies_for_attachments( 'objects' );
$taxonomies = wp_filter_object_list( $taxonomies, array( 'show_admin_column' => true ), 'and', 'name' );
/**
* Filter the taxonomy columns for attachments in the Media list table.
*
* @since 3.5.0
*
* @param array $taxonomies An array of registered taxonomies to show for attachments.
* @param string $post_type The post type. Default 'attachment'.
*/
$taxonomies = apply_filters( 'manage_taxonomies_for_attachment_columns', $taxonomies, 'attachment' );
$taxonomies = array_filter( $taxonomies, 'taxonomy_exists' );
foreach ( $taxonomies as $taxonomy ) {
if ( 'category' === $taxonomy ) {
$column_key = 'categories';
} elseif ( 'post_tag' === $taxonomy ) {
$column_key = 'tags';
} else {
$column_key = 'taxonomy-' . $taxonomy;
}
$posts_columns[ $column_key ] = get_taxonomy( $taxonomy )->labels->name;
}
/* translators: column name */
if ( !$this->detached ) {
$posts_columns['parent'] = _x( 'Uploaded to', 'column name' );
if ( post_type_supports( 'attachment', 'comments' ) )
$posts_columns['comments'] = '<span class="vers comment-grey-bubble" title="' . esc_attr__( 'Comments' ) . '"><span class="screen-reader-text">' . __( 'Comments' ) . '</span></span>';
}
/* translators: column name */
$posts_columns['date'] = _x( 'Date', 'column name' );
/**
* Filter the Media list table columns.
*
* @since 2.5.0
*
* @param array $posts_columns An array of columns displayed in the Media list table.
* @param bool $detached Whether the list table contains media not attached
* to any posts. Default true.
*/
return apply_filters( 'manage_media_columns', $posts_columns, $this->detached );
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'title' => 'title',
'author' => 'author',
'parent' => 'parent',
'comments' => 'comment_count',
'date' => array( 'date', true ),
);
}
/**
* Handles the checkbox column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_cb( $post ) {
if ( current_user_can( 'edit_post', $post->ID ) ) { ?>
<label class="screen-reader-text" for="cb-select-<?php echo $post->ID; ?>"><?php
echo sprintf( __( 'Select %s' ), _draft_or_post_title() );
?></label>
<input type="checkbox" name="media[]" id="cb-select-<?php echo $post->ID; ?>" value="<?php echo $post->ID; ?>" />
<?php }
}
/**
* Handles the title column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_title( $post ) {
list( $mime ) = explode( '/', $post->post_mime_type );
$title = _draft_or_post_title();
$thumb = wp_get_attachment_image( $post->ID, array( 60, 60 ), true, array( 'alt' => '' ) );
$link_start = $link_end = '';
if ( current_user_can( 'edit_post', $post->ID ) && ! $this->is_trash ) {
$link_start = sprintf(
'<a href="%s" aria-label="%s">',
get_edit_post_link( $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( '&#8220;%s&#8221; (Edit)' ), $title ) )
);
$link_end = '</a>';
}
$class = $thumb ? ' class="has-media-icon"' : '';
?>
<strong<?php echo $class; ?>>
<?php
echo $link_start;
if ( $thumb ) : ?>
<span class="media-icon <?php echo sanitize_html_class( $mime . '-icon' ); ?>"><?php echo $thumb; ?></span>
<?php endif;
echo $title . $link_end;
_media_states( $post );
?>
</strong>
<p class="filename">
<span class="screen-reader-text"><?php _e( 'File name:' ); ?> </span>
<?php
$file = get_attached_file( $post->ID );
echo esc_html( wp_basename( $file ) );
?>
</p>
<?php
}
/**
* Handles the author column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_author( $post ) {
printf( '<a href="%s">%s</a>',
esc_url( add_query_arg( array( 'author' => get_the_author_meta('ID') ), 'upload.php' ) ),
get_the_author()
);
}
/**
* Handles the description column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_desc( $post ) {
echo has_excerpt() ? $post->post_excerpt : '';
}
/**
* Handles the date column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_date( $post ) {
if ( '0000-00-00 00:00:00' === $post->post_date ) {
$h_time = __( 'Unpublished' );
} else {
$m_time = $post->post_date;
$time = get_post_time( 'G', true, $post, false );
if ( ( abs( $t_diff = time() - $time ) ) < DAY_IN_SECONDS ) {
if ( $t_diff < 0 ) {
$h_time = sprintf( __( '%s from now' ), human_time_diff( $time ) );
} else {
$h_time = sprintf( __( '%s ago' ), human_time_diff( $time ) );
}
} else {
$h_time = mysql2date( __( 'Y/m/d' ), $m_time );
}
}
echo $h_time;
}
/**
* Handles the parent column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_parent( $post ) {
$user_can_edit = current_user_can( 'edit_post', $post->ID );
if ( $post->post_parent > 0 ) {
$parent = get_post( $post->post_parent );
} else {
$parent = false;
}
if ( $parent ) {
$title = _draft_or_post_title( $post->post_parent );
$parent_type = get_post_type_object( $parent->post_type );
?>
<strong>
<?php if ( $parent_type && $parent_type->show_ui && current_user_can( 'edit_post', $post->post_parent ) ) { ?>
<a href="<?php echo get_edit_post_link( $post->post_parent ); ?>">
<?php echo $title ?></a><?php
} else {
echo $title;
} ?></strong>
<br />
<?php
if ( $user_can_edit ):
$detach_url = add_query_arg( array(
'parent_post_id' => $post->post_parent,
'media[]' => $post->ID,
'_wpnonce' => wp_create_nonce( 'bulk-' . $this->_args['plural'] )
), 'upload.php' );
printf(
'<a href="%s" class="hide-if-no-js detach-from-parent" aria-label="%s">%s</a>',
$detach_url,
/* translators: %s: title of the post the attachment is attached to */
esc_attr( sprintf( __( 'Detach from &#8220;%s&#8221;' ), $title ) ),
__( 'Detach' )
);
endif;
} else {
_e( '(Unattached)' ); ?><br />
<?php if ( $user_can_edit ) {
$title = _draft_or_post_title( $post->post_parent );
printf(
'<a href="#the-list" onclick="findPosts.open( \'media[]\', \'%s\' ); return false;" class="hide-if-no-js" aria-label="%s">%s</a>',
$post->ID,
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Attach &#8220;%s&#8221; to existing content' ), $title ) ),
__( 'Attach' )
);
}
}
}
/**
* Handles the comments column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
*/
public function column_comments( $post ) {
echo '<div class="post-com-count-wrapper">';
if ( isset( $this->comment_pending_count[ $post->ID ] ) ) {
$pending_comments = $this->comment_pending_count[ $post->ID ];
} else {
$pending_comments = get_pending_comments_num( $post->ID );
}
$this->comments_bubble( $post->ID, $pending_comments );
echo '</div>';
}
/**
* Handles output for the default column.
*
* @since 4.3.0
* @access public
*
* @param WP_Post $post The current WP_Post object.
* @param string $column_name Current column name.
*/
public function column_default( $post, $column_name ) {
if ( 'categories' === $column_name ) {
$taxonomy = 'category';
} elseif ( 'tags' === $column_name ) {
$taxonomy = 'post_tag';
} elseif ( 0 === strpos( $column_name, 'taxonomy-' ) ) {
$taxonomy = substr( $column_name, 9 );
} else {
$taxonomy = false;
}
if ( $taxonomy ) {
$terms = get_the_terms( $post->ID, $taxonomy );
if ( is_array( $terms ) ) {
$out = array();
foreach ( $terms as $t ) {
$posts_in_term_qv = array();
$posts_in_term_qv['taxonomy'] = $taxonomy;
$posts_in_term_qv['term'] = $t->slug;
$out[] = sprintf( '<a href="%s">%s</a>',
esc_url( add_query_arg( $posts_in_term_qv, 'upload.php' ) ),
esc_html( sanitize_term_field( 'name', $t->name, $t->term_id, $taxonomy, 'display' ) )
);
}
/* translators: used between list items, there is a space after the comma */
echo join( __( ', ' ), $out );
} else {
echo '<span aria-hidden="true">&#8212;</span><span class="screen-reader-text">' . get_taxonomy( $taxonomy )->labels->no_terms . '</span>';
}
return;
}
/**
* Fires for each custom column in the Media list table.
*
* Custom columns are registered using the {@see 'manage_media_columns'} filter.
*
* @since 2.5.0
*
* @param string $column_name Name of the custom column.
* @param int $post_id Attachment ID.
*/
do_action( 'manage_media_custom_column', $column_name, $post->ID );
}
/**
*
* @global WP_Post $post
*/
public function display_rows() {
global $post, $wp_query;
$post_ids = wp_list_pluck( $wp_query->posts, 'ID' );
reset( $wp_query->posts );
$this->comment_pending_count = get_pending_comments_num( $post_ids );
add_filter( 'the_title','esc_html' );
while ( have_posts() ) : the_post();
if (
( $this->is_trash && $post->post_status != 'trash' )
|| ( ! $this->is_trash && $post->post_status === 'trash' )
) {
continue;
}
$post_owner = ( get_current_user_id() == $post->post_author ) ? 'self' : 'other';
?>
<tr id="post-<?php echo $post->ID; ?>" class="<?php echo trim( ' author-' . $post_owner . ' status-' . $post->post_status ); ?>">
<?php $this->single_row_columns( $post ); ?>
</tr>
<?php
endwhile;
}
/**
* Gets the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'title'.
*/
protected function get_default_primary_column_name() {
return 'title';
}
/**
* @param WP_Post $post
* @param string $att_title
*
* @return array
*/
private function _get_row_actions( $post, $att_title ) {
$actions = array();
if ( $this->detached ) {
if ( current_user_can( 'edit_post', $post->ID ) ) {
$actions['edit'] = sprintf(
'<a href="%s" aria-label="%s">%s</a>',
get_edit_post_link( $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ),
__( 'Edit' )
);
}
if ( current_user_can( 'delete_post', $post->ID ) ) {
if ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
$actions['trash'] = sprintf(
'<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $att_title ) ),
_x( 'Trash', 'verb' )
);
} else {
$delete_ays = ! MEDIA_TRASH ? " onclick='return showNotice.warn();'" : '';
$actions['delete'] = sprintf(
'<a href="%s" class="submitdelete"%s aria-label="%s">%s</a>',
wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ),
$delete_ays,
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $att_title ) ),
__( 'Delete Permanently' )
);
}
}
$actions['view'] = sprintf(
'<a href="%s" aria-label="%s" rel="permalink">%s</a>',
get_permalink( $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ),
__( 'View' )
);
if ( current_user_can( 'edit_post', $post->ID ) ) {
$actions['attach'] = sprintf(
'<a href="#the-list" onclick="findPosts.open( \'media[]\', \'%s\' ); return false;" class="hide-if-no-js" aria-label="%s">%s</a>',
$post->ID,
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Attach &#8220;%s&#8221; to existing content' ), $att_title ) ),
__( 'Attach' )
);
}
}
else {
if ( current_user_can( 'edit_post', $post->ID ) && !$this->is_trash ) {
$actions['edit'] = sprintf(
'<a href="%s" aria-label="%s">%s</a>',
get_edit_post_link( $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $att_title ) ),
__( 'Edit' )
);
}
if ( current_user_can( 'delete_post', $post->ID ) ) {
if ( $this->is_trash ) {
$actions['untrash'] = sprintf(
'<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
wp_nonce_url( "post.php?action=untrash&amp;post=$post->ID", 'untrash-post_' . $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Restore &#8220;%s&#8221; from the Trash' ), $att_title ) ),
__( 'Restore' )
);
} elseif ( EMPTY_TRASH_DAYS && MEDIA_TRASH ) {
$actions['trash'] = sprintf(
'<a href="%s" class="submitdelete" aria-label="%s">%s</a>',
wp_nonce_url( "post.php?action=trash&amp;post=$post->ID", 'trash-post_' . $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Move &#8220;%s&#8221; to the Trash' ), $att_title ) ),
_x( 'Trash', 'verb' )
);
}
if ( $this->is_trash || ! EMPTY_TRASH_DAYS || ! MEDIA_TRASH ) {
$delete_ays = ( !$this->is_trash && !MEDIA_TRASH ) ? " onclick='return showNotice.warn();'" : '';
$actions['delete'] = sprintf(
'<a href="%s" class="submitdelete"%s aria-label="%s">%s</a>',
wp_nonce_url( "post.php?action=delete&amp;post=$post->ID", 'delete-post_' . $post->ID ),
$delete_ays,
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'Delete &#8220;%s&#8221; permanently' ), $att_title ) ),
__( 'Delete Permanently' )
);
}
}
if ( ! $this->is_trash ) {
$actions['view'] = sprintf(
'<a href="%s" aria-label="%s" rel="permalink">%s</a>',
get_permalink( $post->ID ),
/* translators: %s: attachment title */
esc_attr( sprintf( __( 'View &#8220;%s&#8221;' ), $att_title ) ),
__( 'View' )
);
}
}
/**
* Filter the action links for each attachment in the Media list table.
*
* @since 2.8.0
*
* @param array $actions An array of action links for each attachment.
* Default 'Edit', 'Delete Permanently', 'View'.
* @param WP_Post $post WP_Post object for the current attachment.
* @param bool $detached Whether the list table contains media not attached
* to any posts. Default true.
*/
return apply_filters( 'media_row_actions', $actions, $post, $this->detached );
}
/**
* Generates and displays row action links.
*
* @since 4.3.0
* @access protected
*
* @param object $post Attachment being acted upon.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string Row actions output for media attachments.
*/
protected function handle_row_actions( $post, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$att_title = _draft_or_post_title();
return $this->row_actions( $this->_get_row_actions( $post, $att_title ) );
}
}

View File

@@ -0,0 +1,551 @@
<?php
/**
* List Table API: WP_MS_Sites_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying sites in a list table for the network admin.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_MS_Sites_List_Table extends WP_List_Table {
/**
* Site status list.
*
* @since 4.3.0
* @access public
* @var array
*/
public $status_list;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
$this->status_list = array(
'archived' => array( 'site-archived', __( 'Archived' ) ),
'spam' => array( 'site-spammed', _x( 'Spam', 'site' ) ),
'deleted' => array( 'site-deleted', __( 'Deleted' ) ),
'mature' => array( 'site-mature', __( 'Mature' ) )
);
parent::__construct( array(
'plural' => 'sites',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
}
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can( 'manage_sites' );
}
/**
*
* @global string $s
* @global string $mode
* @global wpdb $wpdb
*/
public function prepare_items() {
global $s, $mode, $wpdb;
$current_site = get_current_site();
if ( ! empty( $_REQUEST['mode'] ) ) {
$mode = $_REQUEST['mode'] === 'excerpt' ? 'excerpt' : 'list';
set_user_setting( 'sites_list_mode', $mode );
} else {
$mode = get_user_setting( 'sites_list_mode', 'list' );
}
$per_page = $this->get_items_per_page( 'sites_network_per_page' );
$pagenum = $this->get_pagenum();
$s = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST[ 's' ] ) ) : '';
$wild = '';
if ( false !== strpos($s, '*') ) {
$wild = '%';
$s = trim($s, '*');
}
/*
* If the network is large and a search is not being performed, show only
* the latest sites with no paging in order to avoid expensive count queries.
*/
if ( !$s && wp_is_large_network() ) {
if ( !isset($_REQUEST['orderby']) )
$_GET['orderby'] = $_REQUEST['orderby'] = '';
if ( !isset($_REQUEST['order']) )
$_GET['order'] = $_REQUEST['order'] = 'DESC';
}
$query = "SELECT * FROM {$wpdb->blogs} WHERE site_id = '{$wpdb->siteid}' ";
if ( empty($s) ) {
// Nothing to do.
} elseif ( preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/', $s ) ||
preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
preg_match( '/^[0-9]{1,3}\.[0-9]{1,3}\.?$/', $s ) ||
preg_match( '/^[0-9]{1,3}\.$/', $s ) ) {
// IPv4 address
$sql = $wpdb->prepare( "SELECT blog_id FROM {$wpdb->registration_log} WHERE {$wpdb->registration_log}.IP LIKE %s", $wpdb->esc_like( $s ) . $wild );
$reg_blog_ids = $wpdb->get_col( $sql );
if ( !$reg_blog_ids )
$reg_blog_ids = array( 0 );
$query = "SELECT *
FROM {$wpdb->blogs}
WHERE site_id = '{$wpdb->siteid}'
AND {$wpdb->blogs}.blog_id IN (" . implode( ', ', $reg_blog_ids ) . ")";
} else {
if ( is_numeric($s) && empty( $wild ) ) {
$query .= $wpdb->prepare( " AND ( {$wpdb->blogs}.blog_id = %s )", $s );
} elseif ( is_subdomain_install() ) {
$blog_s = str_replace( '.' . $current_site->domain, '', $s );
$blog_s = $wpdb->esc_like( $blog_s ) . $wild . $wpdb->esc_like( '.' . $current_site->domain );
$query .= $wpdb->prepare( " AND ( {$wpdb->blogs}.domain LIKE %s ) ", $blog_s );
} else {
if ( $s != trim('/', $current_site->path) ) {
$blog_s = $wpdb->esc_like( $current_site->path . $s ) . $wild . $wpdb->esc_like( '/' );
} else {
$blog_s = $wpdb->esc_like( $s );
}
$query .= $wpdb->prepare( " AND ( {$wpdb->blogs}.path LIKE %s )", $blog_s );
}
}
$order_by = isset( $_REQUEST['orderby'] ) ? $_REQUEST['orderby'] : '';
if ( $order_by === 'registered' ) {
$query .= ' ORDER BY registered ';
} elseif ( $order_by === 'lastupdated' ) {
$query .= ' ORDER BY last_updated ';
} elseif ( $order_by === 'blogname' ) {
if ( is_subdomain_install() ) {
$query .= ' ORDER BY domain ';
} else {
$query .= ' ORDER BY path ';
}
} elseif ( $order_by === 'blog_id' ) {
$query .= ' ORDER BY blog_id ';
} else {
$order_by = null;
}
if ( isset( $order_by ) ) {
$order = ( isset( $_REQUEST['order'] ) && 'DESC' === strtoupper( $_REQUEST['order'] ) ) ? "DESC" : "ASC";
$query .= $order;
}
// Don't do an unbounded count on large networks
if ( ! wp_is_large_network() )
$total = $wpdb->get_var( str_replace( 'SELECT *', 'SELECT COUNT( blog_id )', $query ) );
$query .= " LIMIT " . intval( ( $pagenum - 1 ) * $per_page ) . ", " . intval( $per_page );
$this->items = $wpdb->get_results( $query, ARRAY_A );
if ( wp_is_large_network() )
$total = count($this->items);
$this->set_pagination_args( array(
'total_items' => $total,
'per_page' => $per_page,
) );
}
/**
* @access public
*/
public function no_items() {
_e( 'No sites found.' );
}
/**
*
* @return array
*/
protected function get_bulk_actions() {
$actions = array();
if ( current_user_can( 'delete_sites' ) )
$actions['delete'] = __( 'Delete' );
$actions['spam'] = _x( 'Mark as Spam', 'site' );
$actions['notspam'] = _x( 'Not Spam', 'site' );
return $actions;
}
/**
* @global string $mode
*
* @param string $which
*/
protected function pagination( $which ) {
global $mode;
parent::pagination( $which );
if ( 'top' === $which )
$this->view_switcher( $mode );
}
/**
* @return array
*/
public function get_columns() {
$sites_columns = array(
'cb' => '<input type="checkbox" />',
'blogname' => __( 'URL' ),
'lastupdated' => __( 'Last Updated' ),
'registered' => _x( 'Registered', 'site' ),
'users' => __( 'Users' ),
);
if ( has_filter( 'wpmublogsaction' ) ) {
$sites_columns['plugins'] = __( 'Actions' );
}
/**
* Filter the displayed site columns in Sites list table.
*
* @since MU
*
* @param array $sites_columns An array of displayed site columns. Default 'cb',
* 'blogname', 'lastupdated', 'registered', 'users'.
*/
return apply_filters( 'wpmu_blogs_columns', $sites_columns );
}
/**
* @return array
*/
protected function get_sortable_columns() {
return array(
'blogname' => 'blogname',
'lastupdated' => 'lastupdated',
'registered' => 'blog_id',
);
}
/**
* Handles the checkbox column output.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
*/
public function column_cb( $blog ) {
if ( ! is_main_site( $blog['blog_id'] ) ) :
$blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
?>
<label class="screen-reader-text" for="blog_<?php echo $blog['blog_id']; ?>"><?php
printf( __( 'Select %s' ), $blogname );
?></label>
<input type="checkbox" id="blog_<?php echo $blog['blog_id'] ?>" name="allblogs[]" value="<?php echo esc_attr( $blog['blog_id'] ) ?>" />
<?php endif;
}
/**
* Handles the ID column output.
*
* @since 4.4.0
* @access public
*
* @param array $blog Current site.
*/
public function column_id( $blog ) {
echo $blog['blog_id'];
}
/**
* Handles the site name column output.
*
* @since 4.3.0
* @access public
*
* @global string $mode
*
* @param array $blog Current site.
*/
public function column_blogname( $blog ) {
global $mode;
$blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
$blog_states = array();
reset( $this->status_list );
foreach ( $this->status_list as $status => $col ) {
if ( $blog[ $status ] == 1 ) {
$blog_states[] = $col[1];
}
}
$blog_state = '';
if ( ! empty( $blog_states ) ) {
$state_count = count( $blog_states );
$i = 0;
$blog_state .= ' - ';
foreach ( $blog_states as $state ) {
++$i;
$sep = ( $i == $state_count ) ? '' : ', ';
$blog_state .= "<span class='post-state'>$state$sep</span>";
}
}
?>
<a href="<?php echo esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ); ?>" class="edit"><?php echo $blogname . $blog_state; ?></a>
<?php
if ( 'list' !== $mode ) {
switch_to_blog( $blog['blog_id'] );
echo '<p>';
printf(
/* translators: 1: site name, 2: site tagline. */
__( '%1$s &#8211; %2$s' ),
get_option( 'blogname' ),
'<em>' . get_option( 'blogdescription ' ) . '</em>'
);
echo '</p>';
restore_current_blog();
}
}
/**
* Handles the lastupdated column output.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
*/
public function column_lastupdated( $blog ) {
global $mode;
if ( 'list' === $mode ) {
$date = __( 'Y/m/d' );
} else {
$date = __( 'Y/m/d g:i:s a' );
}
echo ( $blog['last_updated'] === '0000-00-00 00:00:00' ) ? __( 'Never' ) : mysql2date( $date, $blog['last_updated'] );
}
/**
* Handles the registered column output.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
*/
public function column_registered( $blog ) {
global $mode;
if ( 'list' === $mode ) {
$date = __( 'Y/m/d' );
} else {
$date = __( 'Y/m/d g:i:s a' );
}
if ( $blog['registered'] === '0000-00-00 00:00:00' ) {
echo '&#x2014;';
} else {
echo mysql2date( $date, $blog['registered'] );
}
}
/**
* Handles the users column output.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
*/
public function column_users( $blog ) {
$user_count = wp_cache_get( $blog['blog_id'] . '_user_count', 'blog-details' );
if ( ! $user_count ) {
$blog_users = get_users( array( 'blog_id' => $blog['blog_id'], 'fields' => 'ID' ) );
$user_count = count( $blog_users );
unset( $blog_users );
wp_cache_set( $blog['blog_id'] . '_user_count', $user_count, 'blog-details', 12 * HOUR_IN_SECONDS );
}
printf(
'<a href="%s">%s</a>',
esc_url( network_admin_url( 'site-users.php?id=' . $blog['blog_id'] ) ),
number_format_i18n( $user_count )
);
}
/**
* Handles the plugins column output.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
*/
public function column_plugins( $blog ) {
if ( has_filter( 'wpmublogsaction' ) ) {
/**
* Fires inside the auxiliary 'Actions' column of the Sites list table.
*
* By default this column is hidden unless something is hooked to the action.
*
* @since MU
*
* @param int $blog_id The site ID.
*/
do_action( 'wpmublogsaction', $blog['blog_id'] );
}
}
/**
* Handles output for the default column.
*
* @since 4.3.0
* @access public
*
* @param array $blog Current site.
* @param string $column_name Current column name.
*/
public function column_default( $blog, $column_name ) {
/**
* Fires for each registered custom column in the Sites list table.
*
* @since 3.1.0
*
* @param string $column_name The name of the column to display.
* @param int $blog_id The site ID.
*/
do_action( 'manage_sites_custom_column', $column_name, $blog['blog_id'] );
}
/**
*
* @global string $mode
*/
public function display_rows() {
foreach ( $this->items as $blog ) {
$class = '';
reset( $this->status_list );
foreach ( $this->status_list as $status => $col ) {
if ( $blog[ $status ] == 1 ) {
$class = " class='{$col[0]}'";
}
}
echo "<tr{$class}>";
$this->single_row_columns( $blog );
echo '</tr>';
}
}
/**
* Gets the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'blogname'.
*/
protected function get_default_primary_column_name() {
return 'blogname';
}
/**
* Generates and displays row action links.
*
* @since 4.3.0
* @access protected
*
* @param object $blog Site being acted upon.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string Row actions output.
*/
protected function handle_row_actions( $blog, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return;
}
$blogname = untrailingslashit( $blog['domain'] . $blog['path'] );
// Preordered.
$actions = array(
'edit' => '', 'backend' => '',
'activate' => '', 'deactivate' => '',
'archive' => '', 'unarchive' => '',
'spam' => '', 'unspam' => '',
'delete' => '',
'visit' => '',
);
$actions['edit'] = '<a href="' . esc_url( network_admin_url( 'site-info.php?id=' . $blog['blog_id'] ) ) . '">' . __( 'Edit' ) . '</a>';
$actions['backend'] = "<a href='" . esc_url( get_admin_url( $blog['blog_id'] ) ) . "' class='edit'>" . __( 'Dashboard' ) . '</a>';
if ( get_current_site()->blog_id != $blog['blog_id'] ) {
if ( $blog['deleted'] == '1' ) {
$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>';
} else {
$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>';
}
if ( $blog['archived'] == '1' ) {
$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>';
} else {
$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>';
}
if ( $blog['spam'] == '1' ) {
$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>';
} else {
$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>';
}
if ( current_user_can( 'delete_site', $blog['blog_id'] ) ) {
$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>';
}
}
$actions['visit'] = "<a href='" . esc_url( get_home_url( $blog['blog_id'], '/' ) ) . "' rel='permalink'>" . __( 'Visit' ) . '</a>';
/**
* Filter the action links displayed for each site in the Sites list table.
*
* The 'Edit', 'Dashboard', 'Delete', and 'Visit' links are displayed by
* default for each site. The site's status determines whether to show the
* 'Activate' or 'Deactivate' link, 'Unarchive' or 'Archive' links, and
* 'Not Spam' or 'Spam' link for each site.
*
* @since 3.1.0
*
* @param array $actions An array of action links to be displayed.
* @param int $blog_id The site ID.
* @param string $blogname Site path, formatted depending on whether it is a sub-domain
* or subdirectory multisite install.
*/
$actions = apply_filters( 'manage_sites_action_links', array_filter( $actions ), $blog['blog_id'], $blogname );
return $this->row_actions( $actions );
}
}

View File

@@ -0,0 +1,727 @@
<?php
/**
* List Table API: WP_MS_Themes_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying themes in a list table for the network admin.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_MS_Themes_List_Table extends WP_List_Table {
public $site_id;
public $is_site_themes;
private $has_items;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @global string $status
* @global int $page
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
global $status, $page;
parent::__construct( array(
'plural' => 'themes',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
$status = isset( $_REQUEST['theme_status'] ) ? $_REQUEST['theme_status'] : 'all';
if ( !in_array( $status, array( 'all', 'enabled', 'disabled', 'upgrade', 'search', 'broken' ) ) )
$status = 'all';
$page = $this->get_pagenum();
$this->is_site_themes = ( 'site-themes-network' === $this->screen->id ) ? true : false;
if ( $this->is_site_themes )
$this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
}
/**
*
* @return array
*/
protected function get_table_classes() {
// todo: remove and add CSS for .themes
return array( 'widefat', 'plugins' );
}
/**
*
* @return bool
*/
public function ajax_user_can() {
if ( $this->is_site_themes )
return current_user_can( 'manage_sites' );
else
return current_user_can( 'manage_network_themes' );
}
/**
*
* @global string $status
* @global array $totals
* @global int $page
* @global string $orderby
* @global string $order
* @global string $s
*/
public function prepare_items() {
global $status, $totals, $page, $orderby, $order, $s;
wp_reset_vars( array( 'orderby', 'order', 's' ) );
$themes = array(
/**
* Filter the full array of WP_Theme objects to list in the Multisite
* themes list table.
*
* @since 3.1.0
*
* @param array $all An array of WP_Theme objects to display in the list table.
*/
'all' => apply_filters( 'all_themes', wp_get_themes() ),
'search' => array(),
'enabled' => array(),
'disabled' => array(),
'upgrade' => array(),
'broken' => $this->is_site_themes ? array() : wp_get_themes( array( 'errors' => true ) ),
);
if ( $this->is_site_themes ) {
$themes_per_page = $this->get_items_per_page( 'site_themes_network_per_page' );
$allowed_where = 'site';
} else {
$themes_per_page = $this->get_items_per_page( 'themes_network_per_page' );
$allowed_where = 'network';
}
$maybe_update = current_user_can( 'update_themes' ) && ! $this->is_site_themes && $current = get_site_transient( 'update_themes' );
foreach ( (array) $themes['all'] as $key => $theme ) {
if ( $this->is_site_themes && $theme->is_allowed( 'network' ) ) {
unset( $themes['all'][ $key ] );
continue;
}
if ( $maybe_update && isset( $current->response[ $key ] ) ) {
$themes['all'][ $key ]->update = true;
$themes['upgrade'][ $key ] = $themes['all'][ $key ];
}
$filter = $theme->is_allowed( $allowed_where, $this->site_id ) ? 'enabled' : 'disabled';
$themes[ $filter ][ $key ] = $themes['all'][ $key ];
}
if ( $s ) {
$status = 'search';
$themes['search'] = array_filter( array_merge( $themes['all'], $themes['broken'] ), array( $this, '_search_callback' ) );
}
$totals = array();
foreach ( $themes as $type => $list )
$totals[ $type ] = count( $list );
if ( empty( $themes[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
$status = 'all';
$this->items = $themes[ $status ];
WP_Theme::sort_by_name( $this->items );
$this->has_items = ! empty( $themes['all'] );
$total_this_page = $totals[ $status ];
if ( $orderby ) {
$orderby = ucfirst( $orderby );
$order = strtoupper( $order );
if ( $orderby === 'Name' ) {
if ( 'ASC' === $order ) {
$this->items = array_reverse( $this->items );
}
} else {
uasort( $this->items, array( $this, '_order_callback' ) );
}
}
$start = ( $page - 1 ) * $themes_per_page;
if ( $total_this_page > $themes_per_page )
$this->items = array_slice( $this->items, $start, $themes_per_page, true );
$this->set_pagination_args( array(
'total_items' => $total_this_page,
'per_page' => $themes_per_page,
) );
}
/**
* @staticvar string $term
* @param WP_Theme $theme
* @return bool
*/
public function _search_callback( $theme ) {
static $term = null;
if ( is_null( $term ) )
$term = wp_unslash( $_REQUEST['s'] );
foreach ( array( 'Name', 'Description', 'Author', 'Author', 'AuthorURI' ) as $field ) {
// Don't mark up; Do translate.
if ( false !== stripos( $theme->display( $field, false, true ), $term ) )
return true;
}
if ( false !== stripos( $theme->get_stylesheet(), $term ) )
return true;
if ( false !== stripos( $theme->get_template(), $term ) )
return true;
return false;
}
// Not used by any core columns.
/**
* @global string $orderby
* @global string $order
* @param array $theme_a
* @param array $theme_b
* @return int
*/
public function _order_callback( $theme_a, $theme_b ) {
global $orderby, $order;
$a = $theme_a[ $orderby ];
$b = $theme_b[ $orderby ];
if ( $a == $b )
return 0;
if ( 'DESC' === $order )
return ( $a < $b ) ? 1 : -1;
else
return ( $a < $b ) ? -1 : 1;
}
/**
* @access public
*/
public function no_items() {
if ( $this->has_items ) {
_e( 'No themes found.' );
} else {
_e( 'You do not appear to have any themes available at this time.' );
}
}
/**
*
* @return array
*/
public function get_columns() {
return array(
'cb' => '<input type="checkbox" />',
'name' => __( 'Theme' ),
'description' => __( 'Description' ),
);
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'name' => 'name',
);
}
/**
* Gets the name of the primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Unalterable name of the primary column name, in this case, 'name'.
*/
protected function get_primary_column_name() {
return 'name';
}
/**
*
* @global array $totals
* @global string $status
* @return array
*/
protected function get_views() {
global $totals, $status;
$status_links = array();
foreach ( $totals as $type => $count ) {
if ( !$count )
continue;
switch ( $type ) {
case 'all':
$text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'themes' );
break;
case 'enabled':
$text = _n( 'Enabled <span class="count">(%s)</span>', 'Enabled <span class="count">(%s)</span>', $count );
break;
case 'disabled':
$text = _n( 'Disabled <span class="count">(%s)</span>', 'Disabled <span class="count">(%s)</span>', $count );
break;
case 'upgrade':
$text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
break;
case 'broken' :
$text = _n( 'Broken <span class="count">(%s)</span>', 'Broken <span class="count">(%s)</span>', $count );
break;
}
if ( $this->is_site_themes )
$url = 'site-themes.php?id=' . $this->site_id;
else
$url = 'themes.php';
if ( 'search' != $type ) {
$status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
esc_url( add_query_arg('theme_status', $type, $url) ),
( $type === $status ) ? ' class="current"' : '',
sprintf( $text, number_format_i18n( $count ) )
);
}
}
return $status_links;
}
/**
* @global string $status
*
* @return array
*/
protected function get_bulk_actions() {
global $status;
$actions = array();
if ( 'enabled' != $status )
$actions['enable-selected'] = $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' );
if ( 'disabled' != $status )
$actions['disable-selected'] = $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' );
if ( ! $this->is_site_themes ) {
if ( current_user_can( 'update_themes' ) )
$actions['update-selected'] = __( 'Update' );
if ( current_user_can( 'delete_themes' ) )
$actions['delete-selected'] = __( 'Delete' );
}
return $actions;
}
/**
* @access public
*/
public function display_rows() {
foreach ( $this->items as $theme )
$this->single_row( $theme );
}
/**
* Handles the checkbox column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Theme $theme The current WP_Theme object.
*/
public function column_cb( $theme ) {
$checkbox_id = 'checkbox_' . md5( $theme->get('Name') );
?>
<input type="checkbox" name="checked[]" value="<?php echo esc_attr( $theme->get_stylesheet() ) ?>" id="<?php echo $checkbox_id ?>" />
<label class="screen-reader-text" for="<?php echo $checkbox_id ?>" ><?php _e( 'Select' ) ?> <?php echo $theme->display( 'Name' ) ?></label>
<?php
}
/**
* Handles the name column output.
*
* @since 4.3.0
* @access public
*
* @global string $status
* @global int $page
* @global string $s
*
* @param WP_Theme $theme The current WP_Theme object.
*/
public function column_name( $theme ) {
global $status, $page, $s;
$context = $status;
if ( $this->is_site_themes ) {
$url = "site-themes.php?id={$this->site_id}&amp;";
$allowed = $theme->is_allowed( 'site', $this->site_id );
} else {
$url = 'themes.php?';
$allowed = $theme->is_allowed( 'network' );
}
// Pre-order.
$actions = array(
'enable' => '',
'disable' => '',
'edit' => '',
'delete' => ''
);
$stylesheet = $theme->get_stylesheet();
$theme_key = urlencode( $stylesheet );
if ( ! $allowed ) {
if ( ! $theme->errors() ) {
$url = add_query_arg( array(
'action' => 'enable',
'theme' => $theme_key,
'paged' => $page,
's' => $s,
), $url );
if ( $this->is_site_themes ) {
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Enable %s' ), $theme->display( 'Name' ) );
} else {
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Network Enable %s' ), $theme->display( 'Name' ) );
}
$actions['enable'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
esc_url( wp_nonce_url( $url, 'enable-theme_' . $stylesheet ) ),
esc_attr( $aria_label ),
( $this->is_site_themes ? __( 'Enable' ) : __( 'Network Enable' ) )
);
}
} else {
$url = add_query_arg( array(
'action' => 'disable',
'theme' => $theme_key,
'paged' => $page,
's' => $s,
), $url );
if ( $this->is_site_themes ) {
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Disable %s' ), $theme->display( 'Name' ) );
} else {
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Network Disable %s' ), $theme->display( 'Name' ) );
}
$actions['disable'] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
esc_url( wp_nonce_url( $url, 'disable-theme_' . $stylesheet ) ),
esc_attr( $aria_label ),
( $this->is_site_themes ? __( 'Disable' ) : __( 'Network Disable' ) )
);
}
if ( current_user_can('edit_themes') ) {
$url = add_query_arg( array(
'theme' => $theme_key,
), 'theme-editor.php' );
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Open %s in the Theme Editor' ), $theme->display( 'Name' ) );
$actions['edit'] = sprintf( '<a href="%s" class="edit" aria-label="%s">%s</a>',
esc_url( $url ),
esc_attr( $aria_label ),
__( 'Edit' )
);
}
if ( ! $allowed && current_user_can( 'delete_themes' ) && ! $this->is_site_themes && $stylesheet != get_option( 'stylesheet' ) && $stylesheet != get_option( 'template' ) ) {
$url = add_query_arg( array(
'action' => 'delete-selected',
'checked[]' => $theme_key,
'theme_status' => $context,
'paged' => $page,
's' => $s,
), 'themes.php' );
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Delete %s' ), $theme->display( 'Name' ) );
$actions['delete'] = sprintf( '<a href="%s" class="delete" aria-label="%s">%s</a>',
esc_url( wp_nonce_url( $url, 'bulk-themes' ) ),
esc_attr( $aria_label ),
__( 'Delete' )
);
}
/**
* Filter the action links displayed for each theme in the Multisite
* themes list table.
*
* The action links displayed are determined by the theme's status, and
* which Multisite themes list table is being displayed - the Network
* themes list table (themes.php), which displays all installed themes,
* or the Site themes list table (site-themes.php), which displays the
* non-network enabled themes when editing a site in the Network admin.
*
* The default action links for the Network themes list table include
* 'Network Enable', 'Network Disable', 'Edit', and 'Delete'.
*
* The default action links for the Site themes list table include
* 'Enable', 'Disable', and 'Edit'.
*
* @since 2.8.0
*
* @param array $actions An array of action links.
* @param WP_Theme $theme The current WP_Theme object.
* @param string $context Status of the theme.
*/
$actions = apply_filters( 'theme_action_links', array_filter( $actions ), $theme, $context );
/**
* Filter the action links of a specific theme in the Multisite themes
* list table.
*
* The dynamic portion of the hook name, `$stylesheet`, refers to the
* directory name of the theme, which in most cases is synonymous
* with the template name.
*
* @since 3.1.0
*
* @param array $actions An array of action links.
* @param WP_Theme $theme The current WP_Theme object.
* @param string $context Status of the theme.
*/
$actions = apply_filters( "theme_action_links_$stylesheet", $actions, $theme, $context );
echo $this->row_actions( $actions, true );
}
/**
* Handles the description column output.
*
* @since 4.3.0
* @access public
*
* @global string $status
* @global array $totals
*
* @param WP_Theme $theme The current WP_Theme object.
*/
public function column_description( $theme ) {
global $status, $totals;
if ( $theme->errors() ) {
$pre = $status === 'broken' ? __( 'Broken Theme:' ) . ' ' : '';
echo '<p><strong class="error-message">' . $pre . $theme->errors()->get_error_message() . '</strong></p>';
}
if ( $this->is_site_themes ) {
$allowed = $theme->is_allowed( 'site', $this->site_id );
} else {
$allowed = $theme->is_allowed( 'network' );
}
$class = ! $allowed ? 'inactive' : 'active';
if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) )
$class .= ' update';
echo "<div class='theme-description'><p>" . $theme->display( 'Description' ) . "</p></div>
<div class='$class second theme-version-author-uri'>";
$stylesheet = $theme->get_stylesheet();
$theme_meta = array();
if ( $theme->get('Version') ) {
$theme_meta[] = sprintf( __( 'Version %s' ), $theme->display('Version') );
}
$theme_meta[] = sprintf( __( 'By %s' ), $theme->display('Author') );
if ( $theme->get('ThemeURI') ) {
/* translators: %s: theme name */
$aria_label = sprintf( __( 'Visit %s homepage' ), $theme->display( 'Name' ) );
$theme_meta[] = sprintf( '<a href="%s" aria-label="%s">%s</a>',
$theme->display( 'ThemeURI' ),
esc_attr( $aria_label ),
__( 'Visit Theme Site' )
);
}
/**
* Filter the array of row meta for each theme in the Multisite themes
* list table.
*
* @since 3.1.0
*
* @param array $theme_meta An array of the theme's metadata,
* including the version, author, and
* theme URI.
* @param string $stylesheet Directory name of the theme.
* @param WP_Theme $theme WP_Theme object.
* @param string $status Status of the theme.
*/
$theme_meta = apply_filters( 'theme_row_meta', $theme_meta, $stylesheet, $theme, $status );
echo implode( ' | ', $theme_meta );
echo '</div>';
}
/**
* Handles default column output.
*
* @since 4.3.0
* @access public
*
* @param WP_Theme $theme The current WP_Theme object.
* @param string $column_name The current column name.
*/
public function column_default( $theme, $column_name ) {
$stylesheet = $theme->get_stylesheet();
/**
* Fires inside each custom column of the Multisite themes list table.
*
* @since 3.1.0
*
* @param string $column_name Name of the column.
* @param string $stylesheet Directory name of the theme.
* @param WP_Theme $theme Current WP_Theme object.
*/
do_action( 'manage_themes_custom_column', $column_name, $stylesheet, $theme );
}
/**
* Handles the output for a single table row.
*
* @since 4.3.0
* @access public
*
* @param WP_Theme $item The current WP_Theme object.
*/
public function single_row_columns( $item ) {
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
foreach ( $columns as $column_name => $column_display_name ) {
$extra_classes = '';
if ( in_array( $column_name, $hidden ) ) {
$extra_classes .= ' hidden';
}
switch ( $column_name ) {
case 'cb':
echo '<th scope="row" class="check-column">';
$this->column_cb( $item );
echo '</th>';
break;
case 'name':
echo "<td class='theme-title column-primary{$extra_classes}'><strong>" . $item->display('Name') . "</strong>";
$this->column_name( $item );
echo "</td>";
break;
case 'description':
echo "<td class='column-description desc{$extra_classes}'>";
$this->column_description( $item );
echo '</td>';
break;
default:
echo "<td class='$column_name column-$column_name{$extra_classes}'>";
$this->column_default( $item, $column_name );
echo "</td>";
break;
}
}
}
/**
* @global string $status
* @global array $totals
*
* @param WP_Theme $theme
*/
public function single_row( $theme ) {
global $status, $totals;
if ( $this->is_site_themes ) {
$allowed = $theme->is_allowed( 'site', $this->site_id );
} else {
$allowed = $theme->is_allowed( 'network' );
}
$stylesheet = $theme->get_stylesheet();
$class = ! $allowed ? 'inactive' : 'active';
if ( ! empty( $totals['upgrade'] ) && ! empty( $theme->update ) ) {
$class .= ' update';
}
printf( '<tr class="%s" data-slug="%s">',
esc_attr( $class ),
esc_attr( $stylesheet )
);
$this->single_row_columns( $theme );
echo "</tr>";
if ( $this->is_site_themes )
remove_action( "after_theme_row_$stylesheet", 'wp_theme_update_row' );
/**
* Fires after each row in the Multisite themes list table.
*
* @since 3.1.0
*
* @param string $stylesheet Directory name of the theme.
* @param WP_Theme $theme Current WP_Theme object.
* @param string $status Status of the theme.
*/
do_action( 'after_theme_row', $stylesheet, $theme, $status );
/**
* Fires after each specific row in the Multisite themes list table.
*
* The dynamic portion of the hook name, `$stylesheet`, refers to the
* directory name of the theme, most often synonymous with the template
* name of the theme.
*
* @since 3.5.0
*
* @param string $stylesheet Directory name of the theme.
* @param WP_Theme $theme Current WP_Theme object.
* @param string $status Status of the theme.
*/
do_action( "after_theme_row_$stylesheet", $stylesheet, $theme, $status );
}
}

View File

@@ -0,0 +1,460 @@
<?php
/**
* List Table API: WP_MS_Users_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying users in a list table for the network admin.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_MS_Users_List_Table extends WP_List_Table {
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can( 'manage_network_users' );
}
/**
*
* @global string $usersearch
* @global string $role
* @global wpdb $wpdb
* @global string $mode
*/
public function prepare_items() {
global $usersearch, $role, $wpdb, $mode;
$usersearch = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST['s'] ) ) : '';
$users_per_page = $this->get_items_per_page( 'users_network_per_page' );
$role = isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : '';
$paged = $this->get_pagenum();
$args = array(
'number' => $users_per_page,
'offset' => ( $paged-1 ) * $users_per_page,
'search' => $usersearch,
'blog_id' => 0,
'fields' => 'all_with_meta'
);
if ( wp_is_large_network( 'users' ) ) {
$args['search'] = ltrim( $args['search'], '*' );
} else if ( '' !== $args['search'] ) {
$args['search'] = trim( $args['search'], '*' );
$args['search'] = '*' . $args['search'] . '*';
}
if ( $role === 'super' ) {
$logins = implode( "', '", get_super_admins() );
$args['include'] = $wpdb->get_col( "SELECT ID FROM $wpdb->users WHERE user_login IN ('$logins')" );
}
/*
* If the network is large and a search is not being performed,
* show only the latest users with no paging in order to avoid
* expensive count queries.
*/
if ( !$usersearch && wp_is_large_network( 'users' ) ) {
if ( !isset($_REQUEST['orderby']) )
$_GET['orderby'] = $_REQUEST['orderby'] = 'id';
if ( !isset($_REQUEST['order']) )
$_GET['order'] = $_REQUEST['order'] = 'DESC';
$args['count_total'] = false;
}
if ( isset( $_REQUEST['orderby'] ) )
$args['orderby'] = $_REQUEST['orderby'];
if ( isset( $_REQUEST['order'] ) )
$args['order'] = $_REQUEST['order'];
if ( ! empty( $_REQUEST['mode'] ) ) {
$mode = $_REQUEST['mode'] === 'excerpt' ? 'excerpt' : 'list';
set_user_setting( 'network_users_list_mode', $mode );
} else {
$mode = get_user_setting( 'network_users_list_mode', 'list' );
}
/** This filter is documented in wp-admin/includes/class-wp-users-list-table.php */
$args = apply_filters( 'users_list_table_query_args', $args );
// Query the user IDs for this page
$wp_user_search = new WP_User_Query( $args );
$this->items = $wp_user_search->get_results();
$this->set_pagination_args( array(
'total_items' => $wp_user_search->get_total(),
'per_page' => $users_per_page,
) );
}
/**
*
* @return array
*/
protected function get_bulk_actions() {
$actions = array();
if ( current_user_can( 'delete_users' ) )
$actions['delete'] = __( 'Delete' );
$actions['spam'] = _x( 'Mark as Spam', 'user' );
$actions['notspam'] = _x( 'Not Spam', 'user' );
return $actions;
}
/**
* @access public
*/
public function no_items() {
_e( 'No users found.' );
}
/**
*
* @global string $role
* @return array
*/
protected function get_views() {
global $role;
$total_users = get_user_count();
$super_admins = get_super_admins();
$total_admins = count( $super_admins );
$class = $role != 'super' ? ' class="current"' : '';
$role_links = array();
$role_links['all'] = "<a href='" . network_admin_url('users.php') . "'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
$class = $role === 'super' ? ' class="current"' : '';
$role_links['super'] = "<a href='" . network_admin_url('users.php?role=super') . "'$class>" . sprintf( _n( 'Super Admin <span class="count">(%s)</span>', 'Super Admins <span class="count">(%s)</span>', $total_admins ), number_format_i18n( $total_admins ) ) . '</a>';
return $role_links;
}
/**
* @global string $mode
* @param string $which
*/
protected function pagination( $which ) {
global $mode;
parent::pagination ( $which );
if ( 'top' === $which ) {
$this->view_switcher( $mode );
}
}
/**
*
* @return array
*/
public function get_columns() {
$users_columns = array(
'cb' => '<input type="checkbox" />',
'username' => __( 'Username' ),
'name' => __( 'Name' ),
'email' => __( 'Email' ),
'registered' => _x( 'Registered', 'user' ),
'blogs' => __( 'Sites' )
);
/**
* Filter the columns displayed in the Network Admin Users list table.
*
* @since MU
*
* @param array $users_columns An array of user columns. Default 'cb', 'username',
* 'name', 'email', 'registered', 'blogs'.
*/
return apply_filters( 'wpmu_users_columns', $users_columns );
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'username' => 'login',
'name' => 'name',
'email' => 'email',
'registered' => 'id',
);
}
/**
* Handles the checkbox column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_cb( $user ) {
if ( is_super_admin( $user->ID ) ) {
return;
}
?>
<label class="screen-reader-text" for="blog_<?php echo $user->ID; ?>"><?php echo sprintf( __( 'Select %s' ), $user->user_login ); ?></label>
<input type="checkbox" id="blog_<?php echo $user->ID ?>" name="allusers[]" value="<?php echo esc_attr( $user->ID ) ?>" />
<?php
}
/**
* Handles the ID column output.
*
* @since 4.4.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_id( $user ) {
echo $user->ID;
}
/**
* Handles the username column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_username( $user ) {
$super_admins = get_super_admins();
$avatar = get_avatar( $user->user_email, 32 );
$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
echo $avatar;
?><strong><a href="<?php echo $edit_link; ?>" class="edit"><?php echo $user->user_login; ?></a><?php
if ( in_array( $user->user_login, $super_admins ) ) {
echo ' - ' . __( 'Super Admin' );
}
?></strong>
<?php
}
/**
* Handles the name column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_name( $user ) {
echo "$user->first_name $user->last_name";
}
/**
* Handles the email column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_email( $user ) {
echo "<a href='" . esc_url( "mailto:$user->user_email" ) . "'>$user->user_email</a>";
}
/**
* Handles the registered date column output.
*
* @since 4.3.0
* @access public
*
* @global string $mode
*
* @param WP_User $user The current WP_User object.
*/
public function column_registered( $user ) {
global $mode;
if ( 'list' === $mode ) {
$date = __( 'Y/m/d' );
} else {
$date = __( 'Y/m/d g:i:s a' );
}
echo mysql2date( $date, $user->user_registered );
}
/**
* @since 4.3.0
* @access protected
*
* @param WP_User $user
* @param string $classes
* @param string $data
* @param string $primary
*/
protected function _column_blogs( $user, $classes, $data, $primary ) {
echo '<td class="', $classes, ' has-row-actions" ', $data, '>';
echo $this->column_blogs( $user );
echo $this->handle_row_actions( $user, 'blogs', $primary );
echo '</td>';
}
/**
* Handles the sites column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
*/
public function column_blogs( $user ) {
$blogs = get_blogs_of_user( $user->ID, true );
if ( ! is_array( $blogs ) ) {
return;
}
foreach ( $blogs as $val ) {
if ( ! can_edit_network( $val->site_id ) ) {
continue;
}
$path = ( $val->path === '/' ) ? '' : $val->path;
echo '<span class="site-' . $val->site_id . '" >';
echo '<a href="'. esc_url( network_admin_url( 'site-info.php?id=' . $val->userblog_id ) ) .'">' . str_replace( '.' . get_current_site()->domain, '', $val->domain . $path ) . '</a>';
echo ' <small class="row-actions">';
$actions = array();
$actions['edit'] = '<a href="'. esc_url( network_admin_url( 'site-info.php?id=' . $val->userblog_id ) ) .'">' . __( 'Edit' ) . '</a>';
$class = '';
if ( $val->spam == 1 ) {
$class .= 'site-spammed ';
}
if ( $val->mature == 1 ) {
$class .= 'site-mature ';
}
if ( $val->deleted == 1 ) {
$class .= 'site-deleted ';
}
if ( $val->archived == 1 ) {
$class .= 'site-archived ';
}
$actions['view'] = '<a class="' . $class . '" href="' . esc_url( get_home_url( $val->userblog_id ) ) . '">' . __( 'View' ) . '</a>';
/**
* Filter the action links displayed next the sites a user belongs to
* in the Network Admin Users list table.
*
* @since 3.1.0
*
* @param array $actions An array of action links to be displayed.
* Default 'Edit', 'View'.
* @param int $userblog_id The site ID.
*/
$actions = apply_filters( 'ms_user_list_site_actions', $actions, $val->userblog_id );
$i=0;
$action_count = count( $actions );
foreach ( $actions as $action => $link ) {
++$i;
$sep = ( $i == $action_count ) ? '' : ' | ';
echo "<span class='$action'>$link$sep</span>";
}
echo '</small></span><br/>';
}
}
/**
* Handles the default column output.
*
* @since 4.3.0
* @access public
*
* @param WP_User $user The current WP_User object.
* @param string $column_name The current column name.
*/
public function column_default( $user, $column_name ) {
/** This filter is documented in wp-admin/includes/class-wp-users-list-table.php */
echo apply_filters( 'manage_users_custom_column', '', $column_name, $user->ID );
}
public function display_rows() {
foreach ( $this->items as $user ) {
$class = '';
$status_list = array( 'spam' => 'site-spammed', 'deleted' => 'site-deleted' );
foreach ( $status_list as $status => $col ) {
if ( $user->$status ) {
$class .= " $col";
}
}
?>
<tr class="<?php echo trim( $class ); ?>">
<?php $this->single_row_columns( $user ); ?>
</tr>
<?php
}
}
/**
* Gets the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'username'.
*/
protected function get_default_primary_column_name() {
return 'username';
}
/**
* Generates and displays row action links.
*
* @since 4.3.0
* @access protected
*
* @param object $user User being acted upon.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string Row actions output for users in Multisite.
*/
protected function handle_row_actions( $user, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$super_admins = get_super_admins();
$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user->ID ) ) );
$actions = array();
$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
if ( current_user_can( 'delete_user', $user->ID ) && ! in_array( $user->user_login, $super_admins ) ) {
$actions['delete'] = '<a href="' . $delete = esc_url( network_admin_url( add_query_arg( '_wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), wp_nonce_url( 'users.php', 'deleteuser' ) . '&amp;action=deleteuser&amp;id=' . $user->ID ) ) ) . '" class="delete">' . __( 'Delete' ) . '</a>';
}
/**
* Filter the action links displayed under each user in the Network Admin Users list table.
*
* @since 3.2.0
*
* @param array $actions An array of action links to be displayed.
* Default 'Edit', 'Delete'.
* @param WP_User $user WP_User object.
*/
$actions = apply_filters( 'ms_user_row_actions', $actions, $user );
return $this->row_actions( $actions );
}
}

View File

@@ -0,0 +1,569 @@
<?php
/**
* List Table API: WP_Plugin_Install_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying plugins to install in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Plugin_Install_List_Table extends WP_List_Table {
public $order = 'ASC';
public $orderby = null;
public $groups = array();
private $error;
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can('install_plugins');
}
/**
* Return a list of slugs of installed plugins, if known.
*
* Uses the transient data from the updates API to determine the slugs of
* known installed plugins. This might be better elsewhere, perhaps even
* within get_plugins().
*
* @since 4.0.0
* @access protected
*
* @return array
*/
protected function get_installed_plugin_slugs() {
$slugs = array();
$plugin_info = get_site_transient( 'update_plugins' );
if ( isset( $plugin_info->no_update ) ) {
foreach ( $plugin_info->no_update as $plugin ) {
$slugs[] = $plugin->slug;
}
}
if ( isset( $plugin_info->response ) ) {
foreach ( $plugin_info->response as $plugin ) {
$slugs[] = $plugin->slug;
}
}
return $slugs;
}
/**
*
* @global array $tabs
* @global string $tab
* @global int $paged
* @global string $type
* @global string $term
* @global string $wp_version
*/
public function prepare_items() {
include( ABSPATH . 'wp-admin/includes/plugin-install.php' );
global $tabs, $tab, $paged, $type, $term;
wp_reset_vars( array( 'tab' ) );
$paged = $this->get_pagenum();
$per_page = 30;
// These are the tabs which are shown on the page
$tabs = array();
if ( 'search' === $tab ) {
$tabs['search'] = __( 'Search Results' );
}
if ( $tab === 'beta' || false !== strpos( $GLOBALS['wp_version'], '-' ) ) {
$tabs['beta'] = _x( 'Beta Testing', 'Plugin Installer' );
}
$tabs['featured'] = _x( 'Featured', 'Plugin Installer' );
$tabs['popular'] = _x( 'Popular', 'Plugin Installer' );
$tabs['recommended'] = _x( 'Recommended', 'Plugin Installer' );
$tabs['favorites'] = _x( 'Favorites', 'Plugin Installer' );
if ( current_user_can( 'upload_plugins' ) ) {
// No longer a real tab. Here for filter compatibility.
// Gets skipped in get_views().
$tabs['upload'] = __( 'Upload Plugin' );
}
$nonmenu_tabs = array( 'plugin-information' ); // Valid actions to perform which do not have a Menu item.
/**
* Filter the tabs shown on the Plugin Install screen.
*
* @since 2.7.0
*
* @param array $tabs The tabs shown on the Plugin Install screen. Defaults include 'featured', 'popular',
* 'recommended', 'favorites', and 'upload'.
*/
$tabs = apply_filters( 'install_plugins_tabs', $tabs );
/**
* Filter tabs not associated with a menu item on the Plugin Install screen.
*
* @since 2.7.0
*
* @param array $nonmenu_tabs The tabs that don't have a Menu item on the Plugin Install screen.
*/
$nonmenu_tabs = apply_filters( 'install_plugins_nonmenu_tabs', $nonmenu_tabs );
// If a non-valid menu tab has been selected, And it's not a non-menu action.
if ( empty( $tab ) || ( !isset( $tabs[ $tab ] ) && !in_array( $tab, (array) $nonmenu_tabs ) ) )
$tab = key( $tabs );
$args = array(
'page' => $paged,
'per_page' => $per_page,
'fields' => array(
'last_updated' => true,
'icons' => true,
'active_installs' => true
),
// Send the locale and installed plugin slugs to the API so it can provide context-sensitive results.
'locale' => get_locale(),
'installed_plugins' => $this->get_installed_plugin_slugs(),
);
switch ( $tab ) {
case 'search':
$type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
$term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
switch ( $type ) {
case 'tag':
$args['tag'] = sanitize_title_with_dashes( $term );
break;
case 'term':
$args['search'] = $term;
break;
case 'author':
$args['author'] = $term;
break;
}
break;
case 'featured':
$args['fields']['group'] = true;
$this->orderby = 'group';
// No break!
case 'popular':
case 'new':
case 'beta':
case 'recommended':
$args['browse'] = $tab;
break;
case 'favorites':
$action = 'save_wporg_username_' . get_current_user_id();
if ( isset( $_GET['_wpnonce'] ) && wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), $action ) ) {
$user = isset( $_GET['user'] ) ? wp_unslash( $_GET['user'] ) : get_user_option( 'wporg_favorites' );
update_user_meta( get_current_user_id(), 'wporg_favorites', $user );
} else {
$user = get_user_option( 'wporg_favorites' );
}
if ( $user )
$args['user'] = $user;
else
$args = false;
add_action( 'install_plugins_favorites', 'install_plugins_favorites_form', 9, 0 );
break;
default:
$args = false;
break;
}
/**
* Filter API request arguments for each Plugin Install screen tab.
*
* The dynamic portion of the hook name, `$tab`, refers to the plugin install tabs.
* Default tabs include 'featured', 'popular', 'recommended', 'favorites', and 'upload'.
*
* @since 3.7.0
*
* @param array|bool $args Plugin Install API arguments.
*/
$args = apply_filters( "install_plugins_table_api_args_$tab", $args );
if ( !$args )
return;
$api = plugins_api( 'query_plugins', $args );
if ( is_wp_error( $api ) ) {
$this->error = $api;
return;
}
$this->items = $api->plugins;
if ( $this->orderby ) {
uasort( $this->items, array( $this, 'order_callback' ) );
}
$this->set_pagination_args( array(
'total_items' => $api->info['results'],
'per_page' => $args['per_page'],
) );
if ( isset( $api->info['groups'] ) ) {
$this->groups = $api->info['groups'];
}
}
/**
* @access public
*/
public function no_items() {
if ( isset( $this->error ) ) {
$message = $this->error->get_error_message() . '<p class="hide-if-no-js"><a href="#" class="button" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a></p>';
} else {
$message = __( 'No plugins match your request.' );
}
echo '<div class="no-plugin-results">' . $message . '</div>';
}
/**
*
* @global array $tabs
* @global string $tab
*
* @return array
*/
protected function get_views() {
global $tabs, $tab;
$display_tabs = array();
foreach ( (array) $tabs as $action => $text ) {
$class = ( $action === $tab ) ? ' current' : '';
$href = self_admin_url('plugin-install.php?tab=' . $action);
$display_tabs['plugin-install-'.$action] = "<a href='$href' class='$class'>$text</a>";
}
// No longer a real tab.
unset( $display_tabs['plugin-install-upload'] );
return $display_tabs;
}
/**
* Override parent views so we can use the filter bar display.
*/
public function views() {
$views = $this->get_views();
/** This filter is documented in wp-admin/inclues/class-wp-list-table.php */
$views = apply_filters( "views_{$this->screen->id}", $views );
$this->screen->render_screen_reader_content( 'heading_views' );
?>
<div class="wp-filter">
<ul class="filter-links">
<?php
if ( ! empty( $views ) ) {
foreach ( $views as $class => $view ) {
$views[ $class ] = "\t<li class='$class'>$view";
}
echo implode( " </li>\n", $views ) . "</li>\n";
}
?>
</ul>
<?php install_search_form( isset( $views['plugin-install-search'] ) ); ?>
</div>
<?php
}
/**
* Override the parent display() so we can provide a different container.
*/
public function display() {
$singular = $this->_args['singular'];
$data_attr = '';
if ( $singular ) {
$data_attr = " data-wp-lists='list:$singular'";
}
$this->display_tablenav( 'top' );
?>
<div class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
<?php
$this->screen->render_screen_reader_content( 'heading_list' );
?>
<div id="the-list"<?php echo $data_attr; ?>>
<?php $this->display_rows_or_placeholder(); ?>
</div>
</div>
<?php
$this->display_tablenav( 'bottom' );
}
/**
* @global string $tab
*
* @param string $which
*/
protected function display_tablenav( $which ) {
if ( $GLOBALS['tab'] === 'featured' ) {
return;
}
if ( 'top' === $which ) {
wp_referer_field();
?>
<div class="tablenav top">
<div class="alignleft actions">
<?php
/**
* Fires before the Plugin Install table header pagination is displayed.
*
* @since 2.7.0
*/
do_action( 'install_plugins_table_header' ); ?>
</div>
<?php $this->pagination( $which ); ?>
<br class="clear" />
</div>
<?php } else { ?>
<div class="tablenav bottom">
<?php $this->pagination( $which ); ?>
<br class="clear" />
</div>
<?php
}
}
/**
* @return array
*/
protected function get_table_classes() {
return array( 'widefat', $this->_args['plural'] );
}
/**
* @return array
*/
public function get_columns() {
return array();
}
/**
* @param object $plugin_a
* @param object $plugin_b
* @return int
*/
private function order_callback( $plugin_a, $plugin_b ) {
$orderby = $this->orderby;
if ( ! isset( $plugin_a->$orderby, $plugin_b->$orderby ) ) {
return 0;
}
$a = $plugin_a->$orderby;
$b = $plugin_b->$orderby;
if ( $a == $b ) {
return 0;
}
if ( 'DESC' === $this->order ) {
return ( $a < $b ) ? 1 : -1;
} else {
return ( $a < $b ) ? -1 : 1;
}
}
/**
* @global string $wp_version
*/
public function display_rows() {
$plugins_allowedtags = array(
'a' => array( 'href' => array(),'title' => array(), 'target' => array() ),
'abbr' => array( 'title' => array() ),'acronym' => array( 'title' => array() ),
'code' => array(), 'pre' => array(), 'em' => array(),'strong' => array(),
'ul' => array(), 'ol' => array(), 'li' => array(), 'p' => array(), 'br' => array()
);
$plugins_group_titles = array(
'Performance' => _x( 'Performance', 'Plugin installer group title' ),
'Social' => _x( 'Social', 'Plugin installer group title' ),
'Tools' => _x( 'Tools', 'Plugin installer group title' ),
);
$group = null;
foreach ( (array) $this->items as $plugin ) {
if ( is_object( $plugin ) ) {
$plugin = (array) $plugin;
}
// Display the group heading if there is one
if ( isset( $plugin['group'] ) && $plugin['group'] != $group ) {
if ( isset( $this->groups[ $plugin['group'] ] ) ) {
$group_name = $this->groups[ $plugin['group'] ];
if ( isset( $plugins_group_titles[ $group_name ] ) ) {
$group_name = $plugins_group_titles[ $group_name ];
}
} else {
$group_name = $plugin['group'];
}
// Starting a new group, close off the divs of the last one
if ( ! empty( $group ) ) {
echo '</div></div>';
}
echo '<div class="plugin-group"><h3>' . esc_html( $group_name ) . '</h3>';
// needs an extra wrapping div for nth-child selectors to work
echo '<div class="plugin-items">';
$group = $plugin['group'];
}
$title = wp_kses( $plugin['name'], $plugins_allowedtags );
// Remove any HTML from the description.
$description = strip_tags( $plugin['short_description'] );
$version = wp_kses( $plugin['version'], $plugins_allowedtags );
$name = strip_tags( $title . ' ' . $version );
$author = wp_kses( $plugin['author'], $plugins_allowedtags );
if ( ! empty( $author ) ) {
$author = ' <cite>' . sprintf( __( 'By %s' ), $author ) . '</cite>';
}
$action_links = array();
if ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) {
$status = install_plugin_install_status( $plugin );
switch ( $status['status'] ) {
case 'install':
if ( $status['url'] ) {
/* translators: 1: Plugin name and version. */
$action_links[] = '<a class="install-now button" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Install %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Install Now' ) . '</a>';
}
break;
case 'update_available':
if ( $status['url'] ) {
/* translators: 1: Plugin name and version */
$action_links[] = '<a class="update-now button aria-button-if-js" data-plugin="' . esc_attr( $status['file'] ) . '" data-slug="' . esc_attr( $plugin['slug'] ) . '" href="' . esc_url( $status['url'] ) . '" aria-label="' . esc_attr( sprintf( __( 'Update %s now' ), $name ) ) . '" data-name="' . esc_attr( $name ) . '">' . __( 'Update Now' ) . '</a>';
}
break;
case 'latest_installed':
case 'newer_installed':
$action_links[] = '<span class="button button-disabled">' . _x( 'Installed', 'plugin' ) . '</span>';
break;
}
}
$details_link = self_admin_url( 'plugin-install.php?tab=plugin-information&amp;plugin=' . $plugin['slug'] .
'&amp;TB_iframe=true&amp;width=600&amp;height=550' );
/* translators: 1: Plugin name and version. */
$action_links[] = '<a href="' . esc_url( $details_link ) . '" class="thickbox open-plugin-details-modal" aria-label="' . esc_attr( sprintf( __( 'More information about %s' ), $name ) ) . '" data-title="' . esc_attr( $name ) . '">' . __( 'More Details' ) . '</a>';
if ( !empty( $plugin['icons']['svg'] ) ) {
$plugin_icon_url = $plugin['icons']['svg'];
} elseif ( !empty( $plugin['icons']['2x'] ) ) {
$plugin_icon_url = $plugin['icons']['2x'];
} elseif ( !empty( $plugin['icons']['1x'] ) ) {
$plugin_icon_url = $plugin['icons']['1x'];
} else {
$plugin_icon_url = $plugin['icons']['default'];
}
/**
* Filter the install action links for a plugin.
*
* @since 2.7.0
*
* @param array $action_links An array of plugin action hyperlinks. Defaults are links to Details and Install Now.
* @param array $plugin The plugin currently being listed.
*/
$action_links = apply_filters( 'plugin_install_action_links', $action_links, $plugin );
$last_updated_timestamp = strtotime( $plugin['last_updated'] );
?>
<div class="plugin-card plugin-card-<?php echo sanitize_html_class( $plugin['slug'] ); ?>">
<div class="plugin-card-top">
<div class="name column-name">
<h3>
<a href="<?php echo esc_url( $details_link ); ?>" class="thickbox open-plugin-details-modal">
<?php echo $title; ?>
<img src="<?php echo esc_attr( $plugin_icon_url ) ?>" class="plugin-icon" alt="">
</a>
</h3>
</div>
<div class="action-links">
<?php
if ( $action_links ) {
echo '<ul class="plugin-action-buttons"><li>' . implode( '</li><li>', $action_links ) . '</li></ul>';
}
?>
</div>
<div class="desc column-description">
<p><?php echo $description; ?></p>
<p class="authors"><?php echo $author; ?></p>
</div>
</div>
<div class="plugin-card-bottom">
<div class="vers column-rating">
<?php wp_star_rating( array( 'rating' => $plugin['rating'], 'type' => 'percent', 'number' => $plugin['num_ratings'] ) ); ?>
<span class="num-ratings" aria-hidden="true">(<?php echo number_format_i18n( $plugin['num_ratings'] ); ?>)</span>
</div>
<div class="column-updated">
<strong><?php _e( 'Last Updated:' ); ?></strong> <?php printf( __( '%s ago' ), human_time_diff( $last_updated_timestamp ) ); ?>
</div>
<div class="column-downloaded">
<?php
if ( $plugin['active_installs'] >= 1000000 ) {
$active_installs_text = _x( '1+ Million', 'Active plugin installs' );
} else {
$active_installs_text = number_format_i18n( $plugin['active_installs'] ) . '+';
}
printf( __( '%s Active Installs' ), $active_installs_text );
?>
</div>
<div class="column-compatibility">
<?php
if ( ! empty( $plugin['tested'] ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $plugin['tested'] ) ), $plugin['tested'], '>' ) ) {
echo '<span class="compatibility-untested">' . __( 'Untested with your version of WordPress' ) . '</span>';
} elseif ( ! empty( $plugin['requires'] ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $plugin['requires'] ) ), $plugin['requires'], '<' ) ) {
echo '<span class="compatibility-incompatible">' . __( '<strong>Incompatible</strong> with your version of WordPress' ) . '</span>';
} else {
echo '<span class="compatibility-compatible">' . __( '<strong>Compatible</strong> with your version of WordPress' ) . '</span>';
}
?>
</div>
</div>
</div>
<?php
}
// Close off the group divs of the last one
if ( ! empty( $group ) ) {
echo '</div></div>';
}
}
}

View File

@@ -0,0 +1,841 @@
<?php
/**
* List Table API: WP_Plugins_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying installed plugins in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Plugins_List_Table extends WP_List_Table {
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @global string $status
* @global int $page
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
global $status, $page;
parent::__construct( array(
'plural' => 'plugins',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
$status = 'all';
if ( isset( $_REQUEST['plugin_status'] ) && in_array( $_REQUEST['plugin_status'], array( 'active', 'inactive', 'recently_activated', 'upgrade', 'mustuse', 'dropins', 'search' ) ) )
$status = $_REQUEST['plugin_status'];
if ( isset($_REQUEST['s']) )
$_SERVER['REQUEST_URI'] = add_query_arg('s', wp_unslash($_REQUEST['s']) );
$page = $this->get_pagenum();
}
/**
* @return array
*/
protected function get_table_classes() {
return array( 'widefat', $this->_args['plural'] );
}
/**
* @return bool
*/
public function ajax_user_can() {
return current_user_can('activate_plugins');
}
/**
*
* @global string $status
* @global array $plugins
* @global array $totals
* @global int $page
* @global string $orderby
* @global string $order
* @global string $s
*/
public function prepare_items() {
global $status, $plugins, $totals, $page, $orderby, $order, $s;
wp_reset_vars( array( 'orderby', 'order' ) );
/**
* Filters the full array of plugins to list in the Plugins list table.
*
* @since 3.0.0
*
* @see get_plugins()
*
* @param array $all_plugins An array of plugins to display in the list table.
*/
$all_plugins = apply_filters( 'all_plugins', get_plugins() );
$plugins = array(
'all' => $all_plugins,
'search' => array(),
'active' => array(),
'inactive' => array(),
'recently_activated' => array(),
'upgrade' => array(),
'mustuse' => array(),
'dropins' => array(),
);
$screen = $this->screen;
if ( ! is_multisite() || ( $screen->in_admin( 'network' ) && current_user_can( 'manage_network_plugins' ) ) ) {
/**
* Filter whether to display the advanced plugins list table.
*
* There are two types of advanced plugins - must-use and drop-ins -
* which can be used in a single site or Multisite network.
*
* The $type parameter allows you to differentiate between the type of advanced
* plugins to filter the display of. Contexts include 'mustuse' and 'dropins'.
*
* @since 3.0.0
*
* @param bool $show Whether to show the advanced plugins for the specified
* plugin type. Default true.
* @param string $type The plugin type. Accepts 'mustuse', 'dropins'.
*/
if ( apply_filters( 'show_advanced_plugins', true, 'mustuse' ) ) {
$plugins['mustuse'] = get_mu_plugins();
}
/** This action is documented in wp-admin/includes/class-wp-plugins-list-table.php */
if ( apply_filters( 'show_advanced_plugins', true, 'dropins' ) )
$plugins['dropins'] = get_dropins();
if ( current_user_can( 'update_plugins' ) ) {
$current = get_site_transient( 'update_plugins' );
foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
if ( isset( $current->response[ $plugin_file ] ) ) {
$plugins['all'][ $plugin_file ]['update'] = true;
$plugins['upgrade'][ $plugin_file ] = $plugins['all'][ $plugin_file ];
}
}
}
}
if ( ! $screen->in_admin( 'network' ) ) {
$show = current_user_can( 'manage_network_plugins' );
/**
* Filter whether to display network-active plugins alongside plugins active for the current site.
*
* This also controls the display of inactive network-only plugins (plugins with
* "Network: true" in the plugin header).
*
* Plugins cannot be network-activated or network-deactivated from this screen.
*
* @since 4.4.0
*
* @param bool $show Whether to show network-active plugins. Default is whether the current
* user can manage network plugins (ie. a Super Admin).
*/
$show_network_active = apply_filters( 'show_network_active_plugins', $show );
}
set_transient( 'plugin_slugs', array_keys( $plugins['all'] ), DAY_IN_SECONDS );
if ( $screen->in_admin( 'network' ) ) {
$recently_activated = get_site_option( 'recently_activated', array() );
} else {
$recently_activated = get_option( 'recently_activated', array() );
}
foreach ( $recently_activated as $key => $time ) {
if ( $time + WEEK_IN_SECONDS < time() ) {
unset( $recently_activated[$key] );
}
}
if ( $screen->in_admin( 'network' ) ) {
update_site_option( 'recently_activated', $recently_activated );
} else {
update_option( 'recently_activated', $recently_activated );
}
$plugin_info = get_site_transient( 'update_plugins' );
foreach ( (array) $plugins['all'] as $plugin_file => $plugin_data ) {
// Extra info if known. array_merge() ensures $plugin_data has precedence if keys collide.
if ( isset( $plugin_info->response[ $plugin_file ] ) ) {
$plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
// Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
$plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->response[ $plugin_file ], $plugin_data );
}
} elseif ( isset( $plugin_info->no_update[ $plugin_file ] ) ) {
$plugins['all'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
// Make sure that $plugins['upgrade'] also receives the extra info since it is used on ?plugin_status=upgrade
if ( isset( $plugins['upgrade'][ $plugin_file ] ) ) {
$plugins['upgrade'][ $plugin_file ] = $plugin_data = array_merge( (array) $plugin_info->no_update[ $plugin_file ], $plugin_data );
}
}
// Filter into individual sections
if ( is_multisite() && ! $screen->in_admin( 'network' ) && is_network_only_plugin( $plugin_file ) && ! is_plugin_active( $plugin_file ) ) {
if ( $show_network_active ) {
// On the non-network screen, show inactive network-only plugins if allowed
$plugins['inactive'][ $plugin_file ] = $plugin_data;
} else {
// On the non-network screen, filter out network-only plugins as long as they're not individually active
unset( $plugins['all'][ $plugin_file ] );
}
} elseif ( ! $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) {
if ( $show_network_active ) {
// On the non-network screen, show network-active plugins if allowed
$plugins['active'][ $plugin_file ] = $plugin_data;
} else {
// On the non-network screen, filter out network-active plugins
unset( $plugins['all'][ $plugin_file ] );
}
} elseif ( ( ! $screen->in_admin( 'network' ) && is_plugin_active( $plugin_file ) )
|| ( $screen->in_admin( 'network' ) && is_plugin_active_for_network( $plugin_file ) ) ) {
// On the non-network screen, populate the active list with plugins that are individually activated
// On the network-admin screen, populate the active list with plugins that are network activated
$plugins['active'][ $plugin_file ] = $plugin_data;
} else {
if ( isset( $recently_activated[ $plugin_file ] ) ) {
// Populate the recently activated list with plugins that have been recently activated
$plugins['recently_activated'][ $plugin_file ] = $plugin_data;
}
// Populate the inactive list with plugins that aren't activated
$plugins['inactive'][ $plugin_file ] = $plugin_data;
}
}
if ( strlen( $s ) ) {
$status = 'search';
$plugins['search'] = array_filter( $plugins['all'], array( $this, '_search_callback' ) );
}
$totals = array();
foreach ( $plugins as $type => $list )
$totals[ $type ] = count( $list );
if ( empty( $plugins[ $status ] ) && !in_array( $status, array( 'all', 'search' ) ) )
$status = 'all';
$this->items = array();
foreach ( $plugins[ $status ] as $plugin_file => $plugin_data ) {
// Translate, Don't Apply Markup, Sanitize HTML
$this->items[$plugin_file] = _get_plugin_data_markup_translate( $plugin_file, $plugin_data, false, true );
}
$total_this_page = $totals[ $status ];
if ( ! $orderby ) {
$orderby = 'Name';
} else {
$orderby = ucfirst( $orderby );
}
$order = strtoupper( $order );
uasort( $this->items, array( $this, '_order_callback' ) );
$plugins_per_page = $this->get_items_per_page( str_replace( '-', '_', $screen->id . '_per_page' ), 999 );
$start = ( $page - 1 ) * $plugins_per_page;
if ( $total_this_page > $plugins_per_page )
$this->items = array_slice( $this->items, $start, $plugins_per_page );
$this->set_pagination_args( array(
'total_items' => $total_this_page,
'per_page' => $plugins_per_page,
) );
}
/**
* @global string $s URL encoded search term.
*
* @param array $plugin
* @return bool
*/
public function _search_callback( $plugin ) {
global $s;
foreach ( $plugin as $value ) {
if ( is_string( $value ) && false !== stripos( strip_tags( $value ), urldecode( $s ) ) ) {
return true;
}
}
return false;
}
/**
* @global string $orderby
* @global string $order
* @param array $plugin_a
* @param array $plugin_b
* @return int
*/
public function _order_callback( $plugin_a, $plugin_b ) {
global $orderby, $order;
$a = $plugin_a[$orderby];
$b = $plugin_b[$orderby];
if ( $a == $b )
return 0;
if ( 'DESC' === $order ) {
return strcasecmp( $b, $a );
} else {
return strcasecmp( $a, $b );
}
}
/**
*
* @global array $plugins
*/
public function no_items() {
global $plugins;
if ( ! empty( $_REQUEST['s'] ) ) {
$s = esc_html( wp_unslash( $_REQUEST['s'] ) );
printf( __( 'No plugins found for &#8220;%s&#8221;.' ), $s );
// We assume that somebody who can install plugins in multisite is experienced enough to not need this helper link.
if ( ! is_multisite() && current_user_can( 'install_plugins' ) ) {
echo ' <a href="' . esc_url( admin_url( 'plugin-install.php?tab=search&s=' . urlencode( $s ) ) ) . '">' . __( 'Search for plugins in the WordPress Plugin Directory.' ) . '</a>';
}
} elseif ( ! empty( $plugins['all'] ) )
_e( 'No plugins found.' );
else
_e( 'You do not appear to have any plugins available at this time.' );
}
/**
*
* @global string $status
* @return array
*/
public function get_columns() {
global $status;
return array(
'cb' => !in_array( $status, array( 'mustuse', 'dropins' ) ) ? '<input type="checkbox" />' : '',
'name' => __( 'Plugin' ),
'description' => __( 'Description' ),
);
}
/**
* @return array
*/
protected function get_sortable_columns() {
return array();
}
/**
*
* @global array $totals
* @global string $status
* @return array
*/
protected function get_views() {
global $totals, $status;
$status_links = array();
foreach ( $totals as $type => $count ) {
if ( !$count )
continue;
switch ( $type ) {
case 'all':
$text = _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $count, 'plugins' );
break;
case 'active':
$text = _n( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', $count );
break;
case 'recently_activated':
$text = _n( 'Recently Active <span class="count">(%s)</span>', 'Recently Active <span class="count">(%s)</span>', $count );
break;
case 'inactive':
$text = _n( 'Inactive <span class="count">(%s)</span>', 'Inactive <span class="count">(%s)</span>', $count );
break;
case 'mustuse':
$text = _n( 'Must-Use <span class="count">(%s)</span>', 'Must-Use <span class="count">(%s)</span>', $count );
break;
case 'dropins':
$text = _n( 'Drop-ins <span class="count">(%s)</span>', 'Drop-ins <span class="count">(%s)</span>', $count );
break;
case 'upgrade':
$text = _n( 'Update Available <span class="count">(%s)</span>', 'Update Available <span class="count">(%s)</span>', $count );
break;
}
if ( 'search' !== $type ) {
$status_links[$type] = sprintf( "<a href='%s' %s>%s</a>",
add_query_arg('plugin_status', $type, 'plugins.php'),
( $type === $status ) ? ' class="current"' : '',
sprintf( $text, number_format_i18n( $count ) )
);
}
}
return $status_links;
}
/**
*
* @global string $status
* @return array
*/
protected function get_bulk_actions() {
global $status;
$actions = array();
if ( 'active' != $status )
$actions['activate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Activate' ) : __( 'Activate' );
if ( 'inactive' != $status && 'recent' != $status )
$actions['deactivate-selected'] = $this->screen->in_admin( 'network' ) ? __( 'Network Deactivate' ) : __( 'Deactivate' );
if ( !is_multisite() || $this->screen->in_admin( 'network' ) ) {
if ( current_user_can( 'update_plugins' ) )
$actions['update-selected'] = __( 'Update' );
if ( current_user_can( 'delete_plugins' ) && ( 'active' != $status ) )
$actions['delete-selected'] = __( 'Delete' );
}
return $actions;
}
/**
* @global string $status
* @param string $which
*/
public function bulk_actions( $which = '' ) {
global $status;
if ( in_array( $status, array( 'mustuse', 'dropins' ) ) )
return;
parent::bulk_actions( $which );
}
/**
* @global string $status
* @param string $which
*/
protected function extra_tablenav( $which ) {
global $status;
if ( ! in_array($status, array('recently_activated', 'mustuse', 'dropins') ) )
return;
echo '<div class="alignleft actions">';
if ( 'recently_activated' == $status ) {
submit_button( __( 'Clear List' ), 'button', 'clear-recent-list', false );
} elseif ( 'top' === $which && 'mustuse' === $status ) {
/* translators: %s: mu-plugins directory name */
echo '<p>' . sprintf( __( 'Files in the %s directory are executed automatically.' ),
'<code>' . str_replace( ABSPATH, '/', WPMU_PLUGIN_DIR ) . '</code>'
) . '</p>';
} elseif ( 'top' === $which && 'dropins' === $status ) {
/* translators: %s: wp-content directory name */
echo '<p>' . sprintf( __( 'Drop-ins are advanced plugins in the %s directory that replace WordPress functionality when present.' ),
'<code>' . str_replace( ABSPATH, '', WP_CONTENT_DIR ) . '</code>'
) . '</p>';
}
echo '</div>';
}
/**
* @return string
*/
public function current_action() {
if ( isset($_POST['clear-recent-list']) )
return 'clear-recent-list';
return parent::current_action();
}
/**
*
* @global string $status
*/
public function display_rows() {
global $status;
if ( is_multisite() && ! $this->screen->in_admin( 'network' ) && in_array( $status, array( 'mustuse', 'dropins' ) ) )
return;
foreach ( $this->items as $plugin_file => $plugin_data )
$this->single_row( array( $plugin_file, $plugin_data ) );
}
/**
* @global string $status
* @global int $page
* @global string $s
* @global array $totals
*
* @param array $item
*/
public function single_row( $item ) {
global $status, $page, $s, $totals;
list( $plugin_file, $plugin_data ) = $item;
$context = $status;
$screen = $this->screen;
// Pre-order.
$actions = array(
'deactivate' => '',
'activate' => '',
'details' => '',
'edit' => '',
'delete' => '',
);
// Do not restrict by default
$restrict_network_active = false;
$restrict_network_only = false;
if ( 'mustuse' === $context ) {
$is_active = true;
} elseif ( 'dropins' === $context ) {
$dropins = _get_dropins();
$plugin_name = $plugin_file;
if ( $plugin_file != $plugin_data['Name'] )
$plugin_name .= '<br/>' . $plugin_data['Name'];
if ( true === ( $dropins[ $plugin_file ][1] ) ) { // Doesn't require a constant
$is_active = true;
$description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
} elseif ( defined( $dropins[ $plugin_file ][1] ) && constant( $dropins[ $plugin_file ][1] ) ) { // Constant is true
$is_active = true;
$description = '<p><strong>' . $dropins[ $plugin_file ][0] . '</strong></p>';
} else {
$is_active = false;
$description = '<p><strong>' . $dropins[ $plugin_file ][0] . ' <span class="error-message">' . __( 'Inactive:' ) . '</span></strong> ' .
/* translators: 1: drop-in constant name, 2: wp-config.php */
sprintf( __( 'Requires %1$s in %2$s file.' ),
"<code>define('" . $dropins[ $plugin_file ][1] . "', true);</code>",
'<code>wp-config.php</code>'
) . '</p>';
}
if ( $plugin_data['Description'] )
$description .= '<p>' . $plugin_data['Description'] . '</p>';
} else {
if ( $screen->in_admin( 'network' ) ) {
$is_active = is_plugin_active_for_network( $plugin_file );
} else {
$is_active = is_plugin_active( $plugin_file );
$restrict_network_active = ( is_multisite() && is_plugin_active_for_network( $plugin_file ) );
$restrict_network_only = ( is_multisite() && is_network_only_plugin( $plugin_file ) && ! $is_active );
}
if ( $screen->in_admin( 'network' ) ) {
if ( $is_active ) {
if ( current_user_can( 'manage_network_plugins' ) ) {
/* translators: %s: plugin name */
$actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( __( 'Network deactivate %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Deactivate' ) . '</a>';
}
} else {
if ( current_user_can( 'manage_network_plugins' ) ) {
/* translators: %s: plugin name */
$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Network Activate %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Network Activate' ) . '</a>';
}
if ( current_user_can( 'delete_plugins' ) && ! is_plugin_active( $plugin_file ) ) {
/* translators: %s: plugin name */
$actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( __( 'Delete %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
}
}
} else {
if ( $restrict_network_active ) {
$actions = array(
'network_active' => __( 'Network Active' ),
);
} elseif ( $restrict_network_only ) {
$actions = array(
'network_only' => __( 'Network Only' ),
);
} elseif ( $is_active ) {
/* translators: %s: plugin name */
$actions['deactivate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=deactivate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'deactivate-plugin_' . $plugin_file ) . '" aria-label="' . esc_attr( sprintf( __( 'Deactivate %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Deactivate' ) . '</a>';
} else {
/* translators: %s: plugin name */
$actions['activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'activate-plugin_' . $plugin_file ) . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Activate %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Activate' ) . '</a>';
if ( ! is_multisite() && current_user_can( 'delete_plugins' ) ) {
/* translators: %s: plugin name */
$actions['delete'] = '<a href="' . wp_nonce_url( 'plugins.php?action=delete-selected&amp;checked[]=' . $plugin_file . '&amp;plugin_status=' . $context . '&amp;paged=' . $page . '&amp;s=' . $s, 'bulk-plugins' ) . '" class="delete" aria-label="' . esc_attr( sprintf( __( 'Delete %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Delete' ) . '</a>';
}
} // end if $is_active
} // end if $screen->in_admin( 'network' )
if ( ( ! is_multisite() || $screen->in_admin( 'network' ) ) && current_user_can( 'edit_plugins' ) && is_writable( WP_PLUGIN_DIR . '/' . $plugin_file ) ) {
/* translators: %s: plugin name */
$actions['edit'] = '<a href="plugin-editor.php?file=' . $plugin_file . '" class="edit" aria-label="' . esc_attr( sprintf( __( 'Edit %s' ), $plugin_data['Name'] ) ) . '">' . __( 'Edit' ) . '</a>';
}
} // end if $context
$actions = array_filter( $actions );
if ( $screen->in_admin( 'network' ) ) {
/**
* Filter the action links displayed for each plugin in the Network Admin Plugins list table.
*
* The default action links for the Network plugins list table include
* 'Network Activate', 'Network Deactivate', 'Edit', and 'Delete'.
*
* @since 3.1.0 As `{$prefix}_plugin_action_links`
* @since 4.4.0
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*/
$actions = apply_filters( 'network_admin_plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
/**
* Filter the list of action links displayed for a specific plugin in the Network Admin Plugins list table.
*
* The dynamic portion of the hook name, $plugin_file, refers to the path
* to the plugin file, relative to the plugins directory.
*
* @since 3.1.0 As `{$prefix}_plugin_action_links_{$plugin_file}`
* @since 4.4.0
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*/
$actions = apply_filters( "network_admin_plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
} else {
/**
* Filter the action links displayed for each plugin in the Plugins list table.
*
* The default action links for the site plugins list table include
* 'Activate', 'Deactivate', and 'Edit', for a network site, and
* 'Activate', 'Deactivate', 'Edit', and 'Delete' for a single site.
*
* @since 2.5.0 As `{$prefix}_plugin_action_links`
* @since 4.4.0
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*/
$actions = apply_filters( 'plugin_action_links', $actions, $plugin_file, $plugin_data, $context );
/**
* Filter the list of action links displayed for a specific plugin in the Plugins list table.
*
* The dynamic portion of the hook name, $plugin_file, refers to the path
* to the plugin file, relative to the plugins directory.
*
* @since 2.7.0 As `{$prefix}_plugin_action_links_{$plugin_file}`
* @since 4.4.0
*
* @param array $actions An array of plugin action links.
* @param string $plugin_file Path to the plugin file relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $context The plugin context. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade',
* 'Must-Use', 'Drop-ins', 'Search'.
*/
$actions = apply_filters( "plugin_action_links_{$plugin_file}", $actions, $plugin_file, $plugin_data, $context );
}
$class = $is_active ? 'active' : 'inactive';
$checkbox_id = "checkbox_" . md5($plugin_data['Name']);
if ( $restrict_network_active || $restrict_network_only || in_array( $status, array( 'mustuse', 'dropins' ) ) ) {
$checkbox = '';
} else {
$checkbox = "<label class='screen-reader-text' for='" . $checkbox_id . "' >" . sprintf( __( 'Select %s' ), $plugin_data['Name'] ) . "</label>"
. "<input type='checkbox' name='checked[]' value='" . esc_attr( $plugin_file ) . "' id='" . $checkbox_id . "' />";
}
if ( 'dropins' != $context ) {
$description = '<p>' . ( $plugin_data['Description'] ? $plugin_data['Description'] : '&nbsp;' ) . '</p>';
$plugin_name = $plugin_data['Name'];
}
if ( ! empty( $totals['upgrade'] ) && ! empty( $plugin_data['update'] ) )
$class .= ' update';
$plugin_slug = isset( $plugin_data['slug'] ) ? $plugin_data['slug'] : sanitize_title( $plugin_name );
printf( '<tr class="%s" data-slug="%s" data-plugin="%s">',
esc_attr( $class ),
esc_attr( $plugin_slug ),
esc_attr( $plugin_file )
);
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
foreach ( $columns as $column_name => $column_display_name ) {
$extra_classes = '';
if ( in_array( $column_name, $hidden ) ) {
$extra_classes = ' hidden';
}
switch ( $column_name ) {
case 'cb':
echo "<th scope='row' class='check-column'>$checkbox</th>";
break;
case 'name':
echo "<td class='plugin-title column-primary'><strong>$plugin_name</strong>";
echo $this->row_actions( $actions, true );
echo "</td>";
break;
case 'description':
$classes = 'column-description desc';
echo "<td class='$classes{$extra_classes}'>
<div class='plugin-description'>$description</div>
<div class='$class second plugin-version-author-uri'>";
$plugin_meta = array();
if ( !empty( $plugin_data['Version'] ) )
$plugin_meta[] = sprintf( __( 'Version %s' ), $plugin_data['Version'] );
if ( !empty( $plugin_data['Author'] ) ) {
$author = $plugin_data['Author'];
if ( !empty( $plugin_data['AuthorURI'] ) )
$author = '<a href="' . $plugin_data['AuthorURI'] . '">' . $plugin_data['Author'] . '</a>';
$plugin_meta[] = sprintf( __( 'By %s' ), $author );
}
// Details link using API info, if available
if ( isset( $plugin_data['slug'] ) && current_user_can( 'install_plugins' ) ) {
$plugin_meta[] = sprintf( '<a href="%s" class="thickbox open-plugin-details-modal" aria-label="%s" data-title="%s">%s</a>',
esc_url( network_admin_url( 'plugin-install.php?tab=plugin-information&plugin=' . $plugin_data['slug'] .
'&TB_iframe=true&width=600&height=550' ) ),
esc_attr( sprintf( __( 'More information about %s' ), $plugin_name ) ),
esc_attr( $plugin_name ),
__( 'View details' )
);
} elseif ( ! empty( $plugin_data['PluginURI'] ) ) {
$plugin_meta[] = sprintf( '<a href="%s">%s</a>',
esc_url( $plugin_data['PluginURI'] ),
__( 'Visit plugin site' )
);
}
/**
* Filter the array of row meta for each plugin in the Plugins list table.
*
* @since 2.8.0
*
* @param array $plugin_meta An array of the plugin's metadata,
* including the version, author,
* author URI, and plugin URI.
* @param string $plugin_file Path to the plugin file, relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $status Status of the plugin. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
* 'Drop-ins', 'Search'.
*/
$plugin_meta = apply_filters( 'plugin_row_meta', $plugin_meta, $plugin_file, $plugin_data, $status );
echo implode( ' | ', $plugin_meta );
echo "</div></td>";
break;
default:
$classes = "$column_name column-$column_name$class";
echo "<td class='$classes{$extra_classes}'>";
/**
* Fires inside each custom column of the Plugins list table.
*
* @since 3.1.0
*
* @param string $column_name Name of the column.
* @param string $plugin_file Path to the plugin file.
* @param array $plugin_data An array of plugin data.
*/
do_action( 'manage_plugins_custom_column', $column_name, $plugin_file, $plugin_data );
echo "</td>";
}
}
echo "</tr>";
/**
* Fires after each row in the Plugins list table.
*
* @since 2.3.0
*
* @param string $plugin_file Path to the plugin file, relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $status Status of the plugin. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
* 'Drop-ins', 'Search'.
*/
do_action( 'after_plugin_row', $plugin_file, $plugin_data, $status );
/**
* Fires after each specific row in the Plugins list table.
*
* The dynamic portion of the hook name, `$plugin_file`, refers to the path
* to the plugin file, relative to the plugins directory.
*
* @since 2.7.0
*
* @param string $plugin_file Path to the plugin file, relative to the plugins directory.
* @param array $plugin_data An array of plugin data.
* @param string $status Status of the plugin. Defaults are 'All', 'Active',
* 'Inactive', 'Recently Activated', 'Upgrade', 'Must-Use',
* 'Drop-ins', 'Search'.
*/
do_action( "after_plugin_row_$plugin_file", $plugin_file, $plugin_data, $status );
}
/**
* Gets the name of the primary column for this specific list table.
*
* @since 4.3.0
* @access protected
*
* @return string Unalterable name for the primary column, in this case, 'name'.
*/
protected function get_primary_column_name() {
return 'name';
}
}

View File

@@ -0,0 +1,77 @@
<?php
/**
* List Table API: WP_Post_Comments_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Core class used to implement displaying post comments in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_Comments_List_Table
*/
class WP_Post_Comments_List_Table extends WP_Comments_List_Table {
/**
*
* @return array
*/
protected function get_column_info() {
return array(
array(
'author' => __( 'Author' ),
'comment' => _x( 'Comment', 'column name' ),
),
array(),
array(),
'comment',
);
}
/**
*
* @return array
*/
protected function get_table_classes() {
$classes = parent::get_table_classes();
$classes[] = 'wp-list-table';
$classes[] = 'comments-box';
return $classes;
}
/**
*
* @param bool $output_empty
*/
public function display( $output_empty = false ) {
$singular = $this->_args['singular'];
wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
?>
<table class="<?php echo implode( ' ', $this->get_table_classes() ); ?>" style="display:none;">
<tbody id="the-comment-list"<?php
if ( $singular ) {
echo " data-wp-lists='list:$singular'";
} ?>>
<?php if ( ! $output_empty ) {
$this->display_rows_or_placeholder();
} ?>
</tbody>
</table>
<?php
}
/**
*
* @param bool $comment_status
* @return int
*/
public function get_per_page( $comment_status = false ) {
return 10;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
<?php
/**
* Administration API: WP_Site_Icon class
*
* @package WordPress
* @subpackage Administration
* @since 4.3.0
*/
/**
* Core class used to implement site icon functionality.
*
* @since 4.3.0
*/
class WP_Site_Icon {
/**
* The minimum size of the site icon.
*
* @since 4.3.0
* @access public
* @var int
*/
public $min_size = 512;
/**
* The size to which to crop the image so that we can display it in the UI nicely.
*
* @since 4.3.0
* @access public
* @var int
*/
public $page_crop = 512;
/**
* List of site icon sizes.
*
* @since 4.3.0
* @access public
* @var array
*/
public $site_icon_sizes = array(
/*
* Square, medium sized tiles for IE11+.
*
* See https://msdn.microsoft.com/library/dn455106(v=vs.85).aspx
*/
270,
/*
* App icon for Android/Chrome.
*
* @link https://developers.google.com/web/updates/2014/11/Support-for-theme-color-in-Chrome-39-for-Android
* @link https://developer.chrome.com/multidevice/android/installtohomescreen
*/
192,
/*
* App icons up to iPhone 6 Plus.
*
* See https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/MobileHIG/IconMatrix.html
*/
180,
// Our regular Favicon.
32,
);
/**
* Registers actions and filters.
*
* @since 4.3.0
* @access public
*/
public function __construct() {
add_action( 'delete_attachment', array( $this, 'delete_attachment_data' ) );
add_filter( 'get_post_metadata', array( $this, 'get_post_metadata' ), 10, 4 );
}
/**
* Creates an attachment 'object'.
*
* @since 4.3.0
*
* @param string $cropped Cropped image URL.
* @param int $parent_attachment_id Attachment ID of parent image.
* @return array Attachment object.
*/
public function create_attachment_object( $cropped, $parent_attachment_id ) {
$parent = get_post( $parent_attachment_id );
$parent_url = wp_get_attachment_url( $parent->ID );
$url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url );
$size = @getimagesize( $cropped );
$image_type = ( $size ) ? $size['mime'] : 'image/jpeg';
$object = array(
'ID' => $parent_attachment_id,
'post_title' => basename( $cropped ),
'post_content' => $url,
'post_mime_type' => $image_type,
'guid' => $url,
'context' => 'site-icon'
);
return $object;
}
/**
* Inserts an attachment.
*
* @since 4.3.0
* @access public
*
* @param array $object Attachment object.
* @param string $file File path of the attached image.
* @return int Attachment ID
*/
public function insert_attachment( $object, $file ) {
$attachment_id = wp_insert_attachment( $object, $file );
$metadata = wp_generate_attachment_metadata( $attachment_id, $file );
/**
* Filter the site icon attachment metadata.
*
* @since 4.3.0
*
* @see wp_generate_attachment_metadata()
*
* @param array $metadata Attachment metadata.
*/
$metadata = apply_filters( 'site_icon_attachment_metadata', $metadata );
wp_update_attachment_metadata( $attachment_id, $metadata );
return $attachment_id;
}
/**
* Adds additional sizes to be made when creating the site_icon images.
*
* @since 4.3.0
* @access public
*
* @param array $sizes List of additional sizes.
* @return array Additional image sizes.
*/
public function additional_sizes( $sizes = array() ) {
$only_crop_sizes = array();
/**
* Filter the different dimensions that a site icon is saved in.
*
* @since 4.3.0
*
* @param array $site_icon_sizes Sizes available for the Site Icon.
*/
$this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes );
// Use a natural sort of numbers.
natsort( $this->site_icon_sizes );
$this->site_icon_sizes = array_reverse( $this->site_icon_sizes );
// ensure that we only resize the image into
foreach ( $sizes as $name => $size_array ) {
if ( isset( $size_array['crop'] ) ) {
$only_crop_sizes[ $name ] = $size_array;
}
}
foreach ( $this->site_icon_sizes as $size ) {
if ( $size < $this->min_size ) {
$only_crop_sizes[ 'site_icon-' . $size ] = array(
'width ' => $size,
'height' => $size,
'crop' => true,
);
}
}
return $only_crop_sizes;
}
/**
* Adds Site Icon sizes to the array of image sizes on demand.
*
* @since 4.3.0
* @access public
*
* @param array $sizes List of image sizes.
* @return array List of intermediate image sizes.
*/
public function intermediate_image_sizes( $sizes = array() ) {
/** This filter is documented in wp-admin/includes/class-wp-site-icon.php */
$this->site_icon_sizes = apply_filters( 'site_icon_image_sizes', $this->site_icon_sizes );
foreach ( $this->site_icon_sizes as $size ) {
$sizes[] = 'site_icon-' . $size;
}
return $sizes;
}
/**
* Deletes the Site Icon when the image file is deleted.
*
* @since 4.3.0
* @access public
*
* @param int $post_id Attachment ID.
*/
public function delete_attachment_data( $post_id ) {
$site_icon_id = get_option( 'site_icon' );
if ( $site_icon_id && $post_id == $site_icon_id ) {
delete_option( 'site_icon' );
}
}
/**
* Adds custom image sizes when meta data for an image is requested, that happens to be used as Site Icon.
*
* @since 4.3.0
* @access public
*
* @param null|array|string $value The value get_metadata() should return a single metadata value, or an
* array of values.
* @param int $post_id Post ID.
* @param string $meta_key Meta key.
* @param string|array $single Meta value, or an array of values.
* @return array|null|string The attachment metadata value, array of values, or null.
*/
public function get_post_metadata( $value, $post_id, $meta_key, $single ) {
if ( $single && '_wp_attachment_backup_sizes' === $meta_key ) {
$site_icon_id = get_option( 'site_icon' );
if ( $post_id == $site_icon_id ) {
add_filter( 'intermediate_image_sizes', array( $this, 'intermediate_image_sizes' ) );
}
}
return $value;
}
}
/**
* @global WP_Site_Icon $wp_site_icon
*/
$GLOBALS['wp_site_icon'] = new WP_Site_Icon;

View File

@@ -0,0 +1,635 @@
<?php
/**
* List Table API: WP_Terms_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying terms in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Terms_List_Table extends WP_List_Table {
public $callback_args;
private $level;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @global string $post_type
* @global string $taxonomy
* @global string $action
* @global object $tax
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
global $post_type, $taxonomy, $action, $tax;
parent::__construct( array(
'plural' => 'tags',
'singular' => 'tag',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
$action = $this->screen->action;
$post_type = $this->screen->post_type;
$taxonomy = $this->screen->taxonomy;
if ( empty( $taxonomy ) )
$taxonomy = 'post_tag';
if ( ! taxonomy_exists( $taxonomy ) )
wp_die( __( 'Invalid taxonomy' ) );
$tax = get_taxonomy( $taxonomy );
// @todo Still needed? Maybe just the show_ui part.
if ( empty( $post_type ) || !in_array( $post_type, get_post_types( array( 'show_ui' => true ) ) ) )
$post_type = 'post';
}
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->manage_terms );
}
/**
* @access public
*/
public function prepare_items() {
$tags_per_page = $this->get_items_per_page( 'edit_' . $this->screen->taxonomy . '_per_page' );
if ( 'post_tag' === $this->screen->taxonomy ) {
/**
* Filter the number of terms displayed per page for the Tags list table.
*
* @since 2.8.0
*
* @param int $tags_per_page Number of tags to be displayed. Default 20.
*/
$tags_per_page = apply_filters( 'edit_tags_per_page', $tags_per_page );
/**
* Filter the number of terms displayed per page for the Tags list table.
*
* @since 2.7.0
* @deprecated 2.8.0 Use edit_tags_per_page instead.
*
* @param int $tags_per_page Number of tags to be displayed. Default 20.
*/
$tags_per_page = apply_filters( 'tagsperpage', $tags_per_page );
} elseif ( 'category' === $this->screen->taxonomy ) {
/**
* Filter the number of terms displayed per page for the Categories list table.
*
* @since 2.8.0
*
* @param int $tags_per_page Number of categories to be displayed. Default 20.
*/
$tags_per_page = apply_filters( 'edit_categories_per_page', $tags_per_page );
}
$search = !empty( $_REQUEST['s'] ) ? trim( wp_unslash( $_REQUEST['s'] ) ) : '';
$args = array(
'search' => $search,
'page' => $this->get_pagenum(),
'number' => $tags_per_page,
);
if ( !empty( $_REQUEST['orderby'] ) )
$args['orderby'] = trim( wp_unslash( $_REQUEST['orderby'] ) );
if ( !empty( $_REQUEST['order'] ) )
$args['order'] = trim( wp_unslash( $_REQUEST['order'] ) );
$this->callback_args = $args;
$this->set_pagination_args( array(
'total_items' => wp_count_terms( $this->screen->taxonomy, compact( 'search' ) ),
'per_page' => $tags_per_page,
) );
}
/**
*
* @return bool
*/
public function has_items() {
// todo: populate $this->items in prepare_items()
return true;
}
/**
* @access public
*/
public function no_items() {
echo get_taxonomy( $this->screen->taxonomy )->labels->not_found;
}
/**
*
* @return array
*/
protected function get_bulk_actions() {
$actions = array();
$actions['delete'] = __( 'Delete' );
return $actions;
}
/**
*
* @return string
*/
public function current_action() {
if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['delete_tags'] ) && ( 'delete' === $_REQUEST['action'] || 'delete' === $_REQUEST['action2'] ) )
return 'bulk-delete';
return parent::current_action();
}
/**
*
* @return array
*/
public function get_columns() {
$columns = array(
'cb' => '<input type="checkbox" />',
'name' => _x( 'Name', 'term name' ),
'description' => __( 'Description' ),
'slug' => __( 'Slug' ),
);
if ( 'link_category' === $this->screen->taxonomy ) {
$columns['links'] = __( 'Links' );
} else {
$columns['posts'] = _x( 'Count', 'Number/count of items' );
}
return $columns;
}
/**
*
* @return array
*/
protected function get_sortable_columns() {
return array(
'name' => 'name',
'description' => 'description',
'slug' => 'slug',
'posts' => 'count',
'links' => 'count'
);
}
/**
* @access public
*/
public function display_rows_or_placeholder() {
$taxonomy = $this->screen->taxonomy;
$args = wp_parse_args( $this->callback_args, array(
'page' => 1,
'number' => 20,
'search' => '',
'hide_empty' => 0
) );
$page = $args['page'];
// Set variable because $args['number'] can be subsequently overridden.
$number = $args['number'];
$args['offset'] = $offset = ( $page - 1 ) * $number;
// Convert it to table rows.
$count = 0;
if ( is_taxonomy_hierarchical( $taxonomy ) && ! isset( $args['orderby'] ) ) {
// We'll need the full set of terms then.
$args['number'] = $args['offset'] = 0;
}
$terms = get_terms( $taxonomy, $args );
if ( empty( $terms ) || ! is_array( $terms ) ) {
echo '<tr class="no-items"><td class="colspanchange" colspan="' . $this->get_column_count() . '">';
$this->no_items();
echo '</td></tr>';
return;
}
if ( is_taxonomy_hierarchical( $taxonomy ) && ! isset( $args['orderby'] ) ) {
if ( ! empty( $args['search'] ) ) {// Ignore children on searches.
$children = array();
} else {
$children = _get_term_hierarchy( $taxonomy );
}
// Some funky recursion to get the job done( Paging & parents mainly ) is contained within, Skip it for non-hierarchical taxonomies for performance sake
$this->_rows( $taxonomy, $terms, $children, $offset, $number, $count );
} else {
foreach ( $terms as $term ) {
$this->single_row( $term );
}
}
}
/**
* @param string $taxonomy
* @param array $terms
* @param array $children
* @param int $start
* @param int $per_page
* @param int $count
* @param int $parent
* @param int $level
*/
private function _rows( $taxonomy, $terms, &$children, $start, $per_page, &$count, $parent = 0, $level = 0 ) {
$end = $start + $per_page;
foreach ( $terms as $key => $term ) {
if ( $count >= $end )
break;
if ( $term->parent != $parent && empty( $_REQUEST['s'] ) )
continue;
// If the page starts in a subtree, print the parents.
if ( $count == $start && $term->parent > 0 && empty( $_REQUEST['s'] ) ) {
$my_parents = $parent_ids = array();
$p = $term->parent;
while ( $p ) {
$my_parent = get_term( $p, $taxonomy );
$my_parents[] = $my_parent;
$p = $my_parent->parent;
if ( in_array( $p, $parent_ids ) ) // Prevent parent loops.
break;
$parent_ids[] = $p;
}
unset( $parent_ids );
$num_parents = count( $my_parents );
while ( $my_parent = array_pop( $my_parents ) ) {
echo "\t";
$this->single_row( $my_parent, $level - $num_parents );
$num_parents--;
}
}
if ( $count >= $start ) {
echo "\t";
$this->single_row( $term, $level );
}
++$count;
unset( $terms[$key] );
if ( isset( $children[$term->term_id] ) && empty( $_REQUEST['s'] ) )
$this->_rows( $taxonomy, $terms, $children, $start, $per_page, $count, $term->term_id, $level + 1 );
}
}
/**
* @global string $taxonomy
* @param object $tag
* @param int $level
*/
public function single_row( $tag, $level = 0 ) {
global $taxonomy;
$tag = sanitize_term( $tag, $taxonomy );
$this->level = $level;
echo '<tr id="tag-' . $tag->term_id . '">';
$this->single_row_columns( $tag );
echo '</tr>';
}
/**
* @param object $tag
* @return string
*/
public function column_cb( $tag ) {
$default_term = get_option( 'default_' . $this->screen->taxonomy );
if ( current_user_can( get_taxonomy( $this->screen->taxonomy )->cap->delete_terms ) && $tag->term_id != $default_term )
return '<label class="screen-reader-text" for="cb-select-' . $tag->term_id . '">' . sprintf( __( 'Select %s' ), $tag->name ) . '</label>'
. '<input type="checkbox" name="delete_tags[]" value="' . $tag->term_id . '" id="cb-select-' . $tag->term_id . '" />';
return '&nbsp;';
}
/**
* @param object $tag
* @return string
*/
public function column_name( $tag ) {
$taxonomy = $this->screen->taxonomy;
$pad = str_repeat( '&#8212; ', max( 0, $this->level ) );
/**
* Filter display of the term name in the terms list table.
*
* The default output may include padding due to the term's
* current level in the term hierarchy.
*
* @since 2.5.0
*
* @see WP_Terms_List_Table::column_name()
*
* @param string $pad_tag_name The term name, padded if not top-level.
* @param object $tag Term object.
*/
$name = apply_filters( 'term_name', $pad . ' ' . $tag->name, $tag );
$qe_data = get_term( $tag->term_id, $taxonomy, OBJECT, 'edit' );
$uri = ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ? wp_get_referer() : $_SERVER['REQUEST_URI'];
$edit_link = add_query_arg(
'wp_http_referer',
urlencode( wp_unslash( $uri ) ),
get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type )
);
$out = sprintf(
'<strong><a class="row-title" href="%s" aria-label="%s">%s</a></strong><br />',
esc_url( $edit_link ),
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( '&#8220;%s&#8221; (Edit)' ), $tag->name ) ),
$name
);
$out .= '<div class="hidden" id="inline_' . $qe_data->term_id . '">';
$out .= '<div class="name">' . $qe_data->name . '</div>';
/** This filter is documented in wp-admin/edit-tag-form.php */
$out .= '<div class="slug">' . apply_filters( 'editable_slug', $qe_data->slug, $qe_data ) . '</div>';
$out .= '<div class="parent">' . $qe_data->parent . '</div></div>';
return $out;
}
/**
* Gets the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'name'.
*/
protected function get_default_primary_column_name() {
return 'name';
}
/**
* Generates and displays row action links.
*
* @since 4.3.0
* @access protected
*
* @param object $tag Tag being acted upon.
* @param string $column_name Current column name.
* @param string $primary Primary column name.
* @return string Row actions output for terms.
*/
protected function handle_row_actions( $tag, $column_name, $primary ) {
if ( $primary !== $column_name ) {
return '';
}
$taxonomy = $this->screen->taxonomy;
$tax = get_taxonomy( $taxonomy );
$default_term = get_option( 'default_' . $taxonomy );
$uri = ( defined( 'DOING_AJAX' ) && DOING_AJAX ) ? wp_get_referer() : $_SERVER['REQUEST_URI'];
$edit_link = add_query_arg(
'wp_http_referer',
urlencode( wp_unslash( $uri ) ),
get_edit_term_link( $tag->term_id, $taxonomy, $this->screen->post_type )
);
$actions = array();
if ( current_user_can( $tax->cap->edit_terms ) ) {
$actions['edit'] = sprintf(
'<a href="%s" aria-label="%s">%s</a>',
esc_url( $edit_link ),
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;' ), $tag->name ) ),
__( 'Edit' )
);
$actions['inline hide-if-no-js'] = sprintf(
'<a href="#" class="editinline aria-button-if-js" aria-label="%s">%s</a>',
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( 'Quick edit &#8220;%s&#8221; inline' ), $tag->name ) ),
__( 'Quick&nbsp;Edit' )
);
}
if ( current_user_can( $tax->cap->delete_terms ) && $tag->term_id != $default_term ) {
$actions['delete'] = sprintf(
'<a href="%s" class="delete-tag aria-button-if-js" aria-label="%s">%s</a>',
wp_nonce_url( "edit-tags.php?action=delete&amp;taxonomy=$taxonomy&amp;tag_ID=$tag->term_id", 'delete-tag_' . $tag->term_id ),
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( 'Delete &#8220;%s&#8221;' ), $tag->name ) ),
__( 'Delete' )
);
}
if ( $tax->public ) {
$actions['view'] = sprintf(
'<a href="%s" aria-label="%s">%s</a>',
get_term_link( $tag ),
/* translators: %s: taxonomy term name */
esc_attr( sprintf( __( 'View &#8220;%s&#8221; archive' ), $tag->name ) ),
__( 'View' )
);
}
/**
* Filter the action links displayed for each term in the Tags list table.
*
* @since 2.8.0
* @deprecated 3.0.0 Use {$taxonomy}_row_actions instead.
*
* @param array $actions An array of action links to be displayed. Default
* 'Edit', 'Quick Edit', 'Delete', and 'View'.
* @param object $tag Term object.
*/
$actions = apply_filters( 'tag_row_actions', $actions, $tag );
/**
* Filter the action links displayed for each term in the terms list table.
*
* The dynamic portion of the hook name, `$taxonomy`, refers to the taxonomy slug.
*
* @since 3.0.0
*
* @param array $actions An array of action links to be displayed. Default
* 'Edit', 'Quick Edit', 'Delete', and 'View'.
* @param object $tag Term object.
*/
$actions = apply_filters( "{$taxonomy}_row_actions", $actions, $tag );
return $this->row_actions( $actions );
}
/**
* @param object $tag
* @return string
*/
public function column_description( $tag ) {
return $tag->description;
}
/**
* @param object $tag
* @return string
*/
public function column_slug( $tag ) {
/** This filter is documented in wp-admin/edit-tag-form.php */
return apply_filters( 'editable_slug', $tag->slug, $tag );
}
/**
* @param object $tag
* @return string
*/
public function column_posts( $tag ) {
$count = number_format_i18n( $tag->count );
$tax = get_taxonomy( $this->screen->taxonomy );
$ptype_object = get_post_type_object( $this->screen->post_type );
if ( ! $ptype_object->show_ui )
return $count;
if ( $tax->query_var ) {
$args = array( $tax->query_var => $tag->slug );
} else {
$args = array( 'taxonomy' => $tax->name, 'term' => $tag->slug );
}
if ( 'post' != $this->screen->post_type )
$args['post_type'] = $this->screen->post_type;
if ( 'attachment' === $this->screen->post_type )
return "<a href='" . esc_url ( add_query_arg( $args, 'upload.php' ) ) . "'>$count</a>";
return "<a href='" . esc_url ( add_query_arg( $args, 'edit.php' ) ) . "'>$count</a>";
}
/**
* @param object $tag
* @return string
*/
public function column_links( $tag ) {
$count = number_format_i18n( $tag->count );
if ( $count )
$count = "<a href='link-manager.php?cat_id=$tag->term_id'>$count</a>";
return $count;
}
/**
* @param object $tag
* @param string $column_name
* @return string
*/
public function column_default( $tag, $column_name ) {
/**
* Filter the displayed columns in the terms list table.
*
* The dynamic portion of the hook name, `$this->screen->taxonomy`,
* refers to the slug of the current taxonomy.
*
* @since 2.8.0
*
* @param string $string Blank string.
* @param string $column_name Name of the column.
* @param int $term_id Term ID.
*/
return apply_filters( "manage_{$this->screen->taxonomy}_custom_column", '', $column_name, $tag->term_id );
}
/**
* Outputs the hidden row displayed when inline editing
*
* @since 3.1.0
*/
public function inline_edit() {
$tax = get_taxonomy( $this->screen->taxonomy );
if ( ! current_user_can( $tax->cap->edit_terms ) )
return;
?>
<form method="get"><table style="display: none"><tbody id="inlineedit">
<tr id="inline-edit" class="inline-edit-row" style="display: none"><td colspan="<?php echo $this->get_column_count(); ?>" class="colspanchange">
<fieldset>
<legend class="inline-edit-legend"><?php _e( 'Quick Edit' ); ?></legend>
<div class="inline-edit-col">
<label>
<span class="title"><?php _ex( 'Name', 'term name' ); ?></span>
<span class="input-text-wrap"><input type="text" name="name" class="ptitle" value="" /></span>
</label>
<?php if ( !global_terms_enabled() ) { ?>
<label>
<span class="title"><?php _e( 'Slug' ); ?></span>
<span class="input-text-wrap"><input type="text" name="slug" class="ptitle" value="" /></span>
</label>
<?php } ?>
</div></fieldset>
<?php
$core_columns = array( 'cb' => true, 'description' => true, 'name' => true, 'slug' => true, 'posts' => true );
list( $columns ) = $this->get_column_info();
foreach ( $columns as $column_name => $column_display_name ) {
if ( isset( $core_columns[$column_name] ) )
continue;
/** This action is documented in wp-admin/includes/class-wp-posts-list-table.php */
do_action( 'quick_edit_custom_box', $column_name, 'edit-tags', $this->screen->taxonomy );
}
?>
<p class="inline-edit-save submit">
<button type="button" class="cancel button-secondary alignleft"><?php _e( 'Cancel' ); ?></button>
<button type="button" class="save button-primary alignright"><?php echo $tax->labels->update_item; ?></button>
<span class="spinner"></span>
<span class="error" style="display:none;"></span>
<?php wp_nonce_field( 'taxinlineeditnonce', '_inline_edit', false ); ?>
<input type="hidden" name="taxonomy" value="<?php echo esc_attr( $this->screen->taxonomy ); ?>" />
<input type="hidden" name="post_type" value="<?php echo esc_attr( $this->screen->post_type ); ?>" />
<br class="clear" />
</p>
</td></tr>
</tbody></table></form>
<?php
}
}

View File

@@ -0,0 +1,472 @@
<?php
/**
* List Table API: WP_Theme_Install_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying themes to install in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_Thenes_List_Table
*/
class WP_Theme_Install_List_Table extends WP_Themes_List_Table {
public $features = array();
/**
*
* @return bool
*/
public function ajax_user_can() {
return current_user_can( 'install_themes' );
}
/**
*
* @global array $tabs
* @global string $tab
* @global int $paged
* @global string $type
* @global array $theme_field_defaults
*/
public function prepare_items() {
include( ABSPATH . 'wp-admin/includes/theme-install.php' );
global $tabs, $tab, $paged, $type, $theme_field_defaults;
wp_reset_vars( array( 'tab' ) );
$search_terms = array();
$search_string = '';
if ( ! empty( $_REQUEST['s'] ) ){
$search_string = strtolower( wp_unslash( $_REQUEST['s'] ) );
$search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', $search_string ) ) ) );
}
if ( ! empty( $_REQUEST['features'] ) )
$this->features = $_REQUEST['features'];
$paged = $this->get_pagenum();
$per_page = 36;
// These are the tabs which are shown on the page,
$tabs = array();
$tabs['dashboard'] = __( 'Search' );
if ( 'search' === $tab )
$tabs['search'] = __( 'Search Results' );
$tabs['upload'] = __( 'Upload' );
$tabs['featured'] = _x( 'Featured', 'themes' );
//$tabs['popular'] = _x( 'Popular', 'themes' );
$tabs['new'] = _x( 'Latest', 'themes' );
$tabs['updated'] = _x( 'Recently Updated', 'themes' );
$nonmenu_tabs = array( 'theme-information' ); // Valid actions to perform which do not have a Menu item.
/** This filter is documented in wp-admin/theme-install.php */
$tabs = apply_filters( 'install_themes_tabs', $tabs );
/**
* Filter tabs not associated with a menu item on the Install Themes screen.
*
* @since 2.8.0
*
* @param array $nonmenu_tabs The tabs that don't have a menu item on
* the Install Themes screen.
*/
$nonmenu_tabs = apply_filters( 'install_themes_nonmenu_tabs', $nonmenu_tabs );
// If a non-valid menu tab has been selected, And it's not a non-menu action.
if ( empty( $tab ) || ( ! isset( $tabs[ $tab ] ) && ! in_array( $tab, (array) $nonmenu_tabs ) ) )
$tab = key( $tabs );
$args = array( 'page' => $paged, 'per_page' => $per_page, 'fields' => $theme_field_defaults );
switch ( $tab ) {
case 'search':
$type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
switch ( $type ) {
case 'tag':
$args['tag'] = array_map( 'sanitize_key', $search_terms );
break;
case 'term':
$args['search'] = $search_string;
break;
case 'author':
$args['author'] = $search_string;
break;
}
if ( ! empty( $this->features ) ) {
$args['tag'] = $this->features;
$_REQUEST['s'] = implode( ',', $this->features );
$_REQUEST['type'] = 'tag';
}
add_action( 'install_themes_table_header', 'install_theme_search_form', 10, 0 );
break;
case 'featured':
// case 'popular':
case 'new':
case 'updated':
$args['browse'] = $tab;
break;
default:
$args = false;
break;
}
/**
* Filter API request arguments for each Install Themes screen tab.
*
* The dynamic portion of the hook name, `$tab`, refers to the theme install
* tabs. Default tabs are 'dashboard', 'search', 'upload', 'featured',
* 'new', and 'updated'.
*
* @since 3.7.0
*
* @param array $args An array of themes API arguments.
*/
$args = apply_filters( 'install_themes_table_api_args_' . $tab, $args );
if ( ! $args )
return;
$api = themes_api( 'query_themes', $args );
if ( is_wp_error( $api ) )
wp_die( $api->get_error_message() . '</p> <p><a href="#" onclick="document.location.reload(); return false;">' . __( 'Try again' ) . '</a>' );
$this->items = $api->themes;
$this->set_pagination_args( array(
'total_items' => $api->info['results'],
'per_page' => $args['per_page'],
'infinite_scroll' => true,
) );
}
/**
* @access public
*/
public function no_items() {
_e( 'No themes match your request.' );
}
/**
*
* @global array $tabs
* @global string $tab
* @return array
*/
protected function get_views() {
global $tabs, $tab;
$display_tabs = array();
foreach ( (array) $tabs as $action => $text ) {
$class = ( $action === $tab ) ? ' class="current"' : '';
$href = self_admin_url('theme-install.php?tab=' . $action);
$display_tabs['theme-install-'.$action] = "<a href='$href'$class>$text</a>";
}
return $display_tabs;
}
/**
* @access public
*/
public function display() {
wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
?>
<div class="tablenav top themes">
<div class="alignleft actions">
<?php
/**
* Fires in the Install Themes list table header.
*
* @since 2.8.0
*/
do_action( 'install_themes_table_header' );
?>
</div>
<?php $this->pagination( 'top' ); ?>
<br class="clear" />
</div>
<div id="availablethemes">
<?php $this->display_rows_or_placeholder(); ?>
</div>
<?php
$this->tablenav( 'bottom' );
}
/**
* @access public
*/
public function display_rows() {
$themes = $this->items;
foreach ( $themes as $theme ) {
?>
<div class="available-theme installable-theme"><?php
$this->single_row( $theme );
?></div>
<?php } // end foreach $theme_names
$this->theme_installer();
}
/**
* Prints a theme from the WordPress.org API.
*
* @global array $themes_allowedtags
*
* @param object $theme An object that contains theme data returned by the WordPress.org API.
*
* Example theme data:
* object(stdClass)[59]
* public 'name' => string 'Magazine Basic'
* public 'slug' => string 'magazine-basic'
* public 'version' => string '1.1'
* public 'author' => string 'tinkerpriest'
* public 'preview_url' => string 'http://wp-themes.com/?magazine-basic'
* public 'screenshot_url' => string 'http://wp-themes.com/wp-content/themes/magazine-basic/screenshot.png'
* public 'rating' => float 80
* public 'num_ratings' => int 1
* public 'homepage' => string 'http://wordpress.org/themes/magazine-basic'
* public 'description' => string 'A basic magazine style layout with a fully customizable layout through a back-end interface. Designed by <a href="http://bavotasan.com">c.bavota</a> of <a href="http://tinkerpriestmedia.com">Tinker Priest Media</a>.'
* public 'download_link' => string 'http://wordpress.org/themes/download/magazine-basic.1.1.zip'
*/
public function single_row( $theme ) {
global $themes_allowedtags;
if ( empty( $theme ) )
return;
$name = wp_kses( $theme->name, $themes_allowedtags );
$author = wp_kses( $theme->author, $themes_allowedtags );
$preview_title = sprintf( __('Preview &#8220;%s&#8221;'), $name );
$preview_url = add_query_arg( array(
'tab' => 'theme-information',
'theme' => $theme->slug,
), self_admin_url( 'theme-install.php' ) );
$actions = array();
$install_url = add_query_arg( array(
'action' => 'install-theme',
'theme' => $theme->slug,
), self_admin_url( 'update.php' ) );
$update_url = add_query_arg( array(
'action' => 'upgrade-theme',
'theme' => $theme->slug,
), self_admin_url( 'update.php' ) );
$status = $this->_get_theme_status( $theme );
switch ( $status ) {
case 'update_available':
$actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
break;
case 'newer_installed':
case 'latest_installed':
$actions[] = '<span class="install-now" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
break;
case 'install':
default:
$actions[] = '<a class="install-now" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Install %s' ), $name ) ) . '">' . __( 'Install Now' ) . '</a>';
break;
}
$actions[] = '<a class="install-theme-preview" href="' . esc_url( $preview_url ) . '" title="' . esc_attr( sprintf( __( 'Preview %s' ), $name ) ) . '">' . __( 'Preview' ) . '</a>';
/**
* Filter the install action links for a theme in the Install Themes list table.
*
* @since 3.4.0
*
* @param array $actions An array of theme action hyperlinks. Defaults are
* links to Install Now, Preview, and Details.
* @param WP_Theme $theme Theme object.
*/
$actions = apply_filters( 'theme_install_actions', $actions, $theme );
?>
<a class="screenshot install-theme-preview" href="<?php echo esc_url( $preview_url ); ?>" title="<?php echo esc_attr( $preview_title ); ?>">
<img src="<?php echo esc_url( $theme->screenshot_url ); ?>" width="150" alt="" />
</a>
<h3><?php echo $name; ?></h3>
<div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
<div class="action-links">
<ul>
<?php foreach ( $actions as $action ): ?>
<li><?php echo $action; ?></li>
<?php endforeach; ?>
<li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
</ul>
</div>
<?php
$this->install_theme_info( $theme );
}
/**
* Prints the wrapper for the theme installer.
*/
public function theme_installer() {
?>
<div id="theme-installer" class="wp-full-overlay expanded">
<div class="wp-full-overlay-sidebar">
<div class="wp-full-overlay-header">
<a href="#" class="close-full-overlay button-secondary"><?php _e( 'Close' ); ?></a>
<span class="theme-install"></span>
</div>
<div class="wp-full-overlay-sidebar-content">
<div class="install-theme-info"></div>
</div>
<div class="wp-full-overlay-footer">
<button type="button" class="collapse-sidebar button-secondary" aria-expanded="true" aria-label="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
<span class="collapse-sidebar-arrow"></span>
<span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
</button>
</div>
</div>
<div class="wp-full-overlay-main"></div>
</div>
<?php
}
/**
* Prints the wrapper for the theme installer with a provided theme's data.
* Used to make the theme installer work for no-js.
*
* @param object $theme - A WordPress.org Theme API object.
*/
public function theme_installer_single( $theme ) {
?>
<div id="theme-installer" class="wp-full-overlay single-theme">
<div class="wp-full-overlay-sidebar">
<?php $this->install_theme_info( $theme ); ?>
</div>
<div class="wp-full-overlay-main">
<iframe src="<?php echo esc_url( $theme->preview_url ); ?>"></iframe>
</div>
</div>
<?php
}
/**
* Prints the info for a theme (to be used in the theme installer modal).
*
* @global array $themes_allowedtags
*
* @param object $theme - A WordPress.org Theme API object.
*/
public function install_theme_info( $theme ) {
global $themes_allowedtags;
if ( empty( $theme ) )
return;
$name = wp_kses( $theme->name, $themes_allowedtags );
$author = wp_kses( $theme->author, $themes_allowedtags );
$install_url = add_query_arg( array(
'action' => 'install-theme',
'theme' => $theme->slug,
), self_admin_url( 'update.php' ) );
$update_url = add_query_arg( array(
'action' => 'upgrade-theme',
'theme' => $theme->slug,
), self_admin_url( 'update.php' ) );
$status = $this->_get_theme_status( $theme );
?>
<div class="install-theme-info"><?php
switch ( $status ) {
case 'update_available':
echo '<a class="theme-install button-primary" href="' . esc_url( wp_nonce_url( $update_url, 'upgrade-theme_' . $theme->slug ) ) . '" title="' . esc_attr( sprintf( __( 'Update to version %s' ), $theme->version ) ) . '">' . __( 'Update' ) . '</a>';
break;
case 'newer_installed':
case 'latest_installed':
echo '<span class="theme-install" title="' . esc_attr__( 'This theme is already installed and is up to date' ) . '">' . _x( 'Installed', 'theme' ) . '</span>';
break;
case 'install':
default:
echo '<a class="theme-install button-primary" href="' . esc_url( wp_nonce_url( $install_url, 'install-theme_' . $theme->slug ) ) . '">' . __( 'Install' ) . '</a>';
break;
} ?>
<h3 class="theme-name"><?php echo $name; ?></h3>
<span class="theme-by"><?php printf( __( 'By %s' ), $author ); ?></span>
<?php if ( isset( $theme->screenshot_url ) ): ?>
<img class="theme-screenshot" src="<?php echo esc_url( $theme->screenshot_url ); ?>" alt="" />
<?php endif; ?>
<div class="theme-details">
<?php wp_star_rating( array( 'rating' => $theme->rating, 'type' => 'percent', 'number' => $theme->num_ratings ) ); ?>
<div class="theme-version">
<strong><?php _e('Version:') ?> </strong>
<?php echo wp_kses( $theme->version, $themes_allowedtags ); ?>
</div>
<div class="theme-description">
<?php echo wp_kses( $theme->description, $themes_allowedtags ); ?>
</div>
</div>
<input class="theme-preview-url" type="hidden" value="<?php echo esc_url( $theme->preview_url ); ?>" />
</div>
<?php
}
/**
* Send required variables to JavaScript land
*
* @since 3.4.0
* @access public
*
* @global string $tab Current tab within Themes->Install screen
* @global string $type Type of search.
*
* @param array $extra_args Unused.
*/
public function _js_vars( $extra_args = array() ) {
global $tab, $type;
parent::_js_vars( compact( 'tab', 'type' ) );
}
/**
* Check to see if the theme is already installed.
*
* @since 3.4.0
* @access private
*
* @param object $theme - A WordPress.org Theme API object.
* @return string Theme status.
*/
private function _get_theme_status( $theme ) {
$status = 'install';
$installed_theme = wp_get_theme( $theme->slug );
if ( $installed_theme->exists() ) {
if ( version_compare( $installed_theme->get('Version'), $theme->version, '=' ) )
$status = 'latest_installed';
elseif ( version_compare( $installed_theme->get('Version'), $theme->version, '>' ) )
$status = 'newer_installed';
else
$status = 'update_available';
}
return $status;
}
}

View File

@@ -0,0 +1,308 @@
<?php
/**
* List Table API: WP_Themes_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying installed themes in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Themes_List_Table extends WP_List_Table {
protected $search_terms = array();
public $features = array();
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
parent::__construct( array(
'ajax' => true,
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
}
/**
*
* @return bool
*/
public function ajax_user_can() {
// Do not check edit_theme_options here. AJAX calls for available themes require switch_themes.
return current_user_can( 'switch_themes' );
}
/**
* @access public
*/
public function prepare_items() {
$themes = wp_get_themes( array( 'allowed' => true ) );
if ( ! empty( $_REQUEST['s'] ) )
$this->search_terms = array_unique( array_filter( array_map( 'trim', explode( ',', strtolower( wp_unslash( $_REQUEST['s'] ) ) ) ) ) );
if ( ! empty( $_REQUEST['features'] ) )
$this->features = $_REQUEST['features'];
if ( $this->search_terms || $this->features ) {
foreach ( $themes as $key => $theme ) {
if ( ! $this->search_theme( $theme ) )
unset( $themes[ $key ] );
}
}
unset( $themes[ get_option( 'stylesheet' ) ] );
WP_Theme::sort_by_name( $themes );
$per_page = 36;
$page = $this->get_pagenum();
$start = ( $page - 1 ) * $per_page;
$this->items = array_slice( $themes, $start, $per_page, true );
$this->set_pagination_args( array(
'total_items' => count( $themes ),
'per_page' => $per_page,
'infinite_scroll' => true,
) );
}
/**
* @access public
*/
public function no_items() {
if ( $this->search_terms || $this->features ) {
_e( 'No items found.' );
return;
}
if ( is_multisite() ) {
if ( current_user_can( 'install_themes' ) && current_user_can( 'manage_network_themes' ) ) {
printf( __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> or <a href="%2$s">install</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $GLOBALS['blog_id'] ), network_admin_url( 'theme-install.php' ) );
return;
} elseif ( current_user_can( 'manage_network_themes' ) ) {
printf( __( 'You only have one theme enabled for this site right now. Visit the Network Admin to <a href="%1$s">enable</a> more themes.' ), network_admin_url( 'site-themes.php?id=' . $GLOBALS['blog_id'] ) );
return;
}
// Else, fallthrough. install_themes doesn't help if you can't enable it.
} else {
if ( current_user_can( 'install_themes' ) ) {
printf( __( 'You only have one theme installed right now. Live a little! You can choose from over 1,000 free themes in the WordPress.org Theme Directory at any time: just click on the <a href="%s">Install Themes</a> tab above.' ), admin_url( 'theme-install.php' ) );
return;
}
}
// Fallthrough.
printf( __( 'Only the current theme is available to you. Contact the %s administrator for information about accessing additional themes.' ), get_site_option( 'site_name' ) );
}
/**
* @param string $which
*/
public function tablenav( $which = 'top' ) {
if ( $this->get_pagination_arg( 'total_pages' ) <= 1 )
return;
?>
<div class="tablenav themes <?php echo $which; ?>">
<?php $this->pagination( $which ); ?>
<span class="spinner"></span>
<br class="clear" />
</div>
<?php
}
/**
* @access public
*/
public function display() {
wp_nonce_field( "fetch-list-" . get_class( $this ), '_ajax_fetch_list_nonce' );
?>
<?php $this->tablenav( 'top' ); ?>
<div id="availablethemes">
<?php $this->display_rows_or_placeholder(); ?>
</div>
<?php $this->tablenav( 'bottom' ); ?>
<?php
}
/**
*
* @return array
*/
public function get_columns() {
return array();
}
/**
* @access public
*/
public function display_rows_or_placeholder() {
if ( $this->has_items() ) {
$this->display_rows();
} else {
echo '<div class="no-items">';
$this->no_items();
echo '</div>';
}
}
/**
* @access public
*/
public function display_rows() {
$themes = $this->items;
foreach ( $themes as $theme ):
?><div class="available-theme"><?php
$template = $theme->get_template();
$stylesheet = $theme->get_stylesheet();
$title = $theme->display('Name');
$version = $theme->display('Version');
$author = $theme->display('Author');
$activate_link = wp_nonce_url( "themes.php?action=activate&amp;template=" . urlencode( $template ) . "&amp;stylesheet=" . urlencode( $stylesheet ), 'switch-theme_' . $stylesheet );
$actions = array();
$actions['activate'] = '<a href="' . $activate_link . '" class="activatelink" title="'
. esc_attr( sprintf( __( 'Activate &#8220;%s&#8221;' ), $title ) ) . '">' . __( 'Activate' ) . '</a>';
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$actions['preview'] .= '<a href="' . wp_customize_url( $stylesheet ) . '" class="load-customize hide-if-no-customize">'
. __( 'Live Preview' ) . '</a>';
}
if ( ! is_multisite() && current_user_can( 'delete_themes' ) )
$actions['delete'] = '<a class="submitdelete deletion" href="' . wp_nonce_url( 'themes.php?action=delete&amp;stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet )
. '" onclick="' . "return confirm( '" . esc_js( sprintf( __( "You are about to delete this theme '%s'\n 'Cancel' to stop, 'OK' to delete." ), $title ) )
. "' );" . '">' . __( 'Delete' ) . '</a>';
/** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */
$actions = apply_filters( 'theme_action_links', $actions, $theme );
/** This filter is documented in wp-admin/includes/class-wp-ms-themes-list-table.php */
$actions = apply_filters( "theme_action_links_$stylesheet", $actions, $theme );
$delete_action = isset( $actions['delete'] ) ? '<div class="delete-theme">' . $actions['delete'] . '</div>' : '';
unset( $actions['delete'] );
?>
<span class="screenshot hide-if-customize">
<?php if ( $screenshot = $theme->get_screenshot() ) : ?>
<img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
<?php endif; ?>
</span>
<a href="<?php echo wp_customize_url( $stylesheet ); ?>" class="screenshot load-customize hide-if-no-customize">
<?php if ( $screenshot = $theme->get_screenshot() ) : ?>
<img src="<?php echo esc_url( $screenshot ); ?>" alt="" />
<?php endif; ?>
</a>
<h3><?php echo $title; ?></h3>
<div class="theme-author"><?php printf( __( 'By %s' ), $author ); ?></div>
<div class="action-links">
<ul>
<?php foreach ( $actions as $action ): ?>
<li><?php echo $action; ?></li>
<?php endforeach; ?>
<li class="hide-if-no-js"><a href="#" class="theme-detail"><?php _e('Details') ?></a></li>
</ul>
<?php echo $delete_action; ?>
<?php theme_update_available( $theme ); ?>
</div>
<div class="themedetaildiv hide-if-js">
<p><strong><?php _e('Version:'); ?></strong> <?php echo $version; ?></p>
<p><?php echo $theme->display('Description'); ?></p>
<?php if ( $theme->parent() ) {
printf( ' <p class="howto">' . __( 'This <a href="%1$s">child theme</a> requires its parent theme, %2$s.' ) . '</p>',
__( 'https://codex.wordpress.org/Child_Themes' ),
$theme->parent()->display( 'Name' ) );
} ?>
</div>
</div>
<?php
endforeach;
}
/**
* @param WP_Theme $theme
* @return bool
*/
public function search_theme( $theme ) {
// Search the features
foreach ( $this->features as $word ) {
if ( ! in_array( $word, $theme->get('Tags') ) )
return false;
}
// Match all phrases
foreach ( $this->search_terms as $word ) {
if ( in_array( $word, $theme->get('Tags') ) )
continue;
foreach ( array( 'Name', 'Description', 'Author', 'AuthorURI' ) as $header ) {
// Don't mark up; Do translate.
if ( false !== stripos( strip_tags( $theme->display( $header, false, true ) ), $word ) ) {
continue 2;
}
}
if ( false !== stripos( $theme->get_stylesheet(), $word ) )
continue;
if ( false !== stripos( $theme->get_template(), $word ) )
continue;
return false;
}
return true;
}
/**
* Send required variables to JavaScript land
*
* @since 3.4.0
* @access public
*
* @param array $extra_args
*/
public function _js_vars( $extra_args = array() ) {
$search_string = isset( $_REQUEST['s'] ) ? esc_attr( wp_unslash( $_REQUEST['s'] ) ) : '';
$args = array(
'search' => $search_string,
'features' => $this->features,
'paged' => $this->get_pagenum(),
'total_pages' => ! empty( $this->_pagination_args['total_pages'] ) ? $this->_pagination_args['total_pages'] : 1,
);
if ( is_array( $extra_args ) )
$args = array_merge( $args, $extra_args );
printf( "<script type='text/javascript'>var theme_list_args = %s;</script>\n", wp_json_encode( $args ) );
parent::_js_vars();
}
}

View File

@@ -0,0 +1,946 @@
<?php
/**
* The User Interface "Skins" for the WordPress File Upgrader
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
/**
* Generic Skin for the WordPress Upgrader classes. This skin is designed to be extended for specific purposes.
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
class WP_Upgrader_Skin {
public $upgrader;
public $done_header = false;
public $done_footer = false;
public $result = false;
public $options = array();
/**
*
* @param array $args
*/
public function __construct($args = array()) {
$defaults = array( 'url' => '', 'nonce' => '', 'title' => '', 'context' => false );
$this->options = wp_parse_args($args, $defaults);
}
/**
* @param WP_Upgrader $upgrader
*/
public function set_upgrader(&$upgrader) {
if ( is_object($upgrader) )
$this->upgrader =& $upgrader;
$this->add_strings();
}
/**
* @access public
*/
public function add_strings() {
}
/**
*
* @param string|false|WP_Error $result
*/
public function set_result($result) {
$this->result = $result;
}
/**
*
* @param bool $error
* @param string $context
* @param bool $allow_relaxed_file_ownership
* @return type
*/
public function request_filesystem_credentials( $error = false, $context = false, $allow_relaxed_file_ownership = false ) {
$url = $this->options['url'];
if ( ! $context ) {
$context = $this->options['context'];
}
if ( !empty($this->options['nonce']) ) {
$url = wp_nonce_url($url, $this->options['nonce']);
}
$extra_fields = array();
return request_filesystem_credentials( $url, '', $error, $context, $extra_fields, $allow_relaxed_file_ownership );
}
/**
* @access public
*/
public function header() {
if ( $this->done_header ) {
return;
}
$this->done_header = true;
echo '<div class="wrap">';
echo '<h1>' . $this->options['title'] . '</h1>';
}
/**
* @access public
*/
public function footer() {
if ( $this->done_footer ) {
return;
}
$this->done_footer = true;
echo '</div>';
}
/**
*
* @param string|WP_Error $errors
*/
public function error($errors) {
if ( ! $this->done_header )
$this->header();
if ( is_string($errors) ) {
$this->feedback($errors);
} elseif ( is_wp_error($errors) && $errors->get_error_code() ) {
foreach ( $errors->get_error_messages() as $message ) {
if ( $errors->get_error_data() && is_string( $errors->get_error_data() ) )
$this->feedback($message . ' ' . esc_html( strip_tags( $errors->get_error_data() ) ) );
else
$this->feedback($message);
}
}
}
/**
*
* @param string $string
*/
public function feedback($string) {
if ( isset( $this->upgrader->strings[$string] ) )
$string = $this->upgrader->strings[$string];
if ( strpos($string, '%') !== false ) {
$args = func_get_args();
$args = array_splice($args, 1);
if ( $args ) {
$args = array_map( 'strip_tags', $args );
$args = array_map( 'esc_html', $args );
$string = vsprintf($string, $args);
}
}
if ( empty($string) )
return;
show_message($string);
}
/**
* @access public
*/
public function before() {}
/**
* @access public
*/
public function after() {}
/**
* Output JavaScript that calls function to decrement the update counts.
*
* @since 3.9.0
*
* @param string $type Type of update count to decrement. Likely values include 'plugin',
* 'theme', 'translation', etc.
*/
protected function decrement_update_count( $type ) {
if ( ! $this->result || is_wp_error( $this->result ) || 'up_to_date' === $this->result ) {
return;
}
if ( defined( 'IFRAME_REQUEST' ) ) {
echo '<script type="text/javascript">
if ( window.postMessage && JSON ) {
window.parent.postMessage( JSON.stringify( { action: "decrementUpdateCount", upgradeType: "' . $type . '" } ), window.location.protocol + "//" + window.location.hostname );
}
</script>';
} else {
echo '<script type="text/javascript">
(function( wp ) {
if ( wp && wp.updates.decrementCount ) {
wp.updates.decrementCount( "' . $type . '" );
}
})( window.wp );
</script>';
}
}
/**
* @access public
*/
public function bulk_header() {}
/**
* @access public
*/
public function bulk_footer() {}
}
/**
* Plugin Upgrader Skin for WordPress Plugin Upgrades.
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
class Plugin_Upgrader_Skin extends WP_Upgrader_Skin {
public $plugin = '';
public $plugin_active = false;
public $plugin_network_active = false;
/**
*
* @param array $args
*/
public function __construct( $args = array() ) {
$defaults = array( 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => __('Update Plugin') );
$args = wp_parse_args($args, $defaults);
$this->plugin = $args['plugin'];
$this->plugin_active = is_plugin_active( $this->plugin );
$this->plugin_network_active = is_plugin_active_for_network( $this->plugin );
parent::__construct($args);
}
/**
* @access public
*/
public function after() {
$this->plugin = $this->upgrader->plugin_info();
if ( !empty($this->plugin) && !is_wp_error($this->result) && $this->plugin_active ){
// Currently used only when JS is off for a single plugin update?
echo '<iframe title="' . esc_attr__( 'Update progress' ) . '" style="border:0;overflow:hidden" width="100%" height="170" src="' . wp_nonce_url( 'update.php?action=activate-plugin&networkwide=' . $this->plugin_network_active . '&plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin ) . '"></iframe>';
}
$this->decrement_update_count( 'plugin' );
$update_actions = array(
'activate_plugin' => '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $this->plugin ), 'activate-plugin_' . $this->plugin) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>',
'plugins_page' => '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>'
);
if ( $this->plugin_active || ! $this->result || is_wp_error( $this->result ) || ! current_user_can( 'activate_plugins' ) )
unset( $update_actions['activate_plugin'] );
/**
* Filter the list of action links available following a single plugin update.
*
* @since 2.7.0
*
* @param array $update_actions Array of plugin action links.
* @param string $plugin Path to the plugin file.
*/
$update_actions = apply_filters( 'update_plugin_complete_actions', $update_actions, $this->plugin );
if ( ! empty($update_actions) )
$this->feedback(implode(' | ', (array)$update_actions));
}
}
/**
* Plugin Upgrader Skin for WordPress Plugin Upgrades.
*
* @package WordPress
* @subpackage Upgrader
* @since 3.0.0
*/
class Bulk_Upgrader_Skin extends WP_Upgrader_Skin {
public $in_loop = false;
/**
* @var string|false
*/
public $error = false;
/**
*
* @param array $args
*/
public function __construct($args = array()) {
$defaults = array( 'url' => '', 'nonce' => '' );
$args = wp_parse_args($args, $defaults);
parent::__construct($args);
}
/**
* @access public
*/
public function add_strings() {
$this->upgrader->strings['skin_upgrade_start'] = __('The update process is starting. This process may take a while on some hosts, so please be patient.');
/* translators: 1: Title of an update, 2: Error message */
$this->upgrader->strings['skin_update_failed_error'] = __('An error occurred while updating %1$s: %2$s');
/* translators: 1: Title of an update */
$this->upgrader->strings['skin_update_failed'] = __('The update of %1$s failed.');
/* translators: 1: Title of an update */
$this->upgrader->strings['skin_update_successful'] = __( '%1$s updated successfully.' ) . ' <a onclick="%2$s" href="#" class="hide-if-no-js"><span>' . __( 'Show Details' ) . '</span><span class="hidden">' . __( 'Hide Details' ) . '</span></a>';
$this->upgrader->strings['skin_upgrade_end'] = __('All updates have been completed.');
}
/**
* @param string $string
*/
public function feedback($string) {
if ( isset( $this->upgrader->strings[$string] ) )
$string = $this->upgrader->strings[$string];
if ( strpos($string, '%') !== false ) {
$args = func_get_args();
$args = array_splice($args, 1);
if ( $args ) {
$args = array_map( 'strip_tags', $args );
$args = array_map( 'esc_html', $args );
$string = vsprintf($string, $args);
}
}
if ( empty($string) )
return;
if ( $this->in_loop )
echo "$string<br />\n";
else
echo "<p>$string</p>\n";
}
/**
* @access public
*/
public function header() {
// Nothing, This will be displayed within a iframe.
}
/**
* @access public
*/
public function footer() {
// Nothing, This will be displayed within a iframe.
}
/**
*
* @param string|WP_Error $error
*/
public function error($error) {
if ( is_string($error) && isset( $this->upgrader->strings[$error] ) )
$this->error = $this->upgrader->strings[$error];
if ( is_wp_error($error) ) {
$messages = array();
foreach ( $error->get_error_messages() as $emessage ) {
if ( $error->get_error_data() && is_string( $error->get_error_data() ) )
$messages[] = $emessage . ' ' . esc_html( strip_tags( $error->get_error_data() ) );
else
$messages[] = $emessage;
}
$this->error = implode(', ', $messages);
}
echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
}
/**
* @access public
*/
public function bulk_header() {
$this->feedback('skin_upgrade_start');
}
/**
* @access public
*/
public function bulk_footer() {
$this->feedback('skin_upgrade_end');
}
/**
*
* @param string $title
*/
public function before($title = '') {
$this->in_loop = true;
printf( '<h2>' . $this->upgrader->strings['skin_before_update_header'] . ' <span class="spinner waiting-' . $this->upgrader->update_current . '"></span></h2>', $title, $this->upgrader->update_current, $this->upgrader->update_count );
echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').css("display", "inline-block");</script>';
echo '<div class="update-messages hide-if-js" id="progress-' . esc_attr($this->upgrader->update_current) . '"><p>';
$this->flush_output();
}
/**
*
* @param string $title
*/
public function after($title = '') {
echo '</p></div>';
if ( $this->error || ! $this->result ) {
if ( $this->error ) {
echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed_error'], $title, '<strong>' . $this->error . '</strong>' ) . '</p></div>';
} else {
echo '<div class="error"><p>' . sprintf($this->upgrader->strings['skin_update_failed'], $title) . '</p></div>';
}
echo '<script type="text/javascript">jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').show();</script>';
}
if ( $this->result && ! is_wp_error( $this->result ) ) {
if ( ! $this->error )
echo '<div class="updated"><p>' . sprintf($this->upgrader->strings['skin_update_successful'], $title, 'jQuery(\'#progress-' . esc_js($this->upgrader->update_current) . '\').toggle();jQuery(\'span\', this).toggle(); return false;') . '</p></div>';
echo '<script type="text/javascript">jQuery(\'.waiting-' . esc_js($this->upgrader->update_current) . '\').hide();</script>';
}
$this->reset();
$this->flush_output();
}
/**
* @access public
*/
public function reset() {
$this->in_loop = false;
$this->error = false;
}
/**
* @access public
*/
public function flush_output() {
wp_ob_end_flush_all();
flush();
}
}
class Bulk_Plugin_Upgrader_Skin extends Bulk_Upgrader_Skin {
public $plugin_info = array(); // Plugin_Upgrader::bulk() will fill this in.
public function add_strings() {
parent::add_strings();
$this->upgrader->strings['skin_before_update_header'] = __('Updating Plugin %1$s (%2$d/%3$d)');
}
/**
*
* @param string $title
*/
public function before($title = '') {
parent::before($this->plugin_info['Title']);
}
/**
*
* @param string $title
*/
public function after($title = '') {
parent::after($this->plugin_info['Title']);
$this->decrement_update_count( 'plugin' );
}
/**
* @access public
*/
public function bulk_footer() {
parent::bulk_footer();
$update_actions = array(
'plugins_page' => '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>',
'updates_page' => '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>'
);
if ( ! current_user_can( 'activate_plugins' ) )
unset( $update_actions['plugins_page'] );
/**
* Filter the list of action links available following bulk plugin updates.
*
* @since 3.0.0
*
* @param array $update_actions Array of plugin action links.
* @param array $plugin_info Array of information for the last-updated plugin.
*/
$update_actions = apply_filters( 'update_bulk_plugins_complete_actions', $update_actions, $this->plugin_info );
if ( ! empty($update_actions) )
$this->feedback(implode(' | ', (array)$update_actions));
}
}
class Bulk_Theme_Upgrader_Skin extends Bulk_Upgrader_Skin {
public $theme_info = array(); // Theme_Upgrader::bulk() will fill this in.
public function add_strings() {
parent::add_strings();
$this->upgrader->strings['skin_before_update_header'] = __('Updating Theme %1$s (%2$d/%3$d)');
}
/**
*
* @param string $title
*/
public function before($title = '') {
parent::before( $this->theme_info->display('Name') );
}
/**
*
* @param string $title
*/
public function after($title = '') {
parent::after( $this->theme_info->display('Name') );
$this->decrement_update_count( 'theme' );
}
/**
* @access public
*/
public function bulk_footer() {
parent::bulk_footer();
$update_actions = array(
'themes_page' => '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>',
'updates_page' => '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>'
);
if ( ! current_user_can( 'switch_themes' ) && ! current_user_can( 'edit_theme_options' ) )
unset( $update_actions['themes_page'] );
/**
* Filter the list of action links available following bulk theme updates.
*
* @since 3.0.0
*
* @param array $update_actions Array of theme action links.
* @param array $theme_info Array of information for the last-updated theme.
*/
$update_actions = apply_filters( 'update_bulk_theme_complete_actions', $update_actions, $this->theme_info );
if ( ! empty($update_actions) )
$this->feedback(implode(' | ', (array)$update_actions));
}
}
/**
* Plugin Installer Skin for WordPress Plugin Installer.
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
class Plugin_Installer_Skin extends WP_Upgrader_Skin {
public $api;
public $type;
/**
*
* @param array $args
*/
public function __construct($args = array()) {
$defaults = array( 'type' => 'web', 'url' => '', 'plugin' => '', 'nonce' => '', 'title' => '' );
$args = wp_parse_args($args, $defaults);
$this->type = $args['type'];
$this->api = isset($args['api']) ? $args['api'] : array();
parent::__construct($args);
}
/**
* @access public
*/
public function before() {
if ( !empty($this->api) )
$this->upgrader->strings['process_success'] = sprintf( __('Successfully installed the plugin <strong>%s %s</strong>.'), $this->api->name, $this->api->version);
}
/**
* @access public
*/
public function after() {
$plugin_file = $this->upgrader->plugin_info();
$install_actions = array();
$from = isset($_GET['from']) ? wp_unslash( $_GET['from'] ) : 'plugins';
if ( 'import' == $from )
$install_actions['activate_plugin'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;from=import&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin &amp; Run Importer' ) . '</a>';
else
$install_actions['activate_plugin'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Activate Plugin' ) . '</a>';
if ( is_multisite() && current_user_can( 'manage_network_plugins' ) ) {
$install_actions['network_activate'] = '<a href="' . wp_nonce_url( 'plugins.php?action=activate&amp;networkwide=1&amp;plugin=' . urlencode( $plugin_file ), 'activate-plugin_' . $plugin_file ) . '" target="_parent">' . __( 'Network Activate' ) . '</a>';
unset( $install_actions['activate_plugin'] );
}
if ( 'import' == $from ) {
$install_actions['importers_page'] = '<a href="' . admin_url( 'import.php' ) . '" target="_parent">' . __( 'Return to Importers' ) . '</a>';
} elseif ( $this->type == 'web' ) {
$install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugin-install.php' ) . '" target="_parent">' . __( 'Return to Plugin Installer' ) . '</a>';
} else {
$install_actions['plugins_page'] = '<a href="' . self_admin_url( 'plugins.php' ) . '" target="_parent">' . __( 'Return to Plugins page' ) . '</a>';
}
if ( ! $this->result || is_wp_error($this->result) ) {
unset( $install_actions['activate_plugin'], $install_actions['network_activate'] );
} elseif ( ! current_user_can( 'activate_plugins' ) ) {
unset( $install_actions['activate_plugin'] );
}
/**
* Filter the list of action links available following a single plugin installation.
*
* @since 2.7.0
*
* @param array $install_actions Array of plugin action links.
* @param object $api Object containing WordPress.org API plugin data. Empty
* for non-API installs, such as when a plugin is installed
* via upload.
* @param string $plugin_file Path to the plugin file.
*/
$install_actions = apply_filters( 'install_plugin_complete_actions', $install_actions, $this->api, $plugin_file );
if ( ! empty($install_actions) )
$this->feedback(implode(' | ', (array)$install_actions));
}
}
/**
* Theme Installer Skin for the WordPress Theme Installer.
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
class Theme_Installer_Skin extends WP_Upgrader_Skin {
public $api;
public $type;
/**
*
* @param array $args
*/
public function __construct($args = array()) {
$defaults = array( 'type' => 'web', 'url' => '', 'theme' => '', 'nonce' => '', 'title' => '' );
$args = wp_parse_args($args, $defaults);
$this->type = $args['type'];
$this->api = isset($args['api']) ? $args['api'] : array();
parent::__construct($args);
}
/**
* @access public
*/
public function before() {
if ( !empty($this->api) )
$this->upgrader->strings['process_success'] = sprintf( $this->upgrader->strings['process_success_specific'], $this->api->name, $this->api->version);
}
/**
* @access public
*/
public function after() {
if ( empty($this->upgrader->result['destination_name']) )
return;
$theme_info = $this->upgrader->theme_info();
if ( empty( $theme_info ) )
return;
$name = $theme_info->display('Name');
$stylesheet = $this->upgrader->result['destination_name'];
$template = $theme_info->get_template();
$activate_link = add_query_arg( array(
'action' => 'activate',
'template' => urlencode( $template ),
'stylesheet' => urlencode( $stylesheet ),
), admin_url('themes.php') );
$activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
$install_actions = array();
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$install_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
}
$install_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
if ( is_network_admin() && current_user_can( 'manage_network_themes' ) )
$install_actions['network_enable'] = '<a href="' . esc_url( wp_nonce_url( 'themes.php?action=enable&amp;theme=' . urlencode( $stylesheet ), 'enable-theme_' . $stylesheet ) ) . '" target="_parent">' . __( 'Network Enable' ) . '</a>';
if ( $this->type == 'web' )
$install_actions['themes_page'] = '<a href="' . self_admin_url( 'theme-install.php' ) . '" target="_parent">' . __( 'Return to Theme Installer' ) . '</a>';
elseif ( current_user_can( 'switch_themes' ) || current_user_can( 'edit_theme_options' ) )
$install_actions['themes_page'] = '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>';
if ( ! $this->result || is_wp_error($this->result) || is_network_admin() || ! current_user_can( 'switch_themes' ) )
unset( $install_actions['activate'], $install_actions['preview'] );
/**
* Filter the list of action links available following a single theme installation.
*
* @since 2.8.0
*
* @param array $install_actions Array of theme action links.
* @param object $api Object containing WordPress.org API theme data.
* @param string $stylesheet Theme directory name.
* @param WP_Theme $theme_info Theme object.
*/
$install_actions = apply_filters( 'install_theme_complete_actions', $install_actions, $this->api, $stylesheet, $theme_info );
if ( ! empty($install_actions) )
$this->feedback(implode(' | ', (array)$install_actions));
}
}
/**
* Theme Upgrader Skin for WordPress Theme Upgrades.
*
* @package WordPress
* @subpackage Upgrader
* @since 2.8.0
*/
class Theme_Upgrader_Skin extends WP_Upgrader_Skin {
public $theme = '';
/**
*
* @param array $args
*/
public function __construct($args = array()) {
$defaults = array( 'url' => '', 'theme' => '', 'nonce' => '', 'title' => __('Update Theme') );
$args = wp_parse_args($args, $defaults);
$this->theme = $args['theme'];
parent::__construct($args);
}
/**
* @access public
*/
public function after() {
$this->decrement_update_count( 'theme' );
$update_actions = array();
if ( ! empty( $this->upgrader->result['destination_name'] ) && $theme_info = $this->upgrader->theme_info() ) {
$name = $theme_info->display('Name');
$stylesheet = $this->upgrader->result['destination_name'];
$template = $theme_info->get_template();
$activate_link = add_query_arg( array(
'action' => 'activate',
'template' => urlencode( $template ),
'stylesheet' => urlencode( $stylesheet ),
), admin_url('themes.php') );
$activate_link = wp_nonce_url( $activate_link, 'switch-theme_' . $stylesheet );
if ( get_stylesheet() == $stylesheet ) {
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$update_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Customize' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Customize &#8220;%s&#8221;' ), $name ) . '</span></a>';
}
} elseif ( current_user_can( 'switch_themes' ) ) {
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$update_actions['preview'] = '<a href="' . wp_customize_url( $stylesheet ) . '" class="hide-if-no-customize load-customize"><span aria-hidden="true">' . __( 'Live Preview' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Live Preview &#8220;%s&#8221;' ), $name ) . '</span></a>';
}
$update_actions['activate'] = '<a href="' . esc_url( $activate_link ) . '" class="activatelink"><span aria-hidden="true">' . __( 'Activate' ) . '</span><span class="screen-reader-text">' . sprintf( __( 'Activate &#8220;%s&#8221;' ), $name ) . '</span></a>';
}
if ( ! $this->result || is_wp_error( $this->result ) || is_network_admin() )
unset( $update_actions['preview'], $update_actions['activate'] );
}
$update_actions['themes_page'] = '<a href="' . self_admin_url( 'themes.php' ) . '" target="_parent">' . __( 'Return to Themes page' ) . '</a>';
/**
* Filter the list of action links available following a single theme update.
*
* @since 2.8.0
*
* @param array $update_actions Array of theme action links.
* @param string $theme Theme directory name.
*/
$update_actions = apply_filters( 'update_theme_complete_actions', $update_actions, $this->theme );
if ( ! empty($update_actions) )
$this->feedback(implode(' | ', (array)$update_actions));
}
}
/**
* Translation Upgrader Skin for WordPress Translation Upgrades.
*
* @package WordPress
* @subpackage Upgrader
* @since 3.7.0
*/
class Language_Pack_Upgrader_Skin extends WP_Upgrader_Skin {
public $language_update = null;
public $done_header = false;
public $done_footer = false;
public $display_footer_actions = true;
/**
*
* @param array $args
*/
public function __construct( $args = array() ) {
$defaults = array( 'url' => '', 'nonce' => '', 'title' => __( 'Update Translations' ), 'skip_header_footer' => false );
$args = wp_parse_args( $args, $defaults );
if ( $args['skip_header_footer'] ) {
$this->done_header = true;
$this->done_footer = true;
$this->display_footer_actions = false;
}
parent::__construct( $args );
}
/**
* @access public
*/
public function before() {
$name = $this->upgrader->get_name_for_update( $this->language_update );
echo '<div class="update-messages lp-show-latest">';
printf( '<h2>' . __( 'Updating translations for %1$s (%2$s)&#8230;' ) . '</h2>', $name, $this->language_update->language );
}
/**
*
* @param string|WP_Error $error
*/
public function error( $error ) {
echo '<div class="lp-error">';
parent::error( $error );
echo '</div>';
}
/**
* @access public
*/
public function after() {
echo '</div>';
}
/**
* @access public
*/
public function bulk_footer() {
$this->decrement_update_count( 'translation' );
$update_actions = array();
$update_actions['updates_page'] = '<a href="' . self_admin_url( 'update-core.php' ) . '" target="_parent">' . __( 'Return to WordPress Updates page' ) . '</a>';
/**
* Filter the list of action links available following a translations update.
*
* @since 3.7.0
*
* @param array $update_actions Array of translations update links.
*/
$update_actions = apply_filters( 'update_translations_complete_actions', $update_actions );
if ( $update_actions && $this->display_footer_actions )
$this->feedback( implode( ' | ', $update_actions ) );
}
}
/**
* Upgrader Skin for Automatic WordPress Upgrades
*
* This skin is designed to be used when no output is intended, all output
* is captured and stored for the caller to process and log/email/discard.
*
* @package WordPress
* @subpackage Upgrader
* @since 3.7.0
*/
class Automatic_Upgrader_Skin extends WP_Upgrader_Skin {
protected $messages = array();
/**
*
* @param bool $error
* @param string $context
* @param bool $allow_relaxed_file_ownership
* @return bool
*/
public function request_filesystem_credentials( $error = false, $context = '', $allow_relaxed_file_ownership = false ) {
if ( $context ) {
$this->options['context'] = $context;
}
// TODO: fix up request_filesystem_credentials(), or split it, to allow us to request a no-output version
// This will output a credentials form in event of failure, We don't want that, so just hide with a buffer
ob_start();
$result = parent::request_filesystem_credentials( $error, $context, $allow_relaxed_file_ownership );
ob_end_clean();
return $result;
}
/**
* @access public
*
* @return array
*/
public function get_upgrade_messages() {
return $this->messages;
}
/**
* @param string|array|WP_Error $data
*/
public function feedback( $data ) {
if ( is_wp_error( $data ) ) {
$string = $data->get_error_message();
} elseif ( is_array( $data ) ) {
return;
} else {
$string = $data;
}
if ( ! empty( $this->upgrader->strings[ $string ] ) )
$string = $this->upgrader->strings[ $string ];
if ( strpos( $string, '%' ) !== false ) {
$args = func_get_args();
$args = array_splice( $args, 1 );
if ( ! empty( $args ) )
$string = vsprintf( $string, $args );
}
$string = trim( $string );
// Only allow basic HTML in the messages, as it'll be used in emails/logs rather than direct browser output.
$string = wp_kses( $string, array(
'a' => array(
'href' => true
),
'br' => true,
'em' => true,
'strong' => true,
) );
if ( empty( $string ) )
return;
$this->messages[] = $string;
}
/**
* @access public
*/
public function header() {
ob_start();
}
/**
* @access public
*/
public function footer() {
$output = ob_get_clean();
if ( ! empty( $output ) )
$this->feedback( $output );
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,560 @@
<?php
/**
* List Table API: WP_Users_List_Table class
*
* @package WordPress
* @subpackage Administration
* @since 3.1.0
*/
/**
* Core class used to implement displaying users in a list table.
*
* @since 3.1.0
* @access private
*
* @see WP_List_Table
*/
class WP_Users_List_Table extends WP_List_Table {
/**
* Site ID to generate the Users list table for.
*
* @since 3.1.0
* @access public
* @var int
*/
public $site_id;
/**
* Whether or not the current Users list table is for Multisite.
*
* @since 3.1.0
* @access public
* @var bool
*/
public $is_site_users;
/**
* Constructor.
*
* @since 3.1.0
* @access public
*
* @see WP_List_Table::__construct() for more information on default arguments.
*
* @param array $args An associative array of arguments.
*/
public function __construct( $args = array() ) {
parent::__construct( array(
'singular' => 'user',
'plural' => 'users',
'screen' => isset( $args['screen'] ) ? $args['screen'] : null,
) );
$this->is_site_users = 'site-users-network' === $this->screen->id;
if ( $this->is_site_users )
$this->site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
}
/**
* Check the current user's permissions.
*
* @since 3.1.0
* @access public
*
* @return bool
*/
public function ajax_user_can() {
if ( $this->is_site_users )
return current_user_can( 'manage_sites' );
else
return current_user_can( 'list_users' );
}
/**
* Prepare the users list for display.
*
* @since 3.1.0
* @access public
*
* @global string $role
* @global string $usersearch
*/
public function prepare_items() {
global $role, $usersearch;
$usersearch = isset( $_REQUEST['s'] ) ? wp_unslash( trim( $_REQUEST['s'] ) ) : '';
$role = isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : '';
$per_page = ( $this->is_site_users ) ? 'site_users_network_per_page' : 'users_per_page';
$users_per_page = $this->get_items_per_page( $per_page );
$paged = $this->get_pagenum();
if ( 'none' === $role ) {
$args = array(
'number' => $users_per_page,
'offset' => ( $paged-1 ) * $users_per_page,
'include' => wp_get_users_with_no_role(),
'search' => $usersearch,
'fields' => 'all_with_meta'
);
} else {
$args = array(
'number' => $users_per_page,
'offset' => ( $paged-1 ) * $users_per_page,
'role' => $role,
'search' => $usersearch,
'fields' => 'all_with_meta'
);
}
if ( '' !== $args['search'] )
$args['search'] = '*' . $args['search'] . '*';
if ( $this->is_site_users )
$args['blog_id'] = $this->site_id;
if ( isset( $_REQUEST['orderby'] ) )
$args['orderby'] = $_REQUEST['orderby'];
if ( isset( $_REQUEST['order'] ) )
$args['order'] = $_REQUEST['order'];
/**
* Filter the query arguments used to retrieve users for the current users list table.
*
* @since 4.4.0
*
* @param array $args Arguments passed to WP_User_Query to retrieve items for the current
* users list table.
*/
$args = apply_filters( 'users_list_table_query_args', $args );
// Query the user IDs for this page
$wp_user_search = new WP_User_Query( $args );
$this->items = $wp_user_search->get_results();
$this->set_pagination_args( array(
'total_items' => $wp_user_search->get_total(),
'per_page' => $users_per_page,
) );
}
/**
* Output 'no users' message.
*
* @since 3.1.0
* @access public
*/
public function no_items() {
_e( 'No users found.' );
}
/**
* Return an associative array listing all the views that can be used
* with this table.
*
* Provides a list of roles and user count for that role for easy
* filtering of the user table.
*
* @since 3.1.0
* @access protected
*
* @global string $role
*
* @return array An array of HTML links, one for each view.
*/
protected function get_views() {
global $role;
$wp_roles = wp_roles();
if ( $this->is_site_users ) {
$url = 'site-users.php?id=' . $this->site_id;
switch_to_blog( $this->site_id );
$users_of_blog = count_users();
restore_current_blog();
} else {
$url = 'users.php';
$users_of_blog = count_users();
}
$total_users = $users_of_blog['total_users'];
$avail_roles =& $users_of_blog['avail_roles'];
unset($users_of_blog);
$class = empty($role) ? ' class="current"' : '';
$role_links = array();
$role_links['all'] = "<a href='$url'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_users, 'users' ), number_format_i18n( $total_users ) ) . '</a>';
foreach ( $wp_roles->get_names() as $this_role => $name ) {
if ( !isset($avail_roles[$this_role]) )
continue;
$class = '';
if ( $this_role === $role ) {
$class = ' class="current"';
}
$name = translate_user_role( $name );
/* translators: User role name with count */
$name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles[$this_role] ) );
$role_links[$this_role] = "<a href='" . esc_url( add_query_arg( 'role', $this_role, $url ) ) . "'$class>$name</a>";
}
if ( ! empty( $avail_roles['none' ] ) ) {
$class = '';
if ( 'none' === $role ) {
$class = ' class="current"';
}
$name = __( 'No role' );
/* translators: User role name with count */
$name = sprintf( __('%1$s <span class="count">(%2$s)</span>'), $name, number_format_i18n( $avail_roles['none' ] ) );
$role_links['none'] = "<a href='" . esc_url( add_query_arg( 'role', 'none', $url ) ) . "'$class>$name</a>";
}
return $role_links;
}
/**
* Retrieve an associative array of bulk actions available on this table.
*
* @since 3.1.0
* @access protected
*
* @return array Array of bulk actions.
*/
protected function get_bulk_actions() {
$actions = array();
if ( is_multisite() ) {
if ( current_user_can( 'remove_users' ) )
$actions['remove'] = __( 'Remove' );
} else {
if ( current_user_can( 'delete_users' ) )
$actions['delete'] = __( 'Delete' );
}
return $actions;
}
/**
* Output the controls to allow user roles to be changed in bulk.
*
* @since 3.1.0
* @access protected
*
* @param string $which Whether this is being invoked above ("top")
* or below the table ("bottom").
*/
protected function extra_tablenav( $which ) {
$id = 'bottom' === $which ? 'new_role2' : 'new_role';
?>
<div class="alignleft actions">
<?php if ( current_user_can( 'promote_users' ) && $this->has_items() ) : ?>
<label class="screen-reader-text" for="<?php echo $id ?>"><?php _e( 'Change role to&hellip;' ) ?></label>
<select name="<?php echo $id ?>" id="<?php echo $id ?>">
<option value=""><?php _e( 'Change role to&hellip;' ) ?></option>
<?php wp_dropdown_roles(); ?>
</select>
<?php
submit_button( __( 'Change' ), 'button', 'changeit', false );
endif;
/**
* Fires just before the closing div containing the bulk role-change controls
* in the Users list table.
*
* @since 3.5.0
*/
do_action( 'restrict_manage_users' );
echo '</div>';
}
/**
* Capture the bulk action required, and return it.
*
* Overridden from the base class implementation to capture
* the role change drop-down.
*
* @since 3.1.0
* @access public
*
* @return string The bulk action required.
*/
public function current_action() {
if ( isset( $_REQUEST['changeit'] ) &&
( ! empty( $_REQUEST['new_role'] ) || ! empty( $_REQUEST['new_role2'] ) ) ) {
return 'promote';
}
return parent::current_action();
}
/**
* Get a list of columns for the list table.
*
* @since 3.1.0
* @access public
*
* @return array Array in which the key is the ID of the column,
* and the value is the description.
*/
public function get_columns() {
$c = array(
'cb' => '<input type="checkbox" />',
'username' => __( 'Username' ),
'name' => __( 'Name' ),
'email' => __( 'Email' ),
'role' => __( 'Role' ),
'posts' => __( 'Posts' )
);
if ( $this->is_site_users )
unset( $c['posts'] );
return $c;
}
/**
* Get a list of sortable columns for the list table.
*
* @since 3.1.0
* @access protected
*
* @return array Array of sortable columns.
*/
protected function get_sortable_columns() {
$c = array(
'username' => 'login',
'name' => 'name',
'email' => 'email',
);
return $c;
}
/**
* Generate the list table rows.
*
* @since 3.1.0
* @access public
*/
public function display_rows() {
// Query the post counts for this page
if ( ! $this->is_site_users )
$post_counts = count_many_users_posts( array_keys( $this->items ) );
foreach ( $this->items as $userid => $user_object ) {
if ( is_multisite() && empty( $user_object->allcaps ) )
continue;
echo "\n\t" . $this->single_row( $user_object, '', '', isset( $post_counts ) ? $post_counts[ $userid ] : 0 );
}
}
/**
* Generate HTML for a single row on the users.php admin panel.
*
* @since 3.1.0
* @since 4.2.0 The `$style` parameter was deprecated.
* @since 4.4.0 The `$role` parameter was deprecated.
* @access public
*
* @param object $user_object The current user object.
* @param string $style Deprecated. Not used.
* @param string $role Deprecated. Not used.
* @param int $numposts Optional. Post count to display for this user. Defaults
* to zero, as in, a new user has made zero posts.
* @return string Output for a single row.
*/
public function single_row( $user_object, $style = '', $role = '', $numposts = 0 ) {
if ( ! ( $user_object instanceof WP_User ) ) {
$user_object = get_userdata( (int) $user_object );
}
$user_object->filter = 'display';
$email = $user_object->user_email;
if ( $this->is_site_users )
$url = "site-users.php?id={$this->site_id}&amp;";
else
$url = 'users.php?';
$user_roles = $this->get_role_list( $user_object );
// Set up the hover actions for this user
$actions = array();
$checkbox = '';
// Check if the user for this row is editable
if ( current_user_can( 'list_users' ) ) {
// Set up the user editing link
$edit_link = esc_url( add_query_arg( 'wp_http_referer', urlencode( wp_unslash( $_SERVER['REQUEST_URI'] ) ), get_edit_user_link( $user_object->ID ) ) );
if ( current_user_can( 'edit_user', $user_object->ID ) ) {
$edit = "<strong><a href=\"$edit_link\">$user_object->user_login</a></strong><br />";
$actions['edit'] = '<a href="' . $edit_link . '">' . __( 'Edit' ) . '</a>';
} else {
$edit = "<strong>$user_object->user_login</strong><br />";
}
if ( !is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'delete_user', $user_object->ID ) )
$actions['delete'] = "<a class='submitdelete' href='" . wp_nonce_url( "users.php?action=delete&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Delete' ) . "</a>";
if ( is_multisite() && get_current_user_id() != $user_object->ID && current_user_can( 'remove_user', $user_object->ID ) )
$actions['remove'] = "<a class='submitdelete' href='" . wp_nonce_url( $url."action=remove&amp;user=$user_object->ID", 'bulk-users' ) . "'>" . __( 'Remove' ) . "</a>";
/**
* Filter the action links displayed under each user in the Users list table.
*
* @since 2.8.0
*
* @param array $actions An array of action links to be displayed.
* Default 'Edit', 'Delete' for single site, and
* 'Edit', 'Remove' for Multisite.
* @param WP_User $user_object WP_User object for the currently-listed user.
*/
$actions = apply_filters( 'user_row_actions', $actions, $user_object );
// Role classes.
$role_classes = esc_attr( implode( ' ', array_keys( $user_roles ) ) );
// Set up the checkbox ( because the user is editable, otherwise it's empty )
$checkbox = '<label class="screen-reader-text" for="user_' . $user_object->ID . '">' . sprintf( __( 'Select %s' ), $user_object->user_login ) . '</label>'
. "<input type='checkbox' name='users[]' id='user_{$user_object->ID}' class='{$role_classes}' value='{$user_object->ID}' />";
} else {
$edit = '<strong>' . $user_object->user_login . '</strong>';
}
$avatar = get_avatar( $user_object->ID, 32 );
// Comma-separated list of user roles.
$roles_list = implode( ', ', $user_roles );
$r = "<tr id='user-$user_object->ID'>";
list( $columns, $hidden, $sortable, $primary ) = $this->get_column_info();
foreach ( $columns as $column_name => $column_display_name ) {
$classes = "$column_name column-$column_name";
if ( $primary === $column_name ) {
$classes .= ' has-row-actions column-primary';
}
if ( 'posts' === $column_name ) {
$classes .= ' num'; // Special case for that column
}
if ( in_array( $column_name, $hidden ) ) {
$classes .= ' hidden';
}
$data = 'data-colname="' . wp_strip_all_tags( $column_display_name ) . '"';
$attributes = "class='$classes' $data";
if ( 'cb' === $column_name ) {
$r .= "<th scope='row' class='check-column'>$checkbox</th>";
} else {
$r .= "<td $attributes>";
switch ( $column_name ) {
case 'username':
$r .= "$avatar $edit";
break;
case 'name':
$r .= "$user_object->first_name $user_object->last_name";
break;
case 'email':
$r .= "<a href='" . esc_url( "mailto:$email" ) . "'>$email</a>";
break;
case 'role':
$r .= esc_html( $roles_list );
break;
case 'posts':
if ( $numposts > 0 ) {
$r .= "<a href='edit.php?author=$user_object->ID' class='edit'>";
$r .= '<span aria-hidden="true">' . $numposts . '</span>';
$r .= '<span class="screen-reader-text">' . sprintf( _n( '%s post by this author', '%s posts by this author', $numposts ), number_format_i18n( $numposts ) ) . '</span>';
$r .= '</a>';
} else {
$r .= 0;
}
break;
default:
/**
* Filter the display output of custom columns in the Users list table.
*
* @since 2.8.0
*
* @param string $output Custom column output. Default empty.
* @param string $column_name Column name.
* @param int $user_id ID of the currently-listed user.
*/
$r .= apply_filters( 'manage_users_custom_column', '', $column_name, $user_object->ID );
}
if ( $primary === $column_name ) {
$r .= $this->row_actions( $actions );
}
$r .= "</td>";
}
}
$r .= '</tr>';
return $r;
}
/**
* Gets the name of the default primary column.
*
* @since 4.3.0
* @access protected
*
* @return string Name of the default primary column, in this case, 'username'.
*/
protected function get_default_primary_column_name() {
return 'username';
}
/**
* Returns an array of user roles for a given user object.
*
* @since 4.4.0
* @access protected
*
* @param WP_User $user_object The WP_User object.
* @return array An array of user roles.
*/
protected function get_role_list( $user_object ) {
$wp_roles = wp_roles();
$role_list = array();
foreach ( $user_object->roles as $role ) {
if ( isset( $wp_roles->role_names[ $role ] ) ) {
$role_list[ $role ] = translate_user_role( $wp_roles->role_names[ $role ] );
}
}
if ( empty( $role_list ) ) {
$role_list['none'] = _x( 'None', 'no user roles' );
}
/**
* Filter the returned array of roles for a user.
*
* @since 4.4.0
*
* @param array $role_list An array of user roles.
* @param WP_User $user_object A WP_User object.
*/
return apply_filters( 'get_role_list', $role_list, $user_object );
}
}

View File

@@ -0,0 +1,196 @@
<?php
/**
* WordPress Comment Administration API.
*
* @package WordPress
* @subpackage Administration
* @since 2.3.0
*/
/**
* Determine if a comment exists based on author and date.
*
* For best performance, use `$timezone = 'gmt'`, which queries a field that is properly indexed. The default value
* for `$timezone` is 'blog' for legacy reasons.
*
* @since 2.0.0
* @since 4.4.0 Added the `$timezone` parameter.
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param string $comment_author Author of the comment.
* @param string $comment_date Date of the comment.
* @param string $timezone Timezone. Accepts 'blog' or 'gmt'. Default 'blog'.
*
* @return mixed Comment post ID on success.
*/
function comment_exists( $comment_author, $comment_date, $timezone = 'blog' ) {
global $wpdb;
$date_field = 'comment_date';
if ( 'gmt' === $timezone ) {
$date_field = 'comment_date_gmt';
}
return $wpdb->get_var( $wpdb->prepare("SELECT comment_post_ID FROM $wpdb->comments
WHERE comment_author = %s AND $date_field = %s",
stripslashes( $comment_author ),
stripslashes( $comment_date )
) );
}
/**
* Update a comment with values provided in $_POST.
*
* @since 2.0.0
*/
function edit_comment() {
if ( ! current_user_can( 'edit_comment', (int) $_POST['comment_ID'] ) )
wp_die ( __( 'You are not allowed to edit comments on this post.' ) );
if ( isset( $_POST['newcomment_author'] ) )
$_POST['comment_author'] = $_POST['newcomment_author'];
if ( isset( $_POST['newcomment_author_email'] ) )
$_POST['comment_author_email'] = $_POST['newcomment_author_email'];
if ( isset( $_POST['newcomment_author_url'] ) )
$_POST['comment_author_url'] = $_POST['newcomment_author_url'];
if ( isset( $_POST['comment_status'] ) )
$_POST['comment_approved'] = $_POST['comment_status'];
if ( isset( $_POST['content'] ) )
$_POST['comment_content'] = $_POST['content'];
if ( isset( $_POST['comment_ID'] ) )
$_POST['comment_ID'] = (int) $_POST['comment_ID'];
foreach ( array ('aa', 'mm', 'jj', 'hh', 'mn') as $timeunit ) {
if ( !empty( $_POST['hidden_' . $timeunit] ) && $_POST['hidden_' . $timeunit] != $_POST[$timeunit] ) {
$_POST['edit_date'] = '1';
break;
}
}
if ( !empty ( $_POST['edit_date'] ) ) {
$aa = $_POST['aa'];
$mm = $_POST['mm'];
$jj = $_POST['jj'];
$hh = $_POST['hh'];
$mn = $_POST['mn'];
$ss = $_POST['ss'];
$jj = ($jj > 31 ) ? 31 : $jj;
$hh = ($hh > 23 ) ? $hh -24 : $hh;
$mn = ($mn > 59 ) ? $mn -60 : $mn;
$ss = ($ss > 59 ) ? $ss -60 : $ss;
$_POST['comment_date'] = "$aa-$mm-$jj $hh:$mn:$ss";
}
wp_update_comment( $_POST );
}
/**
* Returns a WP_Comment object based on comment ID.
*
* @since 2.0.0
*
* @param int $id ID of comment to retrieve.
* @return WP_Comment|false Comment if found. False on failure.
*/
function get_comment_to_edit( $id ) {
if ( !$comment = get_comment($id) )
return false;
$comment->comment_ID = (int) $comment->comment_ID;
$comment->comment_post_ID = (int) $comment->comment_post_ID;
$comment->comment_content = format_to_edit( $comment->comment_content );
/**
* Filter the comment content before editing.
*
* @since 2.0.0
*
* @param string $comment->comment_content Comment content.
*/
$comment->comment_content = apply_filters( 'comment_edit_pre', $comment->comment_content );
$comment->comment_author = format_to_edit( $comment->comment_author );
$comment->comment_author_email = format_to_edit( $comment->comment_author_email );
$comment->comment_author_url = format_to_edit( $comment->comment_author_url );
$comment->comment_author_url = esc_url($comment->comment_author_url);
return $comment;
}
/**
* Get the number of pending comments on a post or posts
*
* @since 2.3.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int|array $post_id Either a single Post ID or an array of Post IDs
* @return int|array Either a single Posts pending comments as an int or an array of ints keyed on the Post IDs
*/
function get_pending_comments_num( $post_id ) {
global $wpdb;
$single = false;
if ( !is_array($post_id) ) {
$post_id_array = (array) $post_id;
$single = true;
} else {
$post_id_array = $post_id;
}
$post_id_array = array_map('intval', $post_id_array);
$post_id_in = "'" . implode("', '", $post_id_array) . "'";
$pending = $wpdb->get_results( "SELECT comment_post_ID, COUNT(comment_ID) as num_comments FROM $wpdb->comments WHERE comment_post_ID IN ( $post_id_in ) AND comment_approved = '0' GROUP BY comment_post_ID", ARRAY_A );
if ( $single ) {
if ( empty($pending) )
return 0;
else
return absint($pending[0]['num_comments']);
}
$pending_keyed = array();
// Default to zero pending for all posts in request
foreach ( $post_id_array as $id )
$pending_keyed[$id] = 0;
if ( !empty($pending) )
foreach ( $pending as $pend )
$pending_keyed[$pend['comment_post_ID']] = absint($pend['num_comments']);
return $pending_keyed;
}
/**
* Add avatars to relevant places in admin, or try to.
*
* @since 2.5.0
*
* @param string $name User name.
* @return string Avatar with Admin name.
*/
function floated_admin_avatar( $name ) {
$avatar = get_avatar( get_comment(), 32, 'mystery' );
return "$avatar $name";
}
/**
* @since 2.7.0
*/
function enqueue_comment_hotkeys_js() {
if ( 'true' == get_user_option( 'comment_shortcuts' ) )
wp_enqueue_script( 'jquery-table-hotkeys' );
}
/**
* Display error message at bottom of comments.
*
* @param string $msg Error Message. Assumed to contain HTML and be sanitized.
*/
function comment_footer_die( $msg ) {
echo "<div class='wrap'><p>$msg</p></div>";
include( ABSPATH . 'wp-admin/admin-footer.php' );
die;
}

View File

@@ -0,0 +1,498 @@
<?php
/**
* Translation API: Continent and city translations for timezone selection
*
* This file is not included anywhere. It exists solely for use by xgettext.
*
* @package WordPress
* @subpackage i18n
* @since 2.8.0
*/
__('Africa', 'continents-cities');
__('Abidjan', 'continents-cities');
__('Accra', 'continents-cities');
__('Addis Ababa', 'continents-cities');
__('Algiers', 'continents-cities');
__('Asmara', 'continents-cities');
__('Asmera', 'continents-cities');
__('Bamako', 'continents-cities');
__('Bangui', 'continents-cities');
__('Banjul', 'continents-cities');
__('Bissau', 'continents-cities');
__('Blantyre', 'continents-cities');
__('Brazzaville', 'continents-cities');
__('Bujumbura', 'continents-cities');
__('Cairo', 'continents-cities');
__('Casablanca', 'continents-cities');
__('Ceuta', 'continents-cities');
__('Conakry', 'continents-cities');
__('Dakar', 'continents-cities');
__('Dar es Salaam', 'continents-cities');
__('Djibouti', 'continents-cities');
__('Douala', 'continents-cities');
__('El Aaiun', 'continents-cities');
__('Freetown', 'continents-cities');
__('Gaborone', 'continents-cities');
__('Harare', 'continents-cities');
__('Johannesburg', 'continents-cities');
__('Kampala', 'continents-cities');
__('Khartoum', 'continents-cities');
__('Kigali', 'continents-cities');
__('Kinshasa', 'continents-cities');
__('Lagos', 'continents-cities');
__('Libreville', 'continents-cities');
__('Lome', 'continents-cities');
__('Luanda', 'continents-cities');
__('Lubumbashi', 'continents-cities');
__('Lusaka', 'continents-cities');
__('Malabo', 'continents-cities');
__('Maputo', 'continents-cities');
__('Maseru', 'continents-cities');
__('Mbabane', 'continents-cities');
__('Mogadishu', 'continents-cities');
__('Monrovia', 'continents-cities');
__('Nairobi', 'continents-cities');
__('Ndjamena', 'continents-cities');
__('Niamey', 'continents-cities');
__('Nouakchott', 'continents-cities');
__('Ouagadougou', 'continents-cities');
__('Porto-Novo', 'continents-cities');
__('Sao Tome', 'continents-cities');
__('Timbuktu', 'continents-cities');
__('Tripoli', 'continents-cities');
__('Tunis', 'continents-cities');
__('Windhoek', 'continents-cities');
__('America', 'continents-cities');
__('Adak', 'continents-cities');
__('Anchorage', 'continents-cities');
__('Anguilla', 'continents-cities');
__('Antigua', 'continents-cities');
__('Araguaina', 'continents-cities');
__('Argentina', 'continents-cities');
__('Buenos Aires', 'continents-cities');
__('Catamarca', 'continents-cities');
__('ComodRivadavia', 'continents-cities');
__('Cordoba', 'continents-cities');
__('Jujuy', 'continents-cities');
__('La Rioja', 'continents-cities');
__('Mendoza', 'continents-cities');
__('Rio Gallegos', 'continents-cities');
__('San Juan', 'continents-cities');
__('San Luis', 'continents-cities');
__('Tucuman', 'continents-cities');
__('Ushuaia', 'continents-cities');
__('Aruba', 'continents-cities');
__('Asuncion', 'continents-cities');
__('Atikokan', 'continents-cities');
__('Atka', 'continents-cities');
__('Bahia', 'continents-cities');
__('Barbados', 'continents-cities');
__('Belem', 'continents-cities');
__('Belize', 'continents-cities');
__('Blanc-Sablon', 'continents-cities');
__('Boa Vista', 'continents-cities');
__('Bogota', 'continents-cities');
__('Boise', 'continents-cities');
__('Cambridge Bay', 'continents-cities');
__('Campo Grande', 'continents-cities');
__('Cancun', 'continents-cities');
__('Caracas', 'continents-cities');
__('Cayenne', 'continents-cities');
__('Cayman', 'continents-cities');
__('Chicago', 'continents-cities');
__('Chihuahua', 'continents-cities');
__('Coral Harbour', 'continents-cities');
__('Costa Rica', 'continents-cities');
__('Cuiaba', 'continents-cities');
__('Curacao', 'continents-cities');
__('Danmarkshavn', 'continents-cities');
__('Dawson', 'continents-cities');
__('Dawson Creek', 'continents-cities');
__('Denver', 'continents-cities');
__('Detroit', 'continents-cities');
__('Dominica', 'continents-cities');
__('Edmonton', 'continents-cities');
__('Eirunepe', 'continents-cities');
__('El Salvador', 'continents-cities');
__('Ensenada', 'continents-cities');
__('Fort Wayne', 'continents-cities');
__('Fortaleza', 'continents-cities');
__('Glace Bay', 'continents-cities');
__('Godthab', 'continents-cities');
__('Goose Bay', 'continents-cities');
__('Grand Turk', 'continents-cities');
__('Grenada', 'continents-cities');
__('Guadeloupe', 'continents-cities');
__('Guatemala', 'continents-cities');
__('Guayaquil', 'continents-cities');
__('Guyana', 'continents-cities');
__('Halifax', 'continents-cities');
__('Havana', 'continents-cities');
__('Hermosillo', 'continents-cities');
__('Indiana', 'continents-cities');
__('Indianapolis', 'continents-cities');
__('Knox', 'continents-cities');
__('Marengo', 'continents-cities');
__('Petersburg', 'continents-cities');
__('Tell City', 'continents-cities');
__('Vevay', 'continents-cities');
__('Vincennes', 'continents-cities');
__('Winamac', 'continents-cities');
__('Inuvik', 'continents-cities');
__('Iqaluit', 'continents-cities');
__('Jamaica', 'continents-cities');
__('Juneau', 'continents-cities');
__('Kentucky', 'continents-cities');
__('Louisville', 'continents-cities');
__('Monticello', 'continents-cities');
__('Knox IN', 'continents-cities');
__('La Paz', 'continents-cities');
__('Lima', 'continents-cities');
__('Los Angeles', 'continents-cities');
__('Maceio', 'continents-cities');
__('Managua', 'continents-cities');
__('Manaus', 'continents-cities');
__('Marigot', 'continents-cities');
__('Martinique', 'continents-cities');
__('Mazatlan', 'continents-cities');
__('Menominee', 'continents-cities');
__('Merida', 'continents-cities');
__('Mexico City', 'continents-cities');
__('Miquelon', 'continents-cities');
__('Moncton', 'continents-cities');
__('Monterrey', 'continents-cities');
__('Montevideo', 'continents-cities');
__('Montreal', 'continents-cities');
__('Montserrat', 'continents-cities');
__('Nassau', 'continents-cities');
__('New York', 'continents-cities');
__('Nipigon', 'continents-cities');
__('Nome', 'continents-cities');
__('Noronha', 'continents-cities');
__('North Dakota', 'continents-cities');
__('Center', 'continents-cities');
__('New Salem', 'continents-cities');
__('Panama', 'continents-cities');
__('Pangnirtung', 'continents-cities');
__('Paramaribo', 'continents-cities');
__('Phoenix', 'continents-cities');
__('Port-au-Prince', 'continents-cities');
__('Port of Spain', 'continents-cities');
__('Porto Acre', 'continents-cities');
__('Porto Velho', 'continents-cities');
__('Puerto Rico', 'continents-cities');
__('Rainy River', 'continents-cities');
__('Rankin Inlet', 'continents-cities');
__('Recife', 'continents-cities');
__('Regina', 'continents-cities');
__('Resolute', 'continents-cities');
__('Rio Branco', 'continents-cities');
__('Rosario', 'continents-cities');
__('Santiago', 'continents-cities');
__('Santo Domingo', 'continents-cities');
__('Sao Paulo', 'continents-cities');
__('Scoresbysund', 'continents-cities');
__('Shiprock', 'continents-cities');
__('St Barthelemy', 'continents-cities');
__('St Johns', 'continents-cities');
__('St Kitts', 'continents-cities');
__('St Lucia', 'continents-cities');
__('St Thomas', 'continents-cities');
__('St Vincent', 'continents-cities');
__('Swift Current', 'continents-cities');
__('Tegucigalpa', 'continents-cities');
__('Thule', 'continents-cities');
__('Thunder Bay', 'continents-cities');
__('Tijuana', 'continents-cities');
__('Toronto', 'continents-cities');
__('Tortola', 'continents-cities');
__('Vancouver', 'continents-cities');
__('Virgin', 'continents-cities');
__('Whitehorse', 'continents-cities');
__('Winnipeg', 'continents-cities');
__('Yakutat', 'continents-cities');
__('Yellowknife', 'continents-cities');
__('Antarctica', 'continents-cities');
__('Casey', 'continents-cities');
__('Davis', 'continents-cities');
__('DumontDUrville', 'continents-cities');
__('Mawson', 'continents-cities');
__('McMurdo', 'continents-cities');
__('Palmer', 'continents-cities');
__('Rothera', 'continents-cities');
__('South Pole', 'continents-cities');
__('Syowa', 'continents-cities');
__('Vostok', 'continents-cities');
__('Arctic', 'continents-cities');
__('Longyearbyen', 'continents-cities');
__('Asia', 'continents-cities');
__('Aden', 'continents-cities');
__('Almaty', 'continents-cities');
__('Amman', 'continents-cities');
__('Anadyr', 'continents-cities');
__('Aqtau', 'continents-cities');
__('Aqtobe', 'continents-cities');
__('Ashgabat', 'continents-cities');
__('Ashkhabad', 'continents-cities');
__('Baghdad', 'continents-cities');
__('Bahrain', 'continents-cities');
__('Baku', 'continents-cities');
__('Bangkok', 'continents-cities');
__('Beirut', 'continents-cities');
__('Bishkek', 'continents-cities');
__('Brunei', 'continents-cities');
__('Calcutta', 'continents-cities');
__('Choibalsan', 'continents-cities');
__('Chongqing', 'continents-cities');
__('Chungking', 'continents-cities');
__('Colombo', 'continents-cities');
__('Dacca', 'continents-cities');
__('Damascus', 'continents-cities');
__('Dhaka', 'continents-cities');
__('Dili', 'continents-cities');
__('Dubai', 'continents-cities');
__('Dushanbe', 'continents-cities');
__('Gaza', 'continents-cities');
__('Harbin', 'continents-cities');
__('Ho Chi Minh', 'continents-cities');
__('Hong Kong', 'continents-cities');
__('Hovd', 'continents-cities');
__('Irkutsk', 'continents-cities');
__('Istanbul', 'continents-cities');
__('Jakarta', 'continents-cities');
__('Jayapura', 'continents-cities');
__('Jerusalem', 'continents-cities');
__('Kabul', 'continents-cities');
__('Kamchatka', 'continents-cities');
__('Karachi', 'continents-cities');
__('Kashgar', 'continents-cities');
__('Katmandu', 'continents-cities');
__('Kolkata', 'continents-cities');
__('Krasnoyarsk', 'continents-cities');
__('Kuala Lumpur', 'continents-cities');
__('Kuching', 'continents-cities');
__('Kuwait', 'continents-cities');
__('Macao', 'continents-cities');
__('Macau', 'continents-cities');
__('Magadan', 'continents-cities');
__('Makassar', 'continents-cities');
__('Manila', 'continents-cities');
__('Muscat', 'continents-cities');
__('Nicosia', 'continents-cities');
__('Novosibirsk', 'continents-cities');
__('Omsk', 'continents-cities');
__('Oral', 'continents-cities');
__('Phnom Penh', 'continents-cities');
__('Pontianak', 'continents-cities');
__('Pyongyang', 'continents-cities');
__('Qatar', 'continents-cities');
__('Qyzylorda', 'continents-cities');
__('Rangoon', 'continents-cities');
__('Riyadh', 'continents-cities');
__('Saigon', 'continents-cities');
__('Sakhalin', 'continents-cities');
__('Samarkand', 'continents-cities');
__('Seoul', 'continents-cities');
__('Shanghai', 'continents-cities');
__('Singapore', 'continents-cities');
__('Taipei', 'continents-cities');
__('Tashkent', 'continents-cities');
__('Tbilisi', 'continents-cities');
__('Tehran', 'continents-cities');
__('Tel Aviv', 'continents-cities');
__('Thimbu', 'continents-cities');
__('Thimphu', 'continents-cities');
__('Tokyo', 'continents-cities');
__('Ujung Pandang', 'continents-cities');
__('Ulaanbaatar', 'continents-cities');
__('Ulan Bator', 'continents-cities');
__('Urumqi', 'continents-cities');
__('Vientiane', 'continents-cities');
__('Vladivostok', 'continents-cities');
__('Yakutsk', 'continents-cities');
__('Yekaterinburg', 'continents-cities');
__('Yerevan', 'continents-cities');
__('Atlantic', 'continents-cities');
__('Azores', 'continents-cities');
__('Bermuda', 'continents-cities');
__('Canary', 'continents-cities');
__('Cape Verde', 'continents-cities');
__('Faeroe', 'continents-cities');
__('Faroe', 'continents-cities');
__('Jan Mayen', 'continents-cities');
__('Madeira', 'continents-cities');
__('Reykjavik', 'continents-cities');
__('South Georgia', 'continents-cities');
__('St Helena', 'continents-cities');
__('Stanley', 'continents-cities');
__('Australia', 'continents-cities');
__('ACT', 'continents-cities');
__('Adelaide', 'continents-cities');
__('Brisbane', 'continents-cities');
__('Broken Hill', 'continents-cities');
__('Canberra', 'continents-cities');
__('Currie', 'continents-cities');
__('Darwin', 'continents-cities');
__('Eucla', 'continents-cities');
__('Hobart', 'continents-cities');
__('LHI', 'continents-cities');
__('Lindeman', 'continents-cities');
__('Lord Howe', 'continents-cities');
__('Melbourne', 'continents-cities');
__('North', 'continents-cities');
__('NSW', 'continents-cities');
__('Perth', 'continents-cities');
__('Queensland', 'continents-cities');
__('South', 'continents-cities');
__('Sydney', 'continents-cities');
__('Tasmania', 'continents-cities');
__('Victoria', 'continents-cities');
__('West', 'continents-cities');
__('Yancowinna', 'continents-cities');
__('Etc', 'continents-cities');
__('GMT', 'continents-cities');
__('GMT+0', 'continents-cities');
__('GMT+1', 'continents-cities');
__('GMT+10', 'continents-cities');
__('GMT+11', 'continents-cities');
__('GMT+12', 'continents-cities');
__('GMT+2', 'continents-cities');
__('GMT+3', 'continents-cities');
__('GMT+4', 'continents-cities');
__('GMT+5', 'continents-cities');
__('GMT+6', 'continents-cities');
__('GMT+7', 'continents-cities');
__('GMT+8', 'continents-cities');
__('GMT+9', 'continents-cities');
__('GMT-0', 'continents-cities');
__('GMT-1', 'continents-cities');
__('GMT-10', 'continents-cities');
__('GMT-11', 'continents-cities');
__('GMT-12', 'continents-cities');
__('GMT-13', 'continents-cities');
__('GMT-14', 'continents-cities');
__('GMT-2', 'continents-cities');
__('GMT-3', 'continents-cities');
__('GMT-4', 'continents-cities');
__('GMT-5', 'continents-cities');
__('GMT-6', 'continents-cities');
__('GMT-7', 'continents-cities');
__('GMT-8', 'continents-cities');
__('GMT-9', 'continents-cities');
__('GMT0', 'continents-cities');
__('Greenwich', 'continents-cities');
__('UCT', 'continents-cities');
__('Universal', 'continents-cities');
__('UTC', 'continents-cities');
__('Zulu', 'continents-cities');
__('Europe', 'continents-cities');
__('Amsterdam', 'continents-cities');
__('Andorra', 'continents-cities');
__('Athens', 'continents-cities');
__('Belfast', 'continents-cities');
__('Belgrade', 'continents-cities');
__('Berlin', 'continents-cities');
__('Bratislava', 'continents-cities');
__('Brussels', 'continents-cities');
__('Bucharest', 'continents-cities');
__('Budapest', 'continents-cities');
__('Chisinau', 'continents-cities');
__('Copenhagen', 'continents-cities');
__('Dublin', 'continents-cities');
__('Gibraltar', 'continents-cities');
__('Guernsey', 'continents-cities');
__('Helsinki', 'continents-cities');
__('Isle of Man', 'continents-cities');
__('Jersey', 'continents-cities');
__('Kaliningrad', 'continents-cities');
__('Kiev', 'continents-cities');
__('Lisbon', 'continents-cities');
__('Ljubljana', 'continents-cities');
__('London', 'continents-cities');
__('Luxembourg', 'continents-cities');
__('Madrid', 'continents-cities');
__('Malta', 'continents-cities');
__('Mariehamn', 'continents-cities');
__('Minsk', 'continents-cities');
__('Monaco', 'continents-cities');
__('Moscow', 'continents-cities');
__('Oslo', 'continents-cities');
__('Paris', 'continents-cities');
__('Podgorica', 'continents-cities');
__('Prague', 'continents-cities');
__('Riga', 'continents-cities');
__('Rome', 'continents-cities');
__('Samara', 'continents-cities');
__('San Marino', 'continents-cities');
__('Sarajevo', 'continents-cities');
__('Simferopol', 'continents-cities');
__('Skopje', 'continents-cities');
__('Sofia', 'continents-cities');
__('Stockholm', 'continents-cities');
__('Tallinn', 'continents-cities');
__('Tirane', 'continents-cities');
__('Tiraspol', 'continents-cities');
__('Uzhgorod', 'continents-cities');
__('Vaduz', 'continents-cities');
__('Vatican', 'continents-cities');
__('Vienna', 'continents-cities');
__('Vilnius', 'continents-cities');
__('Volgograd', 'continents-cities');
__('Warsaw', 'continents-cities');
__('Zagreb', 'continents-cities');
__('Zaporozhye', 'continents-cities');
__('Zurich', 'continents-cities');
__('Indian', 'continents-cities');
__('Antananarivo', 'continents-cities');
__('Chagos', 'continents-cities');
__('Christmas', 'continents-cities');
__('Cocos', 'continents-cities');
__('Comoro', 'continents-cities');
__('Kerguelen', 'continents-cities');
__('Mahe', 'continents-cities');
__('Maldives', 'continents-cities');
__('Mauritius', 'continents-cities');
__('Mayotte', 'continents-cities');
__('Reunion', 'continents-cities');
__('Pacific', 'continents-cities');
__('Apia', 'continents-cities');
__('Auckland', 'continents-cities');
__('Chatham', 'continents-cities');
__('Easter', 'continents-cities');
__('Efate', 'continents-cities');
__('Enderbury', 'continents-cities');
__('Fakaofo', 'continents-cities');
__('Fiji', 'continents-cities');
__('Funafuti', 'continents-cities');
__('Galapagos', 'continents-cities');
__('Gambier', 'continents-cities');
__('Guadalcanal', 'continents-cities');
__('Guam', 'continents-cities');
__('Honolulu', 'continents-cities');
__('Johnston', 'continents-cities');
__('Kiritimati', 'continents-cities');
__('Kosrae', 'continents-cities');
__('Kwajalein', 'continents-cities');
__('Majuro', 'continents-cities');
__('Marquesas', 'continents-cities');
__('Midway', 'continents-cities');
__('Nauru', 'continents-cities');
__('Niue', 'continents-cities');
__('Norfolk', 'continents-cities');
__('Noumea', 'continents-cities');
__('Pago Pago', 'continents-cities');
__('Palau', 'continents-cities');
__('Pitcairn', 'continents-cities');
__('Ponape', 'continents-cities');
__('Port Moresby', 'continents-cities');
__('Rarotonga', 'continents-cities');
__('Saipan', 'continents-cities');
__('Samoa', 'continents-cities');
__('Tahiti', 'continents-cities');
__('Tarawa', 'continents-cities');
__('Tongatapu', 'continents-cities');
__('Truk', 'continents-cities');
__('Wake', 'continents-cities');
__('Wallis', 'continents-cities');
__('Yap', 'continents-cities');

View File

@@ -0,0 +1,69 @@
<?php
/**
* WordPress Credits Administration API.
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Retrieve the contributor credits.
*
* @global string $wp_version The current WordPress version.
*
* @since 3.2.0
*
* @return array|false A list of all of the contributors, or false on error.
*/
function wp_credits() {
global $wp_version;
$locale = get_locale();
$results = get_site_transient( 'wordpress_credits_' . $locale );
if ( ! is_array( $results )
|| false !== strpos( $wp_version, '-' )
|| ( isset( $results['data']['version'] ) && strpos( $wp_version, $results['data']['version'] ) !== 0 )
) {
$response = wp_remote_get( "http://api.wordpress.org/core/credits/1.1/?version=$wp_version&locale=$locale" );
if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
return false;
$results = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! is_array( $results ) )
return false;
set_site_transient( 'wordpress_credits_' . $locale, $results, DAY_IN_SECONDS );
}
return $results;
}
/**
* Retrieve the link to a contributor's WordPress.org profile page.
*
* @access private
* @since 3.2.0
*
* @param string $display_name The contributor's display name, passed by reference.
* @param string $username The contributor's username.
* @param string $profiles URL to the contributor's WordPress.org profile page.
*/
function _wp_credits_add_profile_link( &$display_name, $username, $profiles ) {
$display_name = '<a href="' . esc_url( sprintf( $profiles, $username ) ) . '">' . esc_html( $display_name ) . '</a>';
}
/**
* Retrieve the link to an external library used in WordPress.
*
* @access private
* @since 3.2.0
*
* @param string $data External library data, passed by reference.
*/
function _wp_credits_build_object_link( &$data ) {
$data = '<a href="' . esc_url( $data[1] ) . '">' . esc_html( $data[0] ) . '</a>';
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,58 @@
<?php
/**
* Edit Tags Administration: Messages
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
$messages = array();
// 0 = unused. Messages start at index 1.
$messages['_item'] = array(
0 => '',
1 => __( 'Item added.' ),
2 => __( 'Item deleted.' ),
3 => __( 'Item updated.' ),
4 => __( 'Item not added.' ),
5 => __( 'Item not updated.' ),
6 => __( 'Items deleted.' ),
);
$messages['category'] = array(
0 => '',
1 => __( 'Category added.' ),
2 => __( 'Category deleted.' ),
3 => __( 'Category updated.' ),
4 => __( 'Category not added.' ),
5 => __( 'Category not updated.' ),
6 => __( 'Categories deleted.' ),
);
$messages['post_tag'] = array(
0 => '',
1 => __( 'Tag added.' ),
2 => __( 'Tag deleted.' ),
3 => __( 'Tag updated.' ),
4 => __( 'Tag not added.' ),
5 => __( 'Tag not updated.' ),
6 => __( 'Tags deleted.' ),
);
/**
* Filter the messages displayed when a tag is updated.
*
* @since 3.7.0
*
* @param array $messages The messages to be displayed.
*/
$messages = apply_filters( 'term_updated_messages', $messages );
$message = false;
if ( isset( $_REQUEST['message'] ) && ( $msg = (int) $_REQUEST['message'] ) ) {
if ( isset( $messages[ $taxonomy ][ $msg ] ) ) {
$message = $messages[ $taxonomy ][ $msg ];
} elseif ( ! isset( $messages[ $taxonomy ] ) && isset( $messages['_item'][ $msg ] ) ) {
$message = $messages['_item'][ $msg ];
}
}

View File

@@ -0,0 +1,541 @@
<?php
/**
* WordPress Export Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Version number for the export format.
*
* Bump this when something changes that might affect compatibility.
*
* @since 2.5.0
*/
define( 'WXR_VERSION', '1.2' );
/**
* Generates the WXR export file for download.
*
* @since 2.1.0
*
* @global wpdb $wpdb
* @global WP_Post $post
*
* @param array $args Filters defining what should be included in the export.
*/
function export_wp( $args = array() ) {
global $wpdb, $post;
$defaults = array( 'content' => 'all', 'author' => false, 'category' => false,
'start_date' => false, 'end_date' => false, 'status' => false,
);
$args = wp_parse_args( $args, $defaults );
/**
* Fires at the beginning of an export, before any headers are sent.
*
* @since 2.3.0
*
* @param array $args An array of export arguments.
*/
do_action( 'export_wp', $args );
$sitename = sanitize_key( get_bloginfo( 'name' ) );
if ( ! empty( $sitename ) ) {
$sitename .= '.';
}
$date = date( 'Y-m-d' );
$wp_filename = $sitename . 'wordpress.' . $date . '.xml';
/**
* Filter the export filename.
*
* @since 4.4.0
*
* @param string $wp_filename The name of the file for download.
* @param string $sitename The site name.
* @param string $date Today's date, formatted.
*/
$filename = apply_filters( 'export_wp_filename', $wp_filename, $sitename, $date );
header( 'Content-Description: File Transfer' );
header( 'Content-Disposition: attachment; filename=' . $filename );
header( 'Content-Type: text/xml; charset=' . get_option( 'blog_charset' ), true );
if ( 'all' != $args['content'] && post_type_exists( $args['content'] ) ) {
$ptype = get_post_type_object( $args['content'] );
if ( ! $ptype->can_export )
$args['content'] = 'post';
$where = $wpdb->prepare( "{$wpdb->posts}.post_type = %s", $args['content'] );
} else {
$post_types = get_post_types( array( 'can_export' => true ) );
$esses = array_fill( 0, count($post_types), '%s' );
$where = $wpdb->prepare( "{$wpdb->posts}.post_type IN (" . implode( ',', $esses ) . ')', $post_types );
}
if ( $args['status'] && ( 'post' == $args['content'] || 'page' == $args['content'] ) )
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", $args['status'] );
else
$where .= " AND {$wpdb->posts}.post_status != 'auto-draft'";
$join = '';
if ( $args['category'] && 'post' == $args['content'] ) {
if ( $term = term_exists( $args['category'], 'category' ) ) {
$join = "INNER JOIN {$wpdb->term_relationships} ON ({$wpdb->posts}.ID = {$wpdb->term_relationships}.object_id)";
$where .= $wpdb->prepare( " AND {$wpdb->term_relationships}.term_taxonomy_id = %d", $term['term_taxonomy_id'] );
}
}
if ( 'post' == $args['content'] || 'page' == $args['content'] || 'attachment' == $args['content'] ) {
if ( $args['author'] )
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_author = %d", $args['author'] );
if ( $args['start_date'] )
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date >= %s", date( 'Y-m-d', strtotime($args['start_date']) ) );
if ( $args['end_date'] )
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_date < %s", date( 'Y-m-d', strtotime('+1 month', strtotime($args['end_date'])) ) );
}
// Grab a snapshot of post IDs, just in case it changes during the export.
$post_ids = $wpdb->get_col( "SELECT ID FROM {$wpdb->posts} $join WHERE $where" );
/*
* Get the requested terms ready, empty unless posts filtered by category
* or all content.
*/
$cats = $tags = $terms = array();
if ( isset( $term ) && $term ) {
$cat = get_term( $term['term_id'], 'category' );
$cats = array( $cat->term_id => $cat );
unset( $term, $cat );
} elseif ( 'all' == $args['content'] ) {
$categories = (array) get_categories( array( 'get' => 'all' ) );
$tags = (array) get_tags( array( 'get' => 'all' ) );
$custom_taxonomies = get_taxonomies( array( '_builtin' => false ) );
$custom_terms = (array) get_terms( $custom_taxonomies, array( 'get' => 'all' ) );
// Put categories in order with no child going before its parent.
while ( $cat = array_shift( $categories ) ) {
if ( $cat->parent == 0 || isset( $cats[$cat->parent] ) )
$cats[$cat->term_id] = $cat;
else
$categories[] = $cat;
}
// Put terms in order with no child going before its parent.
while ( $t = array_shift( $custom_terms ) ) {
if ( $t->parent == 0 || isset( $terms[$t->parent] ) )
$terms[$t->term_id] = $t;
else
$custom_terms[] = $t;
}
unset( $categories, $custom_taxonomies, $custom_terms );
}
/**
* Wrap given string in XML CDATA tag.
*
* @since 2.1.0
*
* @param string $str String to wrap in XML CDATA tag.
* @return string
*/
function wxr_cdata( $str ) {
if ( ! seems_utf8( $str ) ) {
$str = utf8_encode( $str );
}
// $str = ent2ncr(esc_html($str));
$str = '<![CDATA[' . str_replace( ']]>', ']]]]><![CDATA[>', $str ) . ']]>';
return $str;
}
/**
* Return the URL of the site
*
* @since 2.5.0
*
* @return string Site URL.
*/
function wxr_site_url() {
// Multisite: the base URL.
if ( is_multisite() )
return network_home_url();
// WordPress (single site): the blog URL.
else
return get_bloginfo_rss( 'url' );
}
/**
* Output a cat_name XML tag from a given category object
*
* @since 2.1.0
*
* @param object $category Category Object
*/
function wxr_cat_name( $category ) {
if ( empty( $category->name ) )
return;
echo '<wp:cat_name>' . wxr_cdata( $category->name ) . '</wp:cat_name>';
}
/**
* Output a category_description XML tag from a given category object
*
* @since 2.1.0
*
* @param object $category Category Object
*/
function wxr_category_description( $category ) {
if ( empty( $category->description ) )
return;
echo '<wp:category_description>' . wxr_cdata( $category->description ) . '</wp:category_description>';
}
/**
* Output a tag_name XML tag from a given tag object
*
* @since 2.3.0
*
* @param object $tag Tag Object
*/
function wxr_tag_name( $tag ) {
if ( empty( $tag->name ) )
return;
echo '<wp:tag_name>' . wxr_cdata( $tag->name ) . '</wp:tag_name>';
}
/**
* Output a tag_description XML tag from a given tag object
*
* @since 2.3.0
*
* @param object $tag Tag Object
*/
function wxr_tag_description( $tag ) {
if ( empty( $tag->description ) )
return;
echo '<wp:tag_description>' . wxr_cdata( $tag->description ) . '</wp:tag_description>';
}
/**
* Output a term_name XML tag from a given term object
*
* @since 2.9.0
*
* @param object $term Term Object
*/
function wxr_term_name( $term ) {
if ( empty( $term->name ) )
return;
echo '<wp:term_name>' . wxr_cdata( $term->name ) . '</wp:term_name>';
}
/**
* Output a term_description XML tag from a given term object
*
* @since 2.9.0
*
* @param object $term Term Object
*/
function wxr_term_description( $term ) {
if ( empty( $term->description ) )
return;
echo '<wp:term_description>' . wxr_cdata( $term->description ) . '</wp:term_description>';
}
/**
* Output list of authors with posts
*
* @since 3.1.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param array $post_ids Array of post IDs to filter the query by. Optional.
*/
function wxr_authors_list( array $post_ids = null ) {
global $wpdb;
if ( !empty( $post_ids ) ) {
$post_ids = array_map( 'absint', $post_ids );
$and = 'AND ID IN ( ' . implode( ', ', $post_ids ) . ')';
} else {
$and = '';
}
$authors = array();
$results = $wpdb->get_results( "SELECT DISTINCT post_author FROM $wpdb->posts WHERE post_status != 'auto-draft' $and" );
foreach ( (array) $results as $result )
$authors[] = get_userdata( $result->post_author );
$authors = array_filter( $authors );
foreach ( $authors as $author ) {
echo "\t<wp:author>";
echo '<wp:author_id>' . intval( $author->ID ) . '</wp:author_id>';
echo '<wp:author_login>' . wxr_cdata( $author->user_login ) . '</wp:author_login>';
echo '<wp:author_email>' . wxr_cdata( $author->user_email ) . '</wp:author_email>';
echo '<wp:author_display_name>' . wxr_cdata( $author->display_name ) . '</wp:author_display_name>';
echo '<wp:author_first_name>' . wxr_cdata( $author->first_name ) . '</wp:author_first_name>';
echo '<wp:author_last_name>' . wxr_cdata( $author->last_name ) . '</wp:author_last_name>';
echo "</wp:author>\n";
}
}
/**
* Ouput all navigation menu terms
*
* @since 3.1.0
*/
function wxr_nav_menu_terms() {
$nav_menus = wp_get_nav_menus();
if ( empty( $nav_menus ) || ! is_array( $nav_menus ) )
return;
foreach ( $nav_menus as $menu ) {
echo "\t<wp:term>";
echo '<wp:term_id>' . intval( $menu->term_id ) . '</wp:term_id>';
echo '<wp:term_taxonomy>nav_menu</wp:term_taxonomy>';
echo '<wp:term_slug>' . wxr_cdata( $menu->slug ) . '</wp:term_slug>';
wxr_term_name( $menu );
echo "</wp:term>\n";
}
}
/**
* Output list of taxonomy terms, in XML tag format, associated with a post
*
* @since 2.3.0
*/
function wxr_post_taxonomy() {
$post = get_post();
$taxonomies = get_object_taxonomies( $post->post_type );
if ( empty( $taxonomies ) )
return;
$terms = wp_get_object_terms( $post->ID, $taxonomies );
foreach ( (array) $terms as $term ) {
echo "\t\t<category domain=\"{$term->taxonomy}\" nicename=\"{$term->slug}\">" . wxr_cdata( $term->name ) . "</category>\n";
}
}
/**
*
* @param bool $return_me
* @param string $meta_key
* @return bool
*/
function wxr_filter_postmeta( $return_me, $meta_key ) {
if ( '_edit_lock' == $meta_key )
$return_me = true;
return $return_me;
}
add_filter( 'wxr_export_skip_postmeta', 'wxr_filter_postmeta', 10, 2 );
echo '<?xml version="1.0" encoding="' . get_bloginfo('charset') . "\" ?>\n";
?>
<!-- This is a WordPress eXtended RSS file generated by WordPress as an export of your site. -->
<!-- It contains information about your site's posts, pages, comments, categories, and other content. -->
<!-- You may use this file to transfer that content from one site to another. -->
<!-- This file is not intended to serve as a complete backup of your site. -->
<!-- To import this information into a WordPress site follow these steps: -->
<!-- 1. Log in to that site as an administrator. -->
<!-- 2. Go to Tools: Import in the WordPress admin panel. -->
<!-- 3. Install the "WordPress" importer from the list. -->
<!-- 4. Activate & Run Importer. -->
<!-- 5. Upload this file using the form provided on that page. -->
<!-- 6. You will first be asked to map the authors in this export file to users -->
<!-- on the site. For each author, you may choose to map to an -->
<!-- existing user on the site or to create a new user. -->
<!-- 7. WordPress will then import each of the posts, pages, comments, categories, etc. -->
<!-- contained in this file into your site. -->
<?php the_generator( 'export' ); ?>
<rss version="2.0"
xmlns:excerpt="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/excerpt/"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:wfw="http://wellformedweb.org/CommentAPI/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:wp="http://wordpress.org/export/<?php echo WXR_VERSION; ?>/"
>
<channel>
<title><?php bloginfo_rss( 'name' ); ?></title>
<link><?php bloginfo_rss( 'url' ); ?></link>
<description><?php bloginfo_rss( 'description' ); ?></description>
<pubDate><?php echo date( 'D, d M Y H:i:s +0000' ); ?></pubDate>
<language><?php bloginfo_rss( 'language' ); ?></language>
<wp:wxr_version><?php echo WXR_VERSION; ?></wp:wxr_version>
<wp:base_site_url><?php echo wxr_site_url(); ?></wp:base_site_url>
<wp:base_blog_url><?php bloginfo_rss( 'url' ); ?></wp:base_blog_url>
<?php wxr_authors_list( $post_ids ); ?>
<?php foreach ( $cats as $c ) : ?>
<wp:category><wp:term_id><?php echo intval( $c->term_id ); ?></wp:term_id><wp:category_nicename><?php echo wxr_cdata( $c->slug ); ?></wp:category_nicename><wp:category_parent><?php echo wxr_cdata( $c->parent ? $cats[$c->parent]->slug : '' ); ?></wp:category_parent><?php wxr_cat_name( $c ); ?><?php wxr_category_description( $c ); ?></wp:category>
<?php endforeach; ?>
<?php foreach ( $tags as $t ) : ?>
<wp:tag><wp:term_id><?php echo intval( $t->term_id ); ?></wp:term_id><wp:tag_slug><?php echo wxr_cdata( $t->slug ); ?></wp:tag_slug><?php wxr_tag_name( $t ); ?><?php wxr_tag_description( $t ); ?></wp:tag>
<?php endforeach; ?>
<?php foreach ( $terms as $t ) : ?>
<wp:term><wp:term_id><?php echo wxr_cdata( $t->term_id ); ?></wp:term_id><wp:term_taxonomy><?php echo wxr_cdata( $t->taxonomy ); ?></wp:term_taxonomy><wp:term_slug><?php echo wxr_cdata( $t->slug ); ?></wp:term_slug><wp:term_parent><?php echo wxr_cdata( $t->parent ? $terms[$t->parent]->slug : '' ); ?></wp:term_parent><?php wxr_term_name( $t ); ?><?php wxr_term_description( $t ); ?></wp:term>
<?php endforeach; ?>
<?php if ( 'all' == $args['content'] ) wxr_nav_menu_terms(); ?>
<?php
/** This action is documented in wp-includes/feed-rss2.php */
do_action( 'rss2_head' );
?>
<?php if ( $post_ids ) {
/**
* @global WP_Query $wp_query
*/
global $wp_query;
// Fake being in the loop.
$wp_query->in_the_loop = true;
// Fetch 20 posts at a time rather than loading the entire table into memory.
while ( $next_posts = array_splice( $post_ids, 0, 20 ) ) {
$where = 'WHERE ID IN (' . join( ',', $next_posts ) . ')';
$posts = $wpdb->get_results( "SELECT * FROM {$wpdb->posts} $where" );
// Begin Loop.
foreach ( $posts as $post ) {
setup_postdata( $post );
$is_sticky = is_sticky( $post->ID ) ? 1 : 0;
?>
<item>
<title><?php
/** This filter is documented in wp-includes/feed.php */
echo apply_filters( 'the_title_rss', $post->post_title );
?></title>
<link><?php the_permalink_rss() ?></link>
<pubDate><?php echo mysql2date( 'D, d M Y H:i:s +0000', get_post_time( 'Y-m-d H:i:s', true ), false ); ?></pubDate>
<dc:creator><?php echo wxr_cdata( get_the_author_meta( 'login' ) ); ?></dc:creator>
<guid isPermaLink="false"><?php the_guid(); ?></guid>
<description></description>
<content:encoded><?php
/**
* Filter the post content used for WXR exports.
*
* @since 2.5.0
*
* @param string $post_content Content of the current post.
*/
echo wxr_cdata( apply_filters( 'the_content_export', $post->post_content ) );
?></content:encoded>
<excerpt:encoded><?php
/**
* Filter the post excerpt used for WXR exports.
*
* @since 2.6.0
*
* @param string $post_excerpt Excerpt for the current post.
*/
echo wxr_cdata( apply_filters( 'the_excerpt_export', $post->post_excerpt ) );
?></excerpt:encoded>
<wp:post_id><?php echo intval( $post->ID ); ?></wp:post_id>
<wp:post_date><?php echo wxr_cdata( $post->post_date ); ?></wp:post_date>
<wp:post_date_gmt><?php echo wxr_cdata( $post->post_date_gmt ); ?></wp:post_date_gmt>
<wp:comment_status><?php echo wxr_cdata( $post->comment_status ); ?></wp:comment_status>
<wp:ping_status><?php echo wxr_cdata( $post->ping_status ); ?></wp:ping_status>
<wp:post_name><?php echo wxr_cdata( $post->post_name ); ?></wp:post_name>
<wp:status><?php echo wxr_cdata( $post->post_status ); ?></wp:status>
<wp:post_parent><?php echo intval( $post->post_parent ); ?></wp:post_parent>
<wp:menu_order><?php echo intval( $post->menu_order ); ?></wp:menu_order>
<wp:post_type><?php echo wxr_cdata( $post->post_type ); ?></wp:post_type>
<wp:post_password><?php echo wxr_cdata( $post->post_password ); ?></wp:post_password>
<wp:is_sticky><?php echo intval( $is_sticky ); ?></wp:is_sticky>
<?php if ( $post->post_type == 'attachment' ) : ?>
<wp:attachment_url><?php echo wxr_cdata( wp_get_attachment_url( $post->ID ) ); ?></wp:attachment_url>
<?php endif; ?>
<?php wxr_post_taxonomy(); ?>
<?php $postmeta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE post_id = %d", $post->ID ) );
foreach ( $postmeta as $meta ) :
/**
* Filter whether to selectively skip post meta used for WXR exports.
*
* Returning a truthy value to the filter will skip the current meta
* object from being exported.
*
* @since 3.3.0
*
* @param bool $skip Whether to skip the current post meta. Default false.
* @param string $meta_key Current meta key.
* @param object $meta Current meta object.
*/
if ( apply_filters( 'wxr_export_skip_postmeta', false, $meta->meta_key, $meta ) )
continue;
?>
<wp:postmeta>
<wp:meta_key><?php echo wxr_cdata( $meta->meta_key ); ?></wp:meta_key>
<wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
</wp:postmeta>
<?php endforeach;
$_comments = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved <> 'spam'", $post->ID ) );
$comments = array_map( 'get_comment', $_comments );
foreach ( $comments as $c ) : ?>
<wp:comment>
<wp:comment_id><?php echo intval( $c->comment_ID ); ?></wp:comment_id>
<wp:comment_author><?php echo wxr_cdata( $c->comment_author ); ?></wp:comment_author>
<wp:comment_author_email><?php echo wxr_cdata( $c->comment_author_email ); ?></wp:comment_author_email>
<wp:comment_author_url><?php echo esc_url_raw( $c->comment_author_url ); ?></wp:comment_author_url>
<wp:comment_author_IP><?php echo wxr_cdata( $c->comment_author_IP ); ?></wp:comment_author_IP>
<wp:comment_date><?php echo wxr_cdata( $c->comment_date ); ?></wp:comment_date>
<wp:comment_date_gmt><?php echo wxr_cdata( $c->comment_date_gmt ); ?></wp:comment_date_gmt>
<wp:comment_content><?php echo wxr_cdata( $c->comment_content ) ?></wp:comment_content>
<wp:comment_approved><?php echo wxr_cdata( $c->comment_approved ); ?></wp:comment_approved>
<wp:comment_type><?php echo wxr_cdata( $c->comment_type ); ?></wp:comment_type>
<wp:comment_parent><?php echo intval( $c->comment_parent ); ?></wp:comment_parent>
<wp:comment_user_id><?php echo intval( $c->user_id ); ?></wp:comment_user_id>
<?php $c_meta = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM $wpdb->commentmeta WHERE comment_id = %d", $c->comment_ID ) );
foreach ( $c_meta as $meta ) :
/**
* Filter whether to selectively skip comment meta used for WXR exports.
*
* Returning a truthy value to the filter will skip the current meta
* object from being exported.
*
* @since 4.0.0
*
* @param bool $skip Whether to skip the current comment meta. Default false.
* @param string $meta_key Current meta key.
* @param object $meta Current meta object.
*/
if ( apply_filters( 'wxr_export_skip_commentmeta', false, $meta->meta_key, $meta ) ) {
continue;
}
?>
<wp:commentmeta>
<wp:meta_key><?php echo wxr_cdata( $meta->meta_key ); ?></wp:meta_key>
<wp:meta_value><?php echo wxr_cdata( $meta->meta_value ); ?></wp:meta_value>
</wp:commentmeta>
<?php endforeach; ?>
</wp:comment>
<?php endforeach; ?>
</item>
<?php
}
}
} ?>
</channel>
</rss>
<?php
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,893 @@
<?php
/**
* WordPress Image Editor
*
* @package WordPress
* @subpackage Administration
*/
/**
* Loads the WP image-editing interface.
*
* @param int $post_id Post ID.
* @param bool|object $msg Optional. Message to display for image editor updates or errors.
* Default false.
*/
function wp_image_editor($post_id, $msg = false) {
$nonce = wp_create_nonce("image_editor-$post_id");
$meta = wp_get_attachment_metadata($post_id);
$thumb = image_get_intermediate_size($post_id, 'thumbnail');
$sub_sizes = isset($meta['sizes']) && is_array($meta['sizes']);
$note = '';
if ( isset( $meta['width'], $meta['height'] ) )
$big = max( $meta['width'], $meta['height'] );
else
die( __('Image data does not exist. Please re-upload the image.') );
$sizer = $big > 400 ? 400 / $big : 1;
$backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
$can_restore = false;
if ( ! empty( $backup_sizes ) && isset( $backup_sizes['full-orig'], $meta['file'] ) )
$can_restore = $backup_sizes['full-orig']['file'] != basename( $meta['file'] );
if ( $msg ) {
if ( isset($msg->error) )
$note = "<div class='error'><p>$msg->error</p></div>";
elseif ( isset($msg->msg) )
$note = "<div class='updated'><p>$msg->msg</p></div>";
}
?>
<div class="imgedit-wrap wp-clearfix">
<div id="imgedit-panel-<?php echo $post_id; ?>">
<div class="imgedit-settings">
<div class="imgedit-group">
<div class="imgedit-group-top">
<h2><?php _e( 'Scale Image' ); ?></h2>
<button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Scale Image Help' ); ?></span></button>
<div class="imgedit-help">
<p><?php _e('You can proportionally scale the original image. For best results, scaling should be done before you crop, flip, or rotate. Images can only be scaled down, not up.'); ?></p>
</div>
<?php if ( isset( $meta['width'], $meta['height'] ) ): ?>
<p><?php printf( __('Original dimensions %s'), $meta['width'] . ' &times; ' . $meta['height'] ); ?></p>
<?php endif ?>
<div class="imgedit-submit">
<fieldset class="imgedit-scale">
<legend><?php _e( 'New dimensions:' ); ?></legend>
<div class="nowrap">
<label><span class="screen-reader-text"><?php _e( 'scale width' ); ?></span>
<input type="text" id="imgedit-scale-width-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 1)" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
</label>
<span class="imgedit-separator">&times;</span>
<label><span class="screen-reader-text"><?php _e( 'scale height' ); ?></span>
<input type="text" id="imgedit-scale-height-<?php echo $post_id; ?>" onkeyup="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" onblur="imageEdit.scaleChanged(<?php echo $post_id; ?>, 0)" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
</label>
<span class="imgedit-scale-warn" id="imgedit-scale-warn-<?php echo $post_id; ?>">!</span>
<input id="imgedit-scale-button" type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'scale')" class="button button-primary" value="<?php esc_attr_e( 'Scale' ); ?>" />
</div>
</fieldset>
</div>
</div>
</div>
<?php if ( $can_restore ) { ?>
<div class="imgedit-group">
<div class="imgedit-group-top">
<h2><button type="button" onclick="imageEdit.toggleHelp(this);" class="button-link"><?php _e( 'Restore Original Image' ); ?> <span class="dashicons dashicons-arrow-down imgedit-help-toggle"></span></button></h2>
<div class="imgedit-help">
<p><?php _e('Discard any changes and restore the original image.');
if ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE )
echo ' '.__('Previously edited copies of the image will not be deleted.');
?></p>
<div class="imgedit-submit">
<input type="button" onclick="imageEdit.action(<?php echo "$post_id, '$nonce'"; ?>, 'restore')" class="button button-primary" value="<?php esc_attr_e( 'Restore image' ); ?>" <?php echo $can_restore; ?> />
</div>
</div>
</div>
</div>
<?php } ?>
<div class="imgedit-group">
<div class="imgedit-group-top">
<h2><?php _e( 'Image Crop' ); ?></h2>
<button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Image Crop Help' ); ?></span></button>
<div class="imgedit-help">
<p><?php _e('To crop the image, click on it and drag to make your selection.'); ?></p>
<p><strong><?php _e('Crop Aspect Ratio'); ?></strong><br />
<?php _e('The aspect ratio is the relationship between the width and height. You can preserve the aspect ratio by holding down the shift key while resizing your selection. Use the input box to specify the aspect ratio, e.g. 1:1 (square), 4:3, 16:9, etc.'); ?></p>
<p><strong><?php _e('Crop Selection'); ?></strong><br />
<?php _e('Once you have made your selection, you can adjust it by entering the size in pixels. The minimum selection size is the thumbnail size as set in the Media settings.'); ?></p>
</div>
</div>
<fieldset class="imgedit-crop-ratio">
<legend><?php _e( 'Aspect ratio:' ); ?></legend>
<div class="nowrap">
<label><span class="screen-reader-text"><?php _e( 'crop ratio width' ); ?></span>
<input type="text" id="imgedit-crop-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 0, this)" />
</label>
<span class="imgedit-separator">:</span>
<label><span class="screen-reader-text"><?php _e( 'crop ratio height' ); ?></span>
<input type="text" id="imgedit-crop-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setRatioSelection(<?php echo $post_id; ?>, 1, this)" />
</label>
</div>
</fieldset>
<fieldset id="imgedit-crop-sel-<?php echo $post_id; ?>" class="imgedit-crop-sel">
<legend><?php _e( 'Selection:' ); ?></legend>
<div class="nowrap">
<label><span class="screen-reader-text"><?php _e( 'selection width' ); ?></span>
<input type="text" id="imgedit-sel-width-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" />
</label>
<span class="imgedit-separator">&times;</span>
<label><span class="screen-reader-text"><?php _e( 'selection height' ); ?></span>
<input type="text" id="imgedit-sel-height-<?php echo $post_id; ?>" onkeyup="imageEdit.setNumSelection(<?php echo $post_id; ?>)" />
</label>
</div>
</fieldset>
</div>
<?php if ( $thumb && $sub_sizes ) {
$thumb_img = wp_constrain_dimensions( $thumb['width'], $thumb['height'], 160, 120 );
?>
<div class="imgedit-group imgedit-applyto">
<div class="imgedit-group-top">
<h2><?php _e( 'Thumbnail Settings' ); ?></h2>
<button type="button" class="dashicons dashicons-editor-help imgedit-help-toggle" onclick="imageEdit.toggleHelp(this);return false;" aria-expanded="false"><span class="screen-reader-text"><?php esc_html_e( 'Thumbnail Settings Help' ); ?></span></button>
<p class="imgedit-help"><?php _e('You can edit the image while preserving the thumbnail. For example, you may wish to have a square thumbnail that displays just a section of the image.'); ?></p>
</div>
<figure class="imgedit-thumbnail-preview">
<img src="<?php echo $thumb['url']; ?>" width="<?php echo $thumb_img[0]; ?>" height="<?php echo $thumb_img[1]; ?>" class="imgedit-size-preview" alt="" draggable="false" />
<figcaption class="imgedit-thumbnail-preview-caption"><?php _e( 'Current thumbnail' ); ?></figcaption>
</figure>
<div id="imgedit-save-target-<?php echo $post_id; ?>" class="imgedit-save-target">
<fieldset>
<legend><strong><?php _e( 'Apply changes to:' ); ?></strong></legend>
<label class="imgedit-label">
<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="all" checked="checked" />
<?php _e('All image sizes'); ?></label>
<label class="imgedit-label">
<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="thumbnail" />
<?php _e('Thumbnail'); ?></label>
<label class="imgedit-label">
<input type="radio" name="imgedit-target-<?php echo $post_id; ?>" value="nothumb" />
<?php _e('All sizes except thumbnail'); ?></label>
</fieldset>
</div>
</div>
<?php } ?>
</div>
<div class="imgedit-panel-content wp-clearfix">
<?php echo $note; ?>
<div class="imgedit-menu wp-clearfix">
<button type="button" onclick="imageEdit.crop(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-crop button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Crop' ); ?></span></button><?php
// On some setups GD library does not provide imagerotate() - Ticket #11536
if ( wp_image_editor_supports( array( 'mime_type' => get_post_mime_type( $post_id ), 'methods' => array( 'rotate' ) ) ) ) {
$note_no_rotate = '';
?>
<button type="button" class="imgedit-rleft button" onclick="imageEdit.rotate( 90, <?php echo "$post_id, '$nonce'"; ?>, this)"><span class="screen-reader-text"><?php esc_html_e( 'Rotate counter-clockwise' ); ?></span></button>
<button type="button" class="imgedit-rright button" onclick="imageEdit.rotate(-90, <?php echo "$post_id, '$nonce'"; ?>, this)"><span class="screen-reader-text"><?php esc_html_e( 'Rotate clockwise' ); ?></span></button>
<?php } else {
$note_no_rotate = '<p class="note-no-rotate"><em>' . __( 'Image rotation is not supported by your web host.' ) . '</em></p>';
?>
<button type="button" class="imgedit-rleft button disabled" disabled></button>
<button type="button" class="imgedit-rright button disabled" disabled></button>
<?php } ?>
<button type="button" onclick="imageEdit.flip(1, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-flipv button"><span class="screen-reader-text"><?php esc_html_e( 'Flip vertically' ); ?></span></button>
<button type="button" onclick="imageEdit.flip(2, <?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-fliph button"><span class="screen-reader-text"><?php esc_html_e( 'Flip horizontally' ); ?></span></button>
<button type="button" id="image-undo-<?php echo $post_id; ?>" onclick="imageEdit.undo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-undo button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Undo' ); ?></span></button>
<button type="button" id="image-redo-<?php echo $post_id; ?>" onclick="imageEdit.redo(<?php echo "$post_id, '$nonce'"; ?>, this)" class="imgedit-redo button disabled" disabled><span class="screen-reader-text"><?php esc_html_e( 'Redo' ); ?></span></button>
<?php echo $note_no_rotate; ?>
</div>
<input type="hidden" id="imgedit-sizer-<?php echo $post_id; ?>" value="<?php echo $sizer; ?>" />
<input type="hidden" id="imgedit-history-<?php echo $post_id; ?>" value="" />
<input type="hidden" id="imgedit-undone-<?php echo $post_id; ?>" value="0" />
<input type="hidden" id="imgedit-selection-<?php echo $post_id; ?>" value="" />
<input type="hidden" id="imgedit-x-<?php echo $post_id; ?>" value="<?php echo isset( $meta['width'] ) ? $meta['width'] : 0; ?>" />
<input type="hidden" id="imgedit-y-<?php echo $post_id; ?>" value="<?php echo isset( $meta['height'] ) ? $meta['height'] : 0; ?>" />
<div id="imgedit-crop-<?php echo $post_id; ?>" class="imgedit-crop-wrap">
<img id="image-preview-<?php echo $post_id; ?>" onload="imageEdit.imgLoaded('<?php echo $post_id; ?>')" src="<?php echo admin_url( 'admin-ajax.php', 'relative' ); ?>?action=imgedit-preview&amp;_ajax_nonce=<?php echo $nonce; ?>&amp;postid=<?php echo $post_id; ?>&amp;rand=<?php echo rand(1, 99999); ?>" alt="" />
</div>
<div class="imgedit-submit">
<input type="button" onclick="imageEdit.close(<?php echo $post_id; ?>, 1)" class="button imgedit-cancel-btn" value="<?php esc_attr_e( 'Cancel' ); ?>" />
<input type="button" onclick="imageEdit.save(<?php echo "$post_id, '$nonce'"; ?>)" disabled="disabled" class="button button-primary imgedit-submit-btn" value="<?php esc_attr_e( 'Save' ); ?>" />
</div>
</div>
</div>
<div class="imgedit-wait" id="imgedit-wait-<?php echo $post_id; ?>"></div>
<script type="text/javascript">jQuery( function() { imageEdit.init(<?php echo $post_id; ?>); });</script>
<div class="hidden" id="imgedit-leaving-<?php echo $post_id; ?>"><?php _e("There are unsaved changes that will be lost. 'OK' to continue, 'Cancel' to return to the Image Editor."); ?></div>
</div>
<?php
}
/**
* Streams image in WP_Image_Editor to browser.
* Provided for backcompat reasons
*
* @param WP_Image_Editor $image
* @param string $mime_type
* @param int $post_id
* @return bool
*/
function wp_stream_image( $image, $mime_type, $post_id ) {
if ( $image instanceof WP_Image_Editor ) {
/**
* Filter the WP_Image_Editor instance for the image to be streamed to the browser.
*
* @since 3.5.0
*
* @param WP_Image_Editor $image WP_Image_Editor instance.
* @param int $post_id Post ID.
*/
$image = apply_filters( 'image_editor_save_pre', $image, $post_id );
if ( is_wp_error( $image->stream( $mime_type ) ) )
return false;
return true;
} else {
_deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
/**
* Filter the GD image resource to be streamed to the browser.
*
* @since 2.9.0
* @deprecated 3.5.0 Use image_editor_save_pre instead.
*
* @param resource $image Image resource to be streamed.
* @param int $post_id Post ID.
*/
$image = apply_filters( 'image_save_pre', $image, $post_id );
switch ( $mime_type ) {
case 'image/jpeg':
header( 'Content-Type: image/jpeg' );
return imagejpeg( $image, null, 90 );
case 'image/png':
header( 'Content-Type: image/png' );
return imagepng( $image );
case 'image/gif':
header( 'Content-Type: image/gif' );
return imagegif( $image );
default:
return false;
}
}
}
/**
* Saves Image to File
*
* @param string $filename
* @param WP_Image_Editor $image
* @param string $mime_type
* @param int $post_id
* @return bool
*/
function wp_save_image_file( $filename, $image, $mime_type, $post_id ) {
if ( $image instanceof WP_Image_Editor ) {
/** This filter is documented in wp-admin/includes/image-edit.php */
$image = apply_filters( 'image_editor_save_pre', $image, $post_id );
/**
* Filter whether to skip saving the image file.
*
* Returning a non-null value will short-circuit the save method,
* returning that value instead.
*
* @since 3.5.0
*
* @param mixed $override Value to return instead of saving. Default null.
* @param string $filename Name of the file to be saved.
* @param WP_Image_Editor $image WP_Image_Editor instance.
* @param string $mime_type Image mime type.
* @param int $post_id Post ID.
*/
$saved = apply_filters( 'wp_save_image_editor_file', null, $filename, $image, $mime_type, $post_id );
if ( null !== $saved )
return $saved;
return $image->save( $filename, $mime_type );
} else {
_deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
/** This filter is documented in wp-admin/includes/image-edit.php */
$image = apply_filters( 'image_save_pre', $image, $post_id );
/**
* Filter whether to skip saving the image file.
*
* Returning a non-null value will short-circuit the save method,
* returning that value instead.
*
* @since 2.9.0
* @deprecated 3.5.0 Use wp_save_image_editor_file instead.
*
* @param mixed $override Value to return instead of saving. Default null.
* @param string $filename Name of the file to be saved.
* @param WP_Image_Editor $image WP_Image_Editor instance.
* @param string $mime_type Image mime type.
* @param int $post_id Post ID.
*/
$saved = apply_filters( 'wp_save_image_file', null, $filename, $image, $mime_type, $post_id );
if ( null !== $saved )
return $saved;
switch ( $mime_type ) {
case 'image/jpeg':
/** This filter is documented in wp-includes/class-wp-image-editor.php */
return imagejpeg( $image, $filename, apply_filters( 'jpeg_quality', 90, 'edit_image' ) );
case 'image/png':
return imagepng( $image, $filename );
case 'image/gif':
return imagegif( $image, $filename );
default:
return false;
}
}
}
/**
* Image preview ratio. Internal use only.
*
* @since 2.9.0
*
* @ignore
* @param int $w Image width in pixels.
* @param int $h Image height in pixels.
* @return float|int Image preview ratio.
*/
function _image_get_preview_ratio($w, $h) {
$max = max($w, $h);
return $max > 400 ? (400 / $max) : 1;
}
/**
* Returns an image resource. Internal use only.
*
* @since 2.9.0
*
* @ignore
* @param resource $img Image resource.
* @param float|int $angle Image rotation angle, in degrees.
* @return resource|false GD image resource, false otherwise.
*/
function _rotate_image_resource($img, $angle) {
_deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::rotate' ) );
if ( function_exists('imagerotate') ) {
$rotated = imagerotate($img, $angle, 0);
if ( is_resource($rotated) ) {
imagedestroy($img);
$img = $rotated;
}
}
return $img;
}
/**
* Flips an image resource. Internal use only.
*
* @since 2.9.0
*
* @ignore
* @param resource $img Image resource.
* @param bool $horz Whether to flip horizontally.
* @param bool $vert Whether to flip vertically.
* @return resource (maybe) flipped image resource.
*/
function _flip_image_resource($img, $horz, $vert) {
_deprecated_function( __FUNCTION__, '3.5', __( 'Use WP_Image_Editor::flip' ) );
$w = imagesx($img);
$h = imagesy($img);
$dst = wp_imagecreatetruecolor($w, $h);
if ( is_resource($dst) ) {
$sx = $vert ? ($w - 1) : 0;
$sy = $horz ? ($h - 1) : 0;
$sw = $vert ? -$w : $w;
$sh = $horz ? -$h : $h;
if ( imagecopyresampled($dst, $img, 0, 0, $sx, $sy, $w, $h, $sw, $sh) ) {
imagedestroy($img);
$img = $dst;
}
}
return $img;
}
/**
* Crops an image resource. Internal use only.
*
* @since 2.9.0
*
* @ignore
* @param resource $img Image resource.
* @param float $x Source point x-coordinate.
* @param float $y Source point y-cooredinate.
* @param float $w Source width.
* @param float $h Source height.
* @return resource (maybe) cropped image resource.
*/
function _crop_image_resource($img, $x, $y, $w, $h) {
$dst = wp_imagecreatetruecolor($w, $h);
if ( is_resource($dst) ) {
if ( imagecopy($dst, $img, 0, 0, $x, $y, $w, $h) ) {
imagedestroy($img);
$img = $dst;
}
}
return $img;
}
/**
* Performs group of changes on Editor specified.
*
* @since 2.9.0
*
* @param WP_Image_Editor $image {@see WP_Image_Editor} instance.
* @param array $changes Array of change operations.
* @return WP_Image_Editor {@see WP_Image_Editor} instance with changes applied.
*/
function image_edit_apply_changes( $image, $changes ) {
if ( is_resource( $image ) )
_deprecated_argument( __FUNCTION__, '3.5', __( '$image needs to be an WP_Image_Editor object' ) );
if ( !is_array($changes) )
return $image;
// Expand change operations.
foreach ( $changes as $key => $obj ) {
if ( isset($obj->r) ) {
$obj->type = 'rotate';
$obj->angle = $obj->r;
unset($obj->r);
} elseif ( isset($obj->f) ) {
$obj->type = 'flip';
$obj->axis = $obj->f;
unset($obj->f);
} elseif ( isset($obj->c) ) {
$obj->type = 'crop';
$obj->sel = $obj->c;
unset($obj->c);
}
$changes[$key] = $obj;
}
// Combine operations.
if ( count($changes) > 1 ) {
$filtered = array($changes[0]);
for ( $i = 0, $j = 1, $c = count( $changes ); $j < $c; $j++ ) {
$combined = false;
if ( $filtered[$i]->type == $changes[$j]->type ) {
switch ( $filtered[$i]->type ) {
case 'rotate':
$filtered[$i]->angle += $changes[$j]->angle;
$combined = true;
break;
case 'flip':
$filtered[$i]->axis ^= $changes[$j]->axis;
$combined = true;
break;
}
}
if ( !$combined )
$filtered[++$i] = $changes[$j];
}
$changes = $filtered;
unset($filtered);
}
// Image resource before applying the changes.
if ( $image instanceof WP_Image_Editor ) {
/**
* Filter the WP_Image_Editor instance before applying changes to the image.
*
* @since 3.5.0
*
* @param WP_Image_Editor $image WP_Image_Editor instance.
* @param array $changes Array of change operations.
*/
$image = apply_filters( 'wp_image_editor_before_change', $image, $changes );
} elseif ( is_resource( $image ) ) {
/**
* Filter the GD image resource before applying changes to the image.
*
* @since 2.9.0
* @deprecated 3.5.0 Use wp_image_editor_before_change instead.
*
* @param resource $image GD image resource.
* @param array $changes Array of change operations.
*/
$image = apply_filters( 'image_edit_before_change', $image, $changes );
}
foreach ( $changes as $operation ) {
switch ( $operation->type ) {
case 'rotate':
if ( $operation->angle != 0 ) {
if ( $image instanceof WP_Image_Editor )
$image->rotate( $operation->angle );
else
$image = _rotate_image_resource( $image, $operation->angle );
}
break;
case 'flip':
if ( $operation->axis != 0 )
if ( $image instanceof WP_Image_Editor )
$image->flip( ($operation->axis & 1) != 0, ($operation->axis & 2) != 0 );
else
$image = _flip_image_resource( $image, ( $operation->axis & 1 ) != 0, ( $operation->axis & 2 ) != 0 );
break;
case 'crop':
$sel = $operation->sel;
if ( $image instanceof WP_Image_Editor ) {
$size = $image->get_size();
$w = $size['width'];
$h = $size['height'];
$scale = 1 / _image_get_preview_ratio( $w, $h ); // discard preview scaling
$image->crop( $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
} else {
$scale = 1 / _image_get_preview_ratio( imagesx( $image ), imagesy( $image ) ); // discard preview scaling
$image = _crop_image_resource( $image, $sel->x * $scale, $sel->y * $scale, $sel->w * $scale, $sel->h * $scale );
}
break;
}
}
return $image;
}
/**
* Streams image in post to browser, along with enqueued changes
* in $_REQUEST['history']
*
* @param int $post_id
* @return bool
*/
function stream_preview_image( $post_id ) {
$post = get_post( $post_id );
/** This filter is documented in wp-admin/admin.php */
@ini_set( 'memory_limit', apply_filters( 'admin_memory_limit', WP_MAX_MEMORY_LIMIT ) );
$img = wp_get_image_editor( _load_image_to_edit_path( $post_id ) );
if ( is_wp_error( $img ) ) {
return false;
}
$changes = !empty($_REQUEST['history']) ? json_decode( wp_unslash($_REQUEST['history']) ) : null;
if ( $changes )
$img = image_edit_apply_changes( $img, $changes );
// Scale the image.
$size = $img->get_size();
$w = $size['width'];
$h = $size['height'];
$ratio = _image_get_preview_ratio( $w, $h );
$w2 = max ( 1, $w * $ratio );
$h2 = max ( 1, $h * $ratio );
if ( is_wp_error( $img->resize( $w2, $h2 ) ) )
return false;
return wp_stream_image( $img, $post->post_mime_type, $post_id );
}
/**
* Restores the metadata for a given attachment.
*
* @since 2.9.0
*
* @param int $post_id Attachment post ID.
* @return stdClass Image restoration message object.
*/
function wp_restore_image($post_id) {
$meta = wp_get_attachment_metadata($post_id);
$file = get_attached_file($post_id);
$backup_sizes = $old_backup_sizes = get_post_meta( $post_id, '_wp_attachment_backup_sizes', true );
$restored = false;
$msg = new stdClass;
if ( !is_array($backup_sizes) ) {
$msg->error = __('Cannot load image metadata.');
return $msg;
}
$parts = pathinfo($file);
$suffix = time() . rand(100, 999);
$default_sizes = get_intermediate_image_sizes();
if ( isset($backup_sizes['full-orig']) && is_array($backup_sizes['full-orig']) ) {
$data = $backup_sizes['full-orig'];
if ( $parts['basename'] != $data['file'] ) {
if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
// Delete only if it's an edited image.
if ( preg_match('/-e[0-9]{13}\./', $parts['basename']) ) {
wp_delete_file( $file );
}
} elseif ( isset( $meta['width'], $meta['height'] ) ) {
$backup_sizes["full-$suffix"] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $parts['basename']);
}
}
$restored_file = path_join($parts['dirname'], $data['file']);
$restored = update_attached_file($post_id, $restored_file);
$meta['file'] = _wp_relative_upload_path( $restored_file );
$meta['width'] = $data['width'];
$meta['height'] = $data['height'];
}
foreach ( $default_sizes as $default_size ) {
if ( isset($backup_sizes["$default_size-orig"]) ) {
$data = $backup_sizes["$default_size-orig"];
if ( isset($meta['sizes'][$default_size]) && $meta['sizes'][$default_size]['file'] != $data['file'] ) {
if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE ) {
// Delete only if it's an edited image.
if ( preg_match('/-e[0-9]{13}-/', $meta['sizes'][$default_size]['file']) ) {
$delete_file = path_join( $parts['dirname'], $meta['sizes'][$default_size]['file'] );
wp_delete_file( $delete_file );
}
} else {
$backup_sizes["$default_size-{$suffix}"] = $meta['sizes'][$default_size];
}
}
$meta['sizes'][$default_size] = $data;
} else {
unset($meta['sizes'][$default_size]);
}
}
if ( ! wp_update_attachment_metadata( $post_id, $meta ) ||
( $old_backup_sizes !== $backup_sizes && ! update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes ) ) ) {
$msg->error = __('Cannot save image metadata.');
return $msg;
}
if ( !$restored )
$msg->error = __('Image metadata is inconsistent.');
else
$msg->msg = __('Image restored successfully.');
return $msg;
}
/**
* Saves image to post along with enqueued changes
* in $_REQUEST['history']
*
* @global array $_wp_additional_image_sizes
*
* @param int $post_id
* @return \stdClass
*/
function wp_save_image( $post_id ) {
global $_wp_additional_image_sizes;
$return = new stdClass;
$success = $delete = $scaled = $nocrop = false;
$post = get_post( $post_id );
$img = wp_get_image_editor( _load_image_to_edit_path( $post_id, 'full' ) );
if ( is_wp_error( $img ) ) {
$return->error = esc_js( __('Unable to create new image.') );
return $return;
}
$fwidth = !empty($_REQUEST['fwidth']) ? intval($_REQUEST['fwidth']) : 0;
$fheight = !empty($_REQUEST['fheight']) ? intval($_REQUEST['fheight']) : 0;
$target = !empty($_REQUEST['target']) ? preg_replace('/[^a-z0-9_-]+/i', '', $_REQUEST['target']) : '';
$scale = !empty($_REQUEST['do']) && 'scale' == $_REQUEST['do'];
if ( $scale && $fwidth > 0 && $fheight > 0 ) {
$size = $img->get_size();
$sX = $size['width'];
$sY = $size['height'];
// Check if it has roughly the same w / h ratio.
$diff = round($sX / $sY, 2) - round($fwidth / $fheight, 2);
if ( -0.1 < $diff && $diff < 0.1 ) {
// Scale the full size image.
if ( $img->resize( $fwidth, $fheight ) )
$scaled = true;
}
if ( !$scaled ) {
$return->error = esc_js( __('Error while saving the scaled image. Please reload the page and try again.') );
return $return;
}
} elseif ( !empty($_REQUEST['history']) ) {
$changes = json_decode( wp_unslash($_REQUEST['history']) );
if ( $changes )
$img = image_edit_apply_changes($img, $changes);
} else {
$return->error = esc_js( __('Nothing to save, the image has not changed.') );
return $return;
}
$meta = wp_get_attachment_metadata($post_id);
$backup_sizes = get_post_meta( $post->ID, '_wp_attachment_backup_sizes', true );
if ( !is_array($meta) ) {
$return->error = esc_js( __('Image data does not exist. Please re-upload the image.') );
return $return;
}
if ( !is_array($backup_sizes) )
$backup_sizes = array();
// Generate new filename.
$path = get_attached_file($post_id);
$path_parts = pathinfo( $path );
$filename = $path_parts['filename'];
$suffix = time() . rand(100, 999);
if ( defined('IMAGE_EDIT_OVERWRITE') && IMAGE_EDIT_OVERWRITE &&
isset($backup_sizes['full-orig']) && $backup_sizes['full-orig']['file'] != $path_parts['basename'] ) {
if ( 'thumbnail' == $target )
$new_path = "{$path_parts['dirname']}/{$filename}-temp.{$path_parts['extension']}";
else
$new_path = $path;
} else {
while( true ) {
$filename = preg_replace( '/-e([0-9]+)$/', '', $filename );
$filename .= "-e{$suffix}";
$new_filename = "{$filename}.{$path_parts['extension']}";
$new_path = "{$path_parts['dirname']}/$new_filename";
if ( file_exists($new_path) )
$suffix++;
else
break;
}
}
// Save the full-size file, also needed to create sub-sizes.
if ( !wp_save_image_file($new_path, $img, $post->post_mime_type, $post_id) ) {
$return->error = esc_js( __('Unable to save the image.') );
return $return;
}
if ( 'nothumb' == $target || 'all' == $target || 'full' == $target || $scaled ) {
$tag = false;
if ( isset($backup_sizes['full-orig']) ) {
if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes['full-orig']['file'] != $path_parts['basename'] )
$tag = "full-$suffix";
} else {
$tag = 'full-orig';
}
if ( $tag )
$backup_sizes[$tag] = array('width' => $meta['width'], 'height' => $meta['height'], 'file' => $path_parts['basename']);
$success = ( $path === $new_path ) || update_attached_file( $post_id, $new_path );
$meta['file'] = _wp_relative_upload_path( $new_path );
$size = $img->get_size();
$meta['width'] = $size['width'];
$meta['height'] = $size['height'];
if ( $success && ('nothumb' == $target || 'all' == $target) ) {
$sizes = get_intermediate_image_sizes();
if ( 'nothumb' == $target )
$sizes = array_diff( $sizes, array('thumbnail') );
}
$return->fw = $meta['width'];
$return->fh = $meta['height'];
} elseif ( 'thumbnail' == $target ) {
$sizes = array( 'thumbnail' );
$success = $delete = $nocrop = true;
}
if ( isset( $sizes ) ) {
$_sizes = array();
foreach ( $sizes as $size ) {
$tag = false;
if ( isset( $meta['sizes'][$size] ) ) {
if ( isset($backup_sizes["$size-orig"]) ) {
if ( ( !defined('IMAGE_EDIT_OVERWRITE') || !IMAGE_EDIT_OVERWRITE ) && $backup_sizes["$size-orig"]['file'] != $meta['sizes'][$size]['file'] )
$tag = "$size-$suffix";
} else {
$tag = "$size-orig";
}
if ( $tag )
$backup_sizes[$tag] = $meta['sizes'][$size];
}
if ( isset( $_wp_additional_image_sizes[ $size ] ) ) {
$width = intval( $_wp_additional_image_sizes[ $size ]['width'] );
$height = intval( $_wp_additional_image_sizes[ $size ]['height'] );
$crop = ( $nocrop ) ? false : $_wp_additional_image_sizes[ $size ]['crop'];
} else {
$height = get_option( "{$size}_size_h" );
$width = get_option( "{$size}_size_w" );
$crop = ( $nocrop ) ? false : get_option( "{$size}_crop" );
}
$_sizes[ $size ] = array( 'width' => $width, 'height' => $height, 'crop' => $crop );
}
$meta['sizes'] = array_merge( $meta['sizes'], $img->multi_resize( $_sizes ) );
}
unset( $img );
if ( $success ) {
wp_update_attachment_metadata( $post_id, $meta );
update_post_meta( $post_id, '_wp_attachment_backup_sizes', $backup_sizes);
if ( $target == 'thumbnail' || $target == 'all' || $target == 'full' ) {
// Check if it's an image edit from attachment edit screen
if ( ! empty( $_REQUEST['context'] ) && 'edit-attachment' == $_REQUEST['context'] ) {
$thumb_url = wp_get_attachment_image_src( $post_id, array( 900, 600 ), true );
$return->thumbnail = $thumb_url[0];
} else {
$file_url = wp_get_attachment_url($post_id);
if ( ! empty( $meta['sizes']['thumbnail'] ) && $thumb = $meta['sizes']['thumbnail'] ) {
$return->thumbnail = path_join( dirname($file_url), $thumb['file'] );
} else {
$return->thumbnail = "$file_url?w=128&h=128";
}
}
}
} else {
$delete = true;
}
if ( $delete ) {
wp_delete_file( $new_path );
}
$return->msg = esc_js( __('Image saved') );
return $return;
}

View File

@@ -0,0 +1,615 @@
<?php
/**
* File contains all the administration image manipulation functions.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Crop an Image to a given size.
*
* @since 2.1.0
*
* @param string|int $src The source file or Attachment ID.
* @param int $src_x The start x position to crop from.
* @param int $src_y The start y position to crop from.
* @param int $src_w The width to crop.
* @param int $src_h The height to crop.
* @param int $dst_w The destination width.
* @param int $dst_h The destination height.
* @param int $src_abs Optional. If the source crop points are absolute.
* @param string $dst_file Optional. The destination file to write to.
* @return string|WP_Error New filepath on success, WP_Error on failure.
*/
function wp_crop_image( $src, $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs = false, $dst_file = false ) {
$src_file = $src;
if ( is_numeric( $src ) ) { // Handle int as attachment ID
$src_file = get_attached_file( $src );
if ( ! file_exists( $src_file ) ) {
// If the file doesn't exist, attempt a URL fopen on the src link.
// This can occur with certain file replication plugins.
$src = _load_image_to_edit_path( $src, 'full' );
} else {
$src = $src_file;
}
}
$editor = wp_get_image_editor( $src );
if ( is_wp_error( $editor ) )
return $editor;
$src = $editor->crop( $src_x, $src_y, $src_w, $src_h, $dst_w, $dst_h, $src_abs );
if ( is_wp_error( $src ) )
return $src;
if ( ! $dst_file )
$dst_file = str_replace( basename( $src_file ), 'cropped-' . basename( $src_file ), $src_file );
/*
* The directory containing the original file may no longer exist when
* using a replication plugin.
*/
wp_mkdir_p( dirname( $dst_file ) );
$dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
$result = $editor->save( $dst_file );
if ( is_wp_error( $result ) )
return $result;
return $dst_file;
}
/**
* Generate post thumbnail attachment meta data.
*
* @since 2.1.0
*
* @global array $_wp_additional_image_sizes
*
* @param int $attachment_id Attachment Id to process.
* @param string $file Filepath of the Attached image.
* @return mixed Metadata for attachment.
*/
function wp_generate_attachment_metadata( $attachment_id, $file ) {
$attachment = get_post( $attachment_id );
$metadata = array();
$support = false;
if ( preg_match('!^image/!', get_post_mime_type( $attachment )) && file_is_displayable_image($file) ) {
$imagesize = getimagesize( $file );
$metadata['width'] = $imagesize[0];
$metadata['height'] = $imagesize[1];
// Make the file path relative to the upload dir.
$metadata['file'] = _wp_relative_upload_path($file);
// Make thumbnails and other intermediate sizes.
global $_wp_additional_image_sizes;
$sizes = array();
foreach ( get_intermediate_image_sizes() as $s ) {
$sizes[$s] = array( 'width' => '', 'height' => '', 'crop' => false );
if ( isset( $_wp_additional_image_sizes[$s]['width'] ) )
$sizes[$s]['width'] = intval( $_wp_additional_image_sizes[$s]['width'] ); // For theme-added sizes
else
$sizes[$s]['width'] = get_option( "{$s}_size_w" ); // For default sizes set in options
if ( isset( $_wp_additional_image_sizes[$s]['height'] ) )
$sizes[$s]['height'] = intval( $_wp_additional_image_sizes[$s]['height'] ); // For theme-added sizes
else
$sizes[$s]['height'] = get_option( "{$s}_size_h" ); // For default sizes set in options
if ( isset( $_wp_additional_image_sizes[$s]['crop'] ) )
$sizes[$s]['crop'] = $_wp_additional_image_sizes[$s]['crop']; // For theme-added sizes
else
$sizes[$s]['crop'] = get_option( "{$s}_crop" ); // For default sizes set in options
}
/**
* Filter the image sizes automatically generated when uploading an image.
*
* @since 2.9.0
* @since 4.4.0 Added the `$metadata` argument.
*
* @param array $sizes An associative array of image sizes.
* @param array $metadata An associative array of image metadata: width, height, file.
*/
$sizes = apply_filters( 'intermediate_image_sizes_advanced', $sizes, $metadata );
if ( $sizes ) {
$editor = wp_get_image_editor( $file );
if ( ! is_wp_error( $editor ) )
$metadata['sizes'] = $editor->multi_resize( $sizes );
} else {
$metadata['sizes'] = array();
}
// Fetch additional metadata from EXIF/IPTC.
$image_meta = wp_read_image_metadata( $file );
if ( $image_meta )
$metadata['image_meta'] = $image_meta;
} elseif ( wp_attachment_is( 'video', $attachment ) ) {
$metadata = wp_read_video_metadata( $file );
$support = current_theme_supports( 'post-thumbnails', 'attachment:video' ) || post_type_supports( 'attachment:video', 'thumbnail' );
} elseif ( wp_attachment_is( 'audio', $attachment ) ) {
$metadata = wp_read_audio_metadata( $file );
$support = current_theme_supports( 'post-thumbnails', 'attachment:audio' ) || post_type_supports( 'attachment:audio', 'thumbnail' );
}
if ( $support && ! empty( $metadata['image']['data'] ) ) {
// Check for existing cover.
$hash = md5( $metadata['image']['data'] );
$posts = get_posts( array(
'fields' => 'ids',
'post_type' => 'attachment',
'post_mime_type' => $metadata['image']['mime'],
'post_status' => 'inherit',
'posts_per_page' => 1,
'meta_key' => '_cover_hash',
'meta_value' => $hash
) );
$exists = reset( $posts );
if ( ! empty( $exists ) ) {
update_post_meta( $attachment_id, '_thumbnail_id', $exists );
} else {
$ext = '.jpg';
switch ( $metadata['image']['mime'] ) {
case 'image/gif':
$ext = '.gif';
break;
case 'image/png':
$ext = '.png';
break;
}
$basename = str_replace( '.', '-', basename( $file ) ) . '-image' . $ext;
$uploaded = wp_upload_bits( $basename, '', $metadata['image']['data'] );
if ( false === $uploaded['error'] ) {
$image_attachment = array(
'post_mime_type' => $metadata['image']['mime'],
'post_type' => 'attachment',
'post_content' => '',
);
/**
* Filter the parameters for the attachment thumbnail creation.
*
* @since 3.9.0
*
* @param array $image_attachment An array of parameters to create the thumbnail.
* @param array $metadata Current attachment metadata.
* @param array $uploaded An array containing the thumbnail path and url.
*/
$image_attachment = apply_filters( 'attachment_thumbnail_args', $image_attachment, $metadata, $uploaded );
$sub_attachment_id = wp_insert_attachment( $image_attachment, $uploaded['file'] );
add_post_meta( $sub_attachment_id, '_cover_hash', $hash );
$attach_data = wp_generate_attachment_metadata( $sub_attachment_id, $uploaded['file'] );
wp_update_attachment_metadata( $sub_attachment_id, $attach_data );
update_post_meta( $attachment_id, '_thumbnail_id', $sub_attachment_id );
}
}
}
// Remove the blob of binary data from the array.
if ( $metadata ) {
unset( $metadata['image']['data'] );
}
/**
* Filter the generated attachment meta data.
*
* @since 2.1.0
*
* @param array $metadata An array of attachment meta data.
* @param int $attachment_id Current attachment ID.
*/
return apply_filters( 'wp_generate_attachment_metadata', $metadata, $attachment_id );
}
/**
* Convert a fraction string to a decimal.
*
* @since 2.5.0
*
* @param string $str
* @return int|float
*/
function wp_exif_frac2dec($str) {
@list( $n, $d ) = explode( '/', $str );
if ( !empty($d) )
return $n / $d;
return $str;
}
/**
* Convert the exif date format to a unix timestamp.
*
* @since 2.5.0
*
* @param string $str
* @return int
*/
function wp_exif_date2ts($str) {
@list( $date, $time ) = explode( ' ', trim($str) );
@list( $y, $m, $d ) = explode( ':', $date );
return strtotime( "{$y}-{$m}-{$d} {$time}" );
}
/**
* Get extended image metadata, exif or iptc as available.
*
* Retrieves the EXIF metadata aperture, credit, camera, caption, copyright, iso
* created_timestamp, focal_length, shutter_speed, and title.
*
* The IPTC metadata that is retrieved is APP13, credit, byline, created date
* and time, caption, copyright, and title. Also includes FNumber, Model,
* DateTimeDigitized, FocalLength, ISOSpeedRatings, and ExposureTime.
*
* @todo Try other exif libraries if available.
* @since 2.5.0
*
* @param string $file
* @return bool|array False on failure. Image metadata array on success.
*/
function wp_read_image_metadata( $file ) {
if ( ! file_exists( $file ) )
return false;
list( , , $sourceImageType ) = getimagesize( $file );
/*
* EXIF contains a bunch of data we'll probably never need formatted in ways
* that are difficult to use. We'll normalize it and just extract the fields
* that are likely to be useful. Fractions and numbers are converted to
* floats, dates to unix timestamps, and everything else to strings.
*/
$meta = array(
'aperture' => 0,
'credit' => '',
'camera' => '',
'caption' => '',
'created_timestamp' => 0,
'copyright' => '',
'focal_length' => 0,
'iso' => 0,
'shutter_speed' => 0,
'title' => '',
'orientation' => 0,
'keywords' => array(),
);
$iptc = array();
/*
* Read IPTC first, since it might contain data not available in exif such
* as caption, description etc.
*/
if ( is_callable( 'iptcparse' ) ) {
getimagesize( $file, $info );
if ( ! empty( $info['APP13'] ) ) {
$iptc = iptcparse( $info['APP13'] );
// Headline, "A brief synopsis of the caption."
if ( ! empty( $iptc['2#105'][0] ) ) {
$meta['title'] = trim( $iptc['2#105'][0] );
/*
* Title, "Many use the Title field to store the filename of the image,
* though the field may be used in many ways."
*/
} elseif ( ! empty( $iptc['2#005'][0] ) ) {
$meta['title'] = trim( $iptc['2#005'][0] );
}
if ( ! empty( $iptc['2#120'][0] ) ) { // description / legacy caption
$caption = trim( $iptc['2#120'][0] );
mbstring_binary_safe_encoding();
$caption_length = strlen( $caption );
reset_mbstring_encoding();
if ( empty( $meta['title'] ) && $caption_length < 80 ) {
// Assume the title is stored in 2:120 if it's short.
$meta['title'] = $caption;
}
$meta['caption'] = $caption;
}
if ( ! empty( $iptc['2#110'][0] ) ) // credit
$meta['credit'] = trim( $iptc['2#110'][0] );
elseif ( ! empty( $iptc['2#080'][0] ) ) // creator / legacy byline
$meta['credit'] = trim( $iptc['2#080'][0] );
if ( ! empty( $iptc['2#055'][0] ) && ! empty( $iptc['2#060'][0] ) ) // created date and time
$meta['created_timestamp'] = strtotime( $iptc['2#055'][0] . ' ' . $iptc['2#060'][0] );
if ( ! empty( $iptc['2#116'][0] ) ) // copyright
$meta['copyright'] = trim( $iptc['2#116'][0] );
if ( ! empty( $iptc['2#025'][0] ) ) { // keywords array
$meta['keywords'] = array_values( $iptc['2#025'] );
}
}
}
/**
* Filter the image types to check for exif data.
*
* @since 2.5.0
*
* @param array $image_types Image types to check for exif data.
*/
if ( is_callable( 'exif_read_data' ) && in_array( $sourceImageType, apply_filters( 'wp_read_image_metadata_types', array( IMAGETYPE_JPEG, IMAGETYPE_TIFF_II, IMAGETYPE_TIFF_MM ) ) ) ) {
$exif = @exif_read_data( $file );
if ( ! empty( $exif['ImageDescription'] ) ) {
mbstring_binary_safe_encoding();
$description_length = strlen( $exif['ImageDescription'] );
reset_mbstring_encoding();
if ( empty( $meta['title'] ) && $description_length < 80 ) {
// Assume the title is stored in ImageDescription
$meta['title'] = trim( $exif['ImageDescription'] );
}
if ( empty( $meta['caption'] ) && ! empty( $exif['COMPUTED']['UserComment'] ) ) {
$meta['caption'] = trim( $exif['COMPUTED']['UserComment'] );
}
if ( empty( $meta['caption'] ) ) {
$meta['caption'] = trim( $exif['ImageDescription'] );
}
} elseif ( empty( $meta['caption'] ) && ! empty( $exif['Comments'] ) ) {
$meta['caption'] = trim( $exif['Comments'] );
}
if ( empty( $meta['credit'] ) ) {
if ( ! empty( $exif['Artist'] ) ) {
$meta['credit'] = trim( $exif['Artist'] );
} elseif ( ! empty($exif['Author'] ) ) {
$meta['credit'] = trim( $exif['Author'] );
}
}
if ( empty( $meta['copyright'] ) && ! empty( $exif['Copyright'] ) ) {
$meta['copyright'] = trim( $exif['Copyright'] );
}
if ( ! empty( $exif['FNumber'] ) ) {
$meta['aperture'] = round( wp_exif_frac2dec( $exif['FNumber'] ), 2 );
}
if ( ! empty( $exif['Model'] ) ) {
$meta['camera'] = trim( $exif['Model'] );
}
if ( empty( $meta['created_timestamp'] ) && ! empty( $exif['DateTimeDigitized'] ) ) {
$meta['created_timestamp'] = wp_exif_date2ts( $exif['DateTimeDigitized'] );
}
if ( ! empty( $exif['FocalLength'] ) ) {
$meta['focal_length'] = (string) wp_exif_frac2dec( $exif['FocalLength'] );
}
if ( ! empty( $exif['ISOSpeedRatings'] ) ) {
$meta['iso'] = is_array( $exif['ISOSpeedRatings'] ) ? reset( $exif['ISOSpeedRatings'] ) : $exif['ISOSpeedRatings'];
$meta['iso'] = trim( $meta['iso'] );
}
if ( ! empty( $exif['ExposureTime'] ) ) {
$meta['shutter_speed'] = (string) wp_exif_frac2dec( $exif['ExposureTime'] );
}
if ( ! empty( $exif['Orientation'] ) ) {
$meta['orientation'] = $exif['Orientation'];
}
}
foreach ( array( 'title', 'caption', 'credit', 'copyright', 'camera', 'iso' ) as $key ) {
if ( $meta[ $key ] && ! seems_utf8( $meta[ $key ] ) ) {
$meta[ $key ] = utf8_encode( $meta[ $key ] );
}
}
foreach ( $meta['keywords'] as $key => $keyword ) {
if ( ! seems_utf8( $keyword ) ) {
$meta['keywords'][ $key ] = utf8_encode( $keyword );
}
}
$meta = wp_kses_post_deep( $meta );
/**
* Filter the array of meta data read from an image's exif data.
*
* @since 2.5.0
* @since 4.4.0 The `$iptc` parameter was added.
*
* @param array $meta Image meta data.
* @param string $file Path to image file.
* @param int $sourceImageType Type of image.
* @param array $iptc IPTC data.
*/
return apply_filters( 'wp_read_image_metadata', $meta, $file, $sourceImageType, $iptc );
}
/**
* Validate that file is an image.
*
* @since 2.5.0
*
* @param string $path File path to test if valid image.
* @return bool True if valid image, false if not valid image.
*/
function file_is_valid_image($path) {
$size = @getimagesize($path);
return !empty($size);
}
/**
* Validate that file is suitable for displaying within a web page.
*
* @since 2.5.0
*
* @param string $path File path to test.
* @return bool True if suitable, false if not suitable.
*/
function file_is_displayable_image($path) {
$displayable_image_types = array( IMAGETYPE_GIF, IMAGETYPE_JPEG, IMAGETYPE_PNG, IMAGETYPE_BMP );
$info = @getimagesize( $path );
if ( empty( $info ) ) {
$result = false;
} elseif ( ! in_array( $info[2], $displayable_image_types ) ) {
$result = false;
} else {
$result = true;
}
/**
* Filter whether the current image is displayable in the browser.
*
* @since 2.5.0
*
* @param bool $result Whether the image can be displayed. Default true.
* @param string $path Path to the image.
*/
return apply_filters( 'file_is_displayable_image', $result, $path );
}
/**
* Load an image resource for editing.
*
* @since 2.9.0
*
* @param string $attachment_id Attachment ID.
* @param string $mime_type Image mime type.
* @param string $size Optional. Image size, defaults to 'full'.
* @return resource|false The resulting image resource on success, false on failure.
*/
function load_image_to_edit( $attachment_id, $mime_type, $size = 'full' ) {
$filepath = _load_image_to_edit_path( $attachment_id, $size );
if ( empty( $filepath ) )
return false;
switch ( $mime_type ) {
case 'image/jpeg':
$image = imagecreatefromjpeg($filepath);
break;
case 'image/png':
$image = imagecreatefrompng($filepath);
break;
case 'image/gif':
$image = imagecreatefromgif($filepath);
break;
default:
$image = false;
break;
}
if ( is_resource($image) ) {
/**
* Filter the current image being loaded for editing.
*
* @since 2.9.0
*
* @param resource $image Current image.
* @param string $attachment_id Attachment ID.
* @param string $size Image size.
*/
$image = apply_filters( 'load_image_to_edit', $image, $attachment_id, $size );
if ( function_exists('imagealphablending') && function_exists('imagesavealpha') ) {
imagealphablending($image, false);
imagesavealpha($image, true);
}
}
return $image;
}
/**
* Retrieve the path or url of an attachment's attached file.
*
* If the attached file is not present on the local filesystem (usually due to replication plugins),
* then the url of the file is returned if url fopen is supported.
*
* @since 3.4.0
* @access private
*
* @param string $attachment_id Attachment ID.
* @param string $size Optional. Image size, defaults to 'full'.
* @return string|false File path or url on success, false on failure.
*/
function _load_image_to_edit_path( $attachment_id, $size = 'full' ) {
$filepath = get_attached_file( $attachment_id );
if ( $filepath && file_exists( $filepath ) ) {
if ( 'full' != $size && ( $data = image_get_intermediate_size( $attachment_id, $size ) ) ) {
/**
* Filter the path to the current image.
*
* The filter is evaluated for all image sizes except 'full'.
*
* @since 3.1.0
*
* @param string $path Path to the current image.
* @param string $attachment_id Attachment ID.
* @param string $size Size of the image.
*/
$filepath = apply_filters( 'load_image_to_edit_filesystempath', path_join( dirname( $filepath ), $data['file'] ), $attachment_id, $size );
}
} elseif ( function_exists( 'fopen' ) && function_exists( 'ini_get' ) && true == ini_get( 'allow_url_fopen' ) ) {
/**
* Filter the image URL if not in the local filesystem.
*
* The filter is only evaluated if fopen is enabled on the server.
*
* @since 3.1.0
*
* @param string $image_url Current image URL.
* @param string $attachment_id Attachment ID.
* @param string $size Size of the image.
*/
$filepath = apply_filters( 'load_image_to_edit_attachmenturl', wp_get_attachment_url( $attachment_id ), $attachment_id, $size );
}
/**
* Filter the returned path or URL of the current image.
*
* @since 2.9.0
*
* @param string|bool $filepath File path or URL to current image, or false.
* @param string $attachment_id Attachment ID.
* @param string $size Size of the image.
*/
return apply_filters( 'load_image_to_edit_path', $filepath, $attachment_id, $size );
}
/**
* Copy an existing image file.
*
* @since 3.4.0
* @access private
*
* @param string $attachment_id Attachment ID.
* @return string|false New file path on success, false on failure.
*/
function _copy_image_file( $attachment_id ) {
$dst_file = $src_file = get_attached_file( $attachment_id );
if ( ! file_exists( $src_file ) )
$src_file = _load_image_to_edit_path( $attachment_id );
if ( $src_file ) {
$dst_file = str_replace( basename( $dst_file ), 'copy-' . basename( $dst_file ), $dst_file );
$dst_file = dirname( $dst_file ) . '/' . wp_unique_filename( dirname( $dst_file ), basename( $dst_file ) );
/*
* The directory containing the original file may no longer
* exist when using a replication plugin.
*/
wp_mkdir_p( dirname( $dst_file ) );
if ( ! @copy( $src_file, $dst_file ) )
$dst_file = false;
} else {
$dst_file = false;
}
return $dst_file;
}

View File

@@ -0,0 +1,207 @@
<?php
/**
* WordPress Administration Importer API.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Retrieve list of importers.
*
* @since 2.0.0
*
* @global array $wp_importers
* @return array
*/
function get_importers() {
global $wp_importers;
if ( is_array( $wp_importers ) ) {
uasort( $wp_importers, '_usort_by_first_member' );
}
return $wp_importers;
}
/**
* Sorts a multidimensional array by first member of each top level member
*
* Used by uasort() as a callback, should not be used directly.
*
* @since 2.9.0
* @access private
*
* @param array $a
* @param array $b
* @return int
*/
function _usort_by_first_member( $a, $b ) {
return strnatcasecmp( $a[0], $b[0] );
}
/**
* Register importer for WordPress.
*
* @since 2.0.0
*
* @global array $wp_importers
*
* @param string $id Importer tag. Used to uniquely identify importer.
* @param string $name Importer name and title.
* @param string $description Importer description.
* @param callable $callback Callback to run.
* @return WP_Error Returns WP_Error when $callback is WP_Error.
*/
function register_importer( $id, $name, $description, $callback ) {
global $wp_importers;
if ( is_wp_error( $callback ) )
return $callback;
$wp_importers[$id] = array ( $name, $description, $callback );
}
/**
* Cleanup importer.
*
* Removes attachment based on ID.
*
* @since 2.0.0
*
* @param string $id Importer ID.
*/
function wp_import_cleanup( $id ) {
wp_delete_attachment( $id );
}
/**
* Handle importer uploading and add attachment.
*
* @since 2.0.0
*
* @return array Uploaded file's details on success, error message on failure
*/
function wp_import_handle_upload() {
if ( ! isset( $_FILES['import'] ) ) {
return array(
'error' => __( 'File is empty. Please upload something more substantial. This error could also be caused by uploads being disabled in your php.ini or by post_max_size being defined as smaller than upload_max_filesize in php.ini.' )
);
}
$overrides = array( 'test_form' => false, 'test_type' => false );
$_FILES['import']['name'] .= '.txt';
$upload = wp_handle_upload( $_FILES['import'], $overrides );
if ( isset( $upload['error'] ) ) {
return $upload;
}
// Construct the object array
$object = array(
'post_title' => basename( $upload['file'] ),
'post_content' => $upload['url'],
'post_mime_type' => $upload['type'],
'guid' => $upload['url'],
'context' => 'import',
'post_status' => 'private'
);
// Save the data
$id = wp_insert_attachment( $object, $upload['file'] );
/*
* Schedule a cleanup for one day from now in case of failed
* import or missing wp_import_cleanup() call.
*/
wp_schedule_single_event( time() + DAY_IN_SECONDS, 'importer_scheduled_cleanup', array( $id ) );
return array( 'file' => $upload['file'], 'id' => $id );
}
/**
* Returns a list from WordPress.org of popular importer plugins.
*
* @since 3.5.0
*
* @return array Importers with metadata for each.
*/
function wp_get_popular_importers() {
include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version
$locale = get_locale();
$popular_importers = get_site_transient( 'popular_importers_' . $locale );
if ( ! $popular_importers ) {
$url = add_query_arg( 'locale', get_locale(), 'http://api.wordpress.org/core/importers/1.1/' );
$options = array( 'user-agent' => 'WordPress/' . $wp_version . '; ' . home_url() );
$response = wp_remote_get( $url, $options );
$popular_importers = json_decode( wp_remote_retrieve_body( $response ), true );
if ( is_array( $popular_importers ) )
set_site_transient( 'popular_importers_' . $locale, $popular_importers, 2 * DAY_IN_SECONDS );
else
$popular_importers = false;
}
if ( is_array( $popular_importers ) ) {
// If the data was received as translated, return it as-is.
if ( $popular_importers['translated'] )
return $popular_importers['importers'];
foreach ( $popular_importers['importers'] as &$importer ) {
$importer['description'] = translate( $importer['description'] );
if ( $importer['name'] != 'WordPress' )
$importer['name'] = translate( $importer['name'] );
}
return $popular_importers['importers'];
}
return array(
// slug => name, description, plugin slug, and register_importer() slug
'blogger' => array(
'name' => __( 'Blogger' ),
'description' => __( 'Install the Blogger importer to import posts, comments, and users from a Blogger blog.' ),
'plugin-slug' => 'blogger-importer',
'importer-id' => 'blogger',
),
'wpcat2tag' => array(
'name' => __( 'Categories and Tags Converter' ),
'description' => __( 'Install the category/tag converter to convert existing categories to tags or tags to categories, selectively.' ),
'plugin-slug' => 'wpcat2tag-importer',
'importer-id' => 'wp-cat2tag',
),
'livejournal' => array(
'name' => __( 'LiveJournal' ),
'description' => __( 'Install the LiveJournal importer to import posts from LiveJournal using their API.' ),
'plugin-slug' => 'livejournal-importer',
'importer-id' => 'livejournal',
),
'movabletype' => array(
'name' => __( 'Movable Type and TypePad' ),
'description' => __( 'Install the Movable Type importer to import posts and comments from a Movable Type or TypePad blog.' ),
'plugin-slug' => 'movabletype-importer',
'importer-id' => 'mt',
),
'opml' => array(
'name' => __( 'Blogroll' ),
'description' => __( 'Install the blogroll importer to import links in OPML format.' ),
'plugin-slug' => 'opml-importer',
'importer-id' => 'opml',
),
'rss' => array(
'name' => __( 'RSS' ),
'description' => __( 'Install the RSS importer to import posts from an RSS feed.' ),
'plugin-slug' => 'rss-importer',
'importer-id' => 'rss',
),
'tumblr' => array(
'name' => __( 'Tumblr' ),
'description' => __( 'Install the Tumblr importer to import posts &amp; media from Tumblr using their API.' ),
'plugin-slug' => 'tumblr-importer',
'importer-id' => 'tumblr',
),
'wordpress' => array(
'name' => 'WordPress',
'description' => __( 'Install the WordPress importer to import posts, pages, comments, custom fields, categories, and tags from a WordPress export file.' ),
'plugin-slug' => 'wordpress-importer',
'importer-id' => 'wordpress',
),
);
}

View File

@@ -0,0 +1,129 @@
<?php
/**
* Helper functions for displaying a list of items in an ajaxified HTML table.
*
* @package WordPress
* @subpackage List_Table
* @since 3.1.0
*/
/**
* Fetch an instance of a WP_List_Table class.
*
* @access private
* @since 3.1.0
*
* @global string $hook_suffix
*
* @param string $class The type of the list table, which is the class name.
* @param array $args Optional. Arguments to pass to the class. Accepts 'screen'.
* @return object|bool Object on success, false if the class does not exist.
*/
function _get_list_table( $class, $args = array() ) {
$core_classes = array(
//Site Admin
'WP_Posts_List_Table' => 'posts',
'WP_Media_List_Table' => 'media',
'WP_Terms_List_Table' => 'terms',
'WP_Users_List_Table' => 'users',
'WP_Comments_List_Table' => 'comments',
'WP_Post_Comments_List_Table' => array( 'comments', 'post-comments' ),
'WP_Links_List_Table' => 'links',
'WP_Plugin_Install_List_Table' => 'plugin-install',
'WP_Themes_List_Table' => 'themes',
'WP_Theme_Install_List_Table' => array( 'themes', 'theme-install' ),
'WP_Plugins_List_Table' => 'plugins',
// Network Admin
'WP_MS_Sites_List_Table' => 'ms-sites',
'WP_MS_Users_List_Table' => 'ms-users',
'WP_MS_Themes_List_Table' => 'ms-themes',
);
if ( isset( $core_classes[ $class ] ) ) {
foreach ( (array) $core_classes[ $class ] as $required )
require_once( ABSPATH . 'wp-admin/includes/class-wp-' . $required . '-list-table.php' );
if ( isset( $args['screen'] ) )
$args['screen'] = convert_to_screen( $args['screen'] );
elseif ( isset( $GLOBALS['hook_suffix'] ) )
$args['screen'] = get_current_screen();
else
$args['screen'] = null;
return new $class( $args );
}
return false;
}
/**
* Register column headers for a particular screen.
*
* @since 2.7.0
*
* @param string $screen The handle for the screen to add help to. This is usually the hook name returned by the add_*_page() functions.
* @param array $columns An array of columns with column IDs as the keys and translated column names as the values
* @see get_column_headers(), print_column_headers(), get_hidden_columns()
*/
function register_column_headers($screen, $columns) {
$wp_list_table = new _WP_List_Table_Compat($screen, $columns);
}
/**
* Prints column headers for a particular screen.
*
* @since 2.7.0
*
* @param string|WP_Screen $screen The screen hook name or screen object.
* @param bool $with_id Whether to set the id attribute or not.
*/
function print_column_headers( $screen, $with_id = true ) {
$wp_list_table = new _WP_List_Table_Compat($screen);
$wp_list_table->print_column_headers( $with_id );
}
/**
* Helper class to be used only by back compat functions
*
* @since 3.1.0
*/
class _WP_List_Table_Compat extends WP_List_Table {
public $_screen;
public $_columns;
public function __construct( $screen, $columns = array() ) {
if ( is_string( $screen ) )
$screen = convert_to_screen( $screen );
$this->_screen = $screen;
if ( !empty( $columns ) ) {
$this->_columns = $columns;
add_filter( 'manage_' . $screen->id . '_columns', array( $this, 'get_columns' ), 0 );
}
}
/**
* @access protected
*
* @return array
*/
protected function get_column_info() {
$columns = get_column_headers( $this->_screen );
$hidden = get_hidden_columns( $this->_screen );
$sortable = array();
$primary = $this->get_default_primary_column_name();
return array( $columns, $hidden, $sortable, $primary );
}
/**
* @access public
*
* @return array
*/
public function get_columns() {
return $this->_columns;
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,345 @@
<?php
/**
* Build Administration Menu.
*
* @package WordPress
* @subpackage Administration
*/
if ( is_network_admin() ) {
/**
* Fires before the administration menu loads in the Network Admin.
*
* The hook fires before menus and sub-menus are removed based on user privileges.
*
* @private
* @since 3.1.0
*/
do_action( '_network_admin_menu' );
} elseif ( is_user_admin() ) {
/**
* Fires before the administration menu loads in the User Admin.
*
* The hook fires before menus and sub-menus are removed based on user privileges.
*
* @private
* @since 3.1.0
*/
do_action( '_user_admin_menu' );
} else {
/**
* Fires before the administration menu loads in the admin.
*
* The hook fires before menus and sub-menus are removed based on user privileges.
*
* @private
* @since 2.2.0
*/
do_action( '_admin_menu' );
}
// Create list of page plugin hook names.
foreach ($menu as $menu_page) {
if ( false !== $pos = strpos($menu_page[2], '?') ) {
// Handle post_type=post|page|foo pages.
$hook_name = substr($menu_page[2], 0, $pos);
$hook_args = substr($menu_page[2], $pos + 1);
wp_parse_str($hook_args, $hook_args);
// Set the hook name to be the post type.
if ( isset($hook_args['post_type']) )
$hook_name = $hook_args['post_type'];
else
$hook_name = basename($hook_name, '.php');
unset($hook_args);
} else {
$hook_name = basename($menu_page[2], '.php');
}
$hook_name = sanitize_title($hook_name);
if ( isset($compat[$hook_name]) )
$hook_name = $compat[$hook_name];
elseif ( !$hook_name )
continue;
$admin_page_hooks[$menu_page[2]] = $hook_name;
}
unset($menu_page, $compat);
$_wp_submenu_nopriv = array();
$_wp_menu_nopriv = array();
// Loop over submenus and remove pages for which the user does not have privs.
foreach ($submenu as $parent => $sub) {
foreach ($sub as $index => $data) {
if ( ! current_user_can($data[1]) ) {
unset($submenu[$parent][$index]);
$_wp_submenu_nopriv[$parent][$data[2]] = true;
}
}
unset($index, $data);
if ( empty($submenu[$parent]) )
unset($submenu[$parent]);
}
unset($sub, $parent);
/*
* Loop over the top-level menu.
* Menus for which the original parent is not accessible due to lack of privileges
* will have the next submenu in line be assigned as the new menu parent.
*/
foreach ( $menu as $id => $data ) {
if ( empty($submenu[$data[2]]) )
continue;
$subs = $submenu[$data[2]];
$first_sub = reset( $subs );
$old_parent = $data[2];
$new_parent = $first_sub[2];
/*
* If the first submenu is not the same as the assigned parent,
* make the first submenu the new parent.
*/
if ( $new_parent != $old_parent ) {
$_wp_real_parent_file[$old_parent] = $new_parent;
$menu[$id][2] = $new_parent;
foreach ($submenu[$old_parent] as $index => $data) {
$submenu[$new_parent][$index] = $submenu[$old_parent][$index];
unset($submenu[$old_parent][$index]);
}
unset($submenu[$old_parent], $index);
if ( isset($_wp_submenu_nopriv[$old_parent]) )
$_wp_submenu_nopriv[$new_parent] = $_wp_submenu_nopriv[$old_parent];
}
}
unset($id, $data, $subs, $first_sub, $old_parent, $new_parent);
if ( is_network_admin() ) {
/**
* Fires before the administration menu loads in the Network Admin.
*
* @since 3.1.0
*
* @param string $context Empty context.
*/
do_action( 'network_admin_menu', '' );
} elseif ( is_user_admin() ) {
/**
* Fires before the administration menu loads in the User Admin.
*
* @since 3.1.0
*
* @param string $context Empty context.
*/
do_action( 'user_admin_menu', '' );
} else {
/**
* Fires before the administration menu loads in the admin.
*
* @since 1.5.0
*
* @param string $context Empty context.
*/
do_action( 'admin_menu', '' );
}
/*
* Remove menus that have no accessible submenus and require privileges
* that the user does not have. Run re-parent loop again.
*/
foreach ( $menu as $id => $data ) {
if ( ! current_user_can($data[1]) )
$_wp_menu_nopriv[$data[2]] = true;
/*
* If there is only one submenu and it is has same destination as the parent,
* remove the submenu.
*/
if ( ! empty( $submenu[$data[2]] ) && 1 == count ( $submenu[$data[2]] ) ) {
$subs = $submenu[$data[2]];
$first_sub = reset( $subs );
if ( $data[2] == $first_sub[2] )
unset( $submenu[$data[2]] );
}
// If submenu is empty...
if ( empty($submenu[$data[2]]) ) {
// And user doesn't have privs, remove menu.
if ( isset( $_wp_menu_nopriv[$data[2]] ) ) {
unset($menu[$id]);
}
}
}
unset($id, $data, $subs, $first_sub);
/**
*
* @param string $add
* @param string $class
* @return string
*/
function add_cssclass($add, $class) {
$class = empty($class) ? $add : $class .= ' ' . $add;
return $class;
}
/**
*
* @param array $menu
* @return array
*/
function add_menu_classes($menu) {
$first = $lastorder = false;
$i = 0;
$mc = count($menu);
foreach ( $menu as $order => $top ) {
$i++;
if ( 0 == $order ) { // dashboard is always shown/single
$menu[0][4] = add_cssclass('menu-top-first', $top[4]);
$lastorder = 0;
continue;
}
if ( 0 === strpos($top[2], 'separator') && false !== $lastorder ) { // if separator
$first = true;
$c = $menu[$lastorder][4];
$menu[$lastorder][4] = add_cssclass('menu-top-last', $c);
continue;
}
if ( $first ) {
$c = $menu[$order][4];
$menu[$order][4] = add_cssclass('menu-top-first', $c);
$first = false;
}
if ( $mc == $i ) { // last item
$c = $menu[$order][4];
$menu[$order][4] = add_cssclass('menu-top-last', $c);
}
$lastorder = $order;
}
/**
* Filter administration menus array with classes added for top-level items.
*
* @since 2.7.0
*
* @param array $menu Associative array of administration menu items.
*/
return apply_filters( 'add_menu_classes', $menu );
}
uksort($menu, "strnatcasecmp"); // make it all pretty
/**
* Filter whether to enable custom ordering of the administration menu.
*
* See the {@see 'menu_order'} filter for reordering menu items.
*
* @since 2.8.0
*
* @param bool $custom Whether custom ordering is enabled. Default false.
*/
if ( apply_filters( 'custom_menu_order', false ) ) {
$menu_order = array();
foreach ( $menu as $menu_item ) {
$menu_order[] = $menu_item[2];
}
unset($menu_item);
$default_menu_order = $menu_order;
/**
* Filter the order of administration menu items.
*
* A truthy value must first be passed to the {@see 'custom_menu_order'} filter
* for this filter to work. Use the following to enable custom menu ordering:
*
* add_filter( 'custom_menu_order', '__return_true' );
*
* @since 2.8.0
*
* @param array $menu_order An ordered array of menu items.
*/
$menu_order = apply_filters( 'menu_order', $menu_order );
$menu_order = array_flip($menu_order);
$default_menu_order = array_flip($default_menu_order);
/**
*
* @global array $menu_order
* @global array $default_menu_order
*
* @param array $a
* @param array $b
* @return int
*/
function sort_menu($a, $b) {
global $menu_order, $default_menu_order;
$a = $a[2];
$b = $b[2];
if ( isset($menu_order[$a]) && !isset($menu_order[$b]) ) {
return -1;
} elseif ( !isset($menu_order[$a]) && isset($menu_order[$b]) ) {
return 1;
} elseif ( isset($menu_order[$a]) && isset($menu_order[$b]) ) {
if ( $menu_order[$a] == $menu_order[$b] )
return 0;
return ($menu_order[$a] < $menu_order[$b]) ? -1 : 1;
} else {
return ($default_menu_order[$a] <= $default_menu_order[$b]) ? -1 : 1;
}
}
usort($menu, 'sort_menu');
unset($menu_order, $default_menu_order);
}
// Prevent adjacent separators
$prev_menu_was_separator = false;
foreach ( $menu as $id => $data ) {
if ( false === stristr( $data[4], 'wp-menu-separator' ) ) {
// This item is not a separator, so falsey the toggler and do nothing
$prev_menu_was_separator = false;
} else {
// The previous item was a separator, so unset this one
if ( true === $prev_menu_was_separator ) {
unset( $menu[ $id ] );
}
// This item is a separator, so truthy the toggler and move on
$prev_menu_was_separator = true;
}
}
unset( $id, $data, $prev_menu_was_separator );
// Remove the last menu item if it is a separator.
$last_menu_key = array_keys( $menu );
$last_menu_key = array_pop( $last_menu_key );
if ( !empty( $menu ) && 'wp-menu-separator' == $menu[ $last_menu_key ][ 4 ] )
unset( $menu[ $last_menu_key ] );
unset( $last_menu_key );
if ( !user_can_access_admin_page() ) {
/**
* Fires when access to an admin page is denied.
*
* @since 2.5.0
*/
do_action( 'admin_page_access_denied' );
wp_die( __( 'You do not have sufficient permissions to access this page.' ), 403 );
}
$menu = add_menu_classes($menu);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,938 @@
<?php
/**
* Misc WordPress Administration API.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Returns whether the server is running Apache with the mod_rewrite module loaded.
*
* @since 2.0.0
*
* @return bool
*/
function got_mod_rewrite() {
$got_rewrite = apache_mod_loaded('mod_rewrite', true);
/**
* Filter whether Apache and mod_rewrite are present.
*
* This filter was previously used to force URL rewriting for other servers,
* like nginx. Use the got_url_rewrite filter in got_url_rewrite() instead.
*
* @since 2.5.0
*
* @see got_url_rewrite()
*
* @param bool $got_rewrite Whether Apache and mod_rewrite are present.
*/
return apply_filters( 'got_rewrite', $got_rewrite );
}
/**
* Returns whether the server supports URL rewriting.
*
* Detects Apache's mod_rewrite, IIS 7.0+ permalink support, and nginx.
*
* @since 3.7.0
*
* @global bool $is_nginx
*
* @return bool Whether the server supports URL rewriting.
*/
function got_url_rewrite() {
$got_url_rewrite = ( got_mod_rewrite() || $GLOBALS['is_nginx'] || iis7_supports_permalinks() );
/**
* Filter whether URL rewriting is available.
*
* @since 3.7.0
*
* @param bool $got_url_rewrite Whether URL rewriting is available.
*/
return apply_filters( 'got_url_rewrite', $got_url_rewrite );
}
/**
* Extracts strings from between the BEGIN and END markers in the .htaccess file.
*
* @since 1.5.0
*
* @param string $filename
* @param string $marker
* @return array An array of strings from a file (.htaccess ) from between BEGIN and END markers.
*/
function extract_from_markers( $filename, $marker ) {
$result = array ();
if (!file_exists( $filename ) ) {
return $result;
}
if ( $markerdata = explode( "\n", implode( '', file( $filename ) ) ));
{
$state = false;
foreach ( $markerdata as $markerline ) {
if (strpos($markerline, '# END ' . $marker) !== false)
$state = false;
if ( $state )
$result[] = $markerline;
if (strpos($markerline, '# BEGIN ' . $marker) !== false)
$state = true;
}
}
return $result;
}
/**
* Inserts an array of strings into a file (.htaccess ), placing it between
* BEGIN and END markers.
*
* Replaces existing marked info. Retains surrounding
* data. Creates file if none exists.
*
* @since 1.5.0
*
* @param string $filename Filename to alter.
* @param string $marker The marker to alter.
* @param array|string $insertion The new content to insert.
* @return bool True on write success, false on failure.
*/
function insert_with_markers( $filename, $marker, $insertion ) {
if ( ! file_exists( $filename ) ) {
if ( ! is_writable( dirname( $filename ) ) ) {
return false;
}
if ( ! touch( $filename ) ) {
return false;
}
} elseif ( ! is_writeable( $filename ) ) {
return false;
}
if ( ! is_array( $insertion ) ) {
$insertion = explode( "\n", $insertion );
}
$start_marker = "# BEGIN {$marker}";
$end_marker = "# END {$marker}";
$fp = fopen( $filename, 'r+' );
if ( ! $fp ) {
return false;
}
// Attempt to get a lock. If the filesystem supports locking, this will block until the lock is acquired.
flock( $fp, LOCK_EX );
$lines = array();
while ( ! feof( $fp ) ) {
$lines[] = rtrim( fgets( $fp ), "\r\n" );
}
// Split out the existing file into the preceeding lines, and those that appear after the marker
$pre_lines = $post_lines = $existing_lines = array();
$found_marker = $found_end_marker = false;
foreach ( $lines as $line ) {
if ( ! $found_marker && false !== strpos( $line, $start_marker ) ) {
$found_marker = true;
continue;
} elseif ( ! $found_end_marker && false !== strpos( $line, $end_marker ) ) {
$found_end_marker = true;
continue;
}
if ( ! $found_marker ) {
$pre_lines[] = $line;
} elseif ( $found_marker && $found_end_marker ) {
$post_lines[] = $line;
} else {
$existing_lines[] = $line;
}
}
// Check to see if there was a change
if ( $existing_lines === $insertion ) {
flock( $fp, LOCK_UN );
fclose( $fp );
return true;
}
// Generate the new file data
$new_file_data = implode( "\n", array_merge(
$pre_lines,
array( $start_marker ),
$insertion,
array( $end_marker ),
$post_lines
) );
// Write to the start of the file, and truncate it to that length
fseek( $fp, 0 );
$bytes = fwrite( $fp, $new_file_data );
if ( $bytes ) {
ftruncate( $fp, ftell( $fp ) );
}
fflush( $fp );
flock( $fp, LOCK_UN );
fclose( $fp );
return (bool) $bytes;
}
/**
* Updates the htaccess file with the current rules if it is writable.
*
* Always writes to the file if it exists and is writable to ensure that we
* blank out old rules.
*
* @since 1.5.0
*
* @global WP_Rewrite $wp_rewrite
*/
function save_mod_rewrite_rules() {
if ( is_multisite() )
return;
global $wp_rewrite;
$home_path = get_home_path();
$htaccess_file = $home_path.'.htaccess';
/*
* If the file doesn't already exist check for write access to the directory
* and whether we have some rules. Else check for write access to the file.
*/
if ((!file_exists($htaccess_file) && is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks()) || is_writable($htaccess_file)) {
if ( got_mod_rewrite() ) {
$rules = explode( "\n", $wp_rewrite->mod_rewrite_rules() );
return insert_with_markers( $htaccess_file, 'WordPress', $rules );
}
}
return false;
}
/**
* Updates the IIS web.config file with the current rules if it is writable.
* If the permalinks do not require rewrite rules then the rules are deleted from the web.config file.
*
* @since 2.8.0
*
* @global WP_Rewrite $wp_rewrite
*
* @return bool True if web.config was updated successfully
*/
function iis7_save_url_rewrite_rules(){
if ( is_multisite() )
return;
global $wp_rewrite;
$home_path = get_home_path();
$web_config_file = $home_path . 'web.config';
// Using win_is_writable() instead of is_writable() because of a bug in Windows PHP
if ( iis7_supports_permalinks() && ( ( ! file_exists($web_config_file) && win_is_writable($home_path) && $wp_rewrite->using_mod_rewrite_permalinks() ) || win_is_writable($web_config_file) ) ) {
$rule = $wp_rewrite->iis7_url_rewrite_rules(false, '', '');
if ( ! empty($rule) ) {
return iis7_add_rewrite_rule($web_config_file, $rule);
} else {
return iis7_delete_rewrite_rule($web_config_file);
}
}
return false;
}
/**
* Update the "recently-edited" file for the plugin or theme editor.
*
* @since 1.5.0
*
* @param string $file
*/
function update_recently_edited( $file ) {
$oldfiles = (array ) get_option( 'recently_edited' );
if ( $oldfiles ) {
$oldfiles = array_reverse( $oldfiles );
$oldfiles[] = $file;
$oldfiles = array_reverse( $oldfiles );
$oldfiles = array_unique( $oldfiles );
if ( 5 < count( $oldfiles ))
array_pop( $oldfiles );
} else {
$oldfiles[] = $file;
}
update_option( 'recently_edited', $oldfiles );
}
/**
* Flushes rewrite rules if siteurl, home or page_on_front changed.
*
* @since 2.1.0
*
* @param string $old_value
* @param string $value
*/
function update_home_siteurl( $old_value, $value ) {
if ( wp_installing() )
return;
if ( is_multisite() && ms_is_switched() ) {
delete_option( 'rewrite_rules' );
} else {
flush_rewrite_rules();
}
}
/**
* Resets global variables based on $_GET and $_POST
*
* This function resets global variables based on the names passed
* in the $vars array to the value of $_POST[$var] or $_GET[$var] or ''
* if neither is defined.
*
* @since 2.0.0
*
* @param array $vars An array of globals to reset.
*/
function wp_reset_vars( $vars ) {
foreach ( $vars as $var ) {
if ( empty( $_POST[ $var ] ) ) {
if ( empty( $_GET[ $var ] ) ) {
$GLOBALS[ $var ] = '';
} else {
$GLOBALS[ $var ] = $_GET[ $var ];
}
} else {
$GLOBALS[ $var ] = $_POST[ $var ];
}
}
}
/**
* Displays the given administration message.
*
* @since 2.1.0
*
* @param string|WP_Error $message
*/
function show_message($message) {
if ( is_wp_error($message) ){
if ( $message->get_error_data() && is_string( $message->get_error_data() ) )
$message = $message->get_error_message() . ': ' . $message->get_error_data();
else
$message = $message->get_error_message();
}
echo "<p>$message</p>\n";
wp_ob_end_flush_all();
flush();
}
/**
* @since 2.8.0
*
* @param string $content
* @return array
*/
function wp_doc_link_parse( $content ) {
if ( !is_string( $content ) || empty( $content ) )
return array();
if ( !function_exists('token_get_all') )
return array();
$tokens = token_get_all( $content );
$count = count( $tokens );
$functions = array();
$ignore_functions = array();
for ( $t = 0; $t < $count - 2; $t++ ) {
if ( ! is_array( $tokens[ $t ] ) ) {
continue;
}
if ( T_STRING == $tokens[ $t ][0] && ( '(' == $tokens[ $t + 1 ] || '(' == $tokens[ $t + 2 ] ) ) {
// If it's a function or class defined locally, there's not going to be any docs available
if ( ( isset( $tokens[ $t - 2 ][1] ) && in_array( $tokens[ $t - 2 ][1], array( 'function', 'class' ) ) ) || ( isset( $tokens[ $t - 2 ][0] ) && T_OBJECT_OPERATOR == $tokens[ $t - 1 ][0] ) ) {
$ignore_functions[] = $tokens[$t][1];
}
// Add this to our stack of unique references
$functions[] = $tokens[$t][1];
}
}
$functions = array_unique( $functions );
sort( $functions );
/**
* Filter the list of functions and classes to be ignored from the documentation lookup.
*
* @since 2.8.0
*
* @param array $ignore_functions Functions and classes to be ignored.
*/
$ignore_functions = apply_filters( 'documentation_ignore_functions', $ignore_functions );
$ignore_functions = array_unique( $ignore_functions );
$out = array();
foreach ( $functions as $function ) {
if ( in_array( $function, $ignore_functions ) )
continue;
$out[] = $function;
}
return $out;
}
/**
* Saves option for number of rows when listing posts, pages, comments, etc.
*
* @since 2.8.0
*/
function set_screen_options() {
if ( isset($_POST['wp_screen_options']) && is_array($_POST['wp_screen_options']) ) {
check_admin_referer( 'screen-options-nonce', 'screenoptionnonce' );
if ( !$user = wp_get_current_user() )
return;
$option = $_POST['wp_screen_options']['option'];
$value = $_POST['wp_screen_options']['value'];
if ( $option != sanitize_key( $option ) )
return;
$map_option = $option;
$type = str_replace('edit_', '', $map_option);
$type = str_replace('_per_page', '', $type);
if ( in_array( $type, get_taxonomies() ) )
$map_option = 'edit_tags_per_page';
elseif ( in_array( $type, get_post_types() ) )
$map_option = 'edit_per_page';
else
$option = str_replace('-', '_', $option);
switch ( $map_option ) {
case 'edit_per_page':
case 'users_per_page':
case 'edit_comments_per_page':
case 'upload_per_page':
case 'edit_tags_per_page':
case 'plugins_per_page':
// Network admin
case 'sites_network_per_page':
case 'users_network_per_page':
case 'site_users_network_per_page':
case 'plugins_network_per_page':
case 'themes_network_per_page':
case 'site_themes_network_per_page':
$value = (int) $value;
if ( $value < 1 || $value > 999 )
return;
break;
default:
/**
* Filter a screen option value before it is set.
*
* The filter can also be used to modify non-standard [items]_per_page
* settings. See the parent function for a full list of standard options.
*
* Returning false to the filter will skip saving the current option.
*
* @since 2.8.0
*
* @see set_screen_options()
*
* @param bool|int $value Screen option value. Default false to skip.
* @param string $option The option name.
* @param int $value The number of rows to use.
*/
$value = apply_filters( 'set-screen-option', false, $option, $value );
if ( false === $value )
return;
break;
}
update_user_meta($user->ID, $option, $value);
$url = remove_query_arg( array( 'pagenum', 'apage', 'paged' ), wp_get_referer() );
if ( isset( $_POST['mode'] ) ) {
$url = add_query_arg( array( 'mode' => $_POST['mode'] ), $url );
}
wp_safe_redirect( $url );
exit;
}
}
/**
* Check if rewrite rule for WordPress already exists in the IIS 7+ configuration file
*
* @since 2.8.0
*
* @return bool
* @param string $filename The file path to the configuration file
*/
function iis7_rewrite_rule_exists($filename) {
if ( ! file_exists($filename) )
return false;
if ( ! class_exists( 'DOMDocument', false ) ) {
return false;
}
$doc = new DOMDocument();
if ( $doc->load($filename) === false )
return false;
$xpath = new DOMXPath($doc);
$rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
if ( $rules->length == 0 )
return false;
else
return true;
}
/**
* Delete WordPress rewrite rule from web.config file if it exists there
*
* @since 2.8.0
*
* @param string $filename Name of the configuration file
* @return bool
*/
function iis7_delete_rewrite_rule($filename) {
// If configuration file does not exist then rules also do not exist so there is nothing to delete
if ( ! file_exists($filename) )
return true;
if ( ! class_exists( 'DOMDocument', false ) ) {
return false;
}
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
if ( $doc -> load($filename) === false )
return false;
$xpath = new DOMXPath($doc);
$rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
if ( $rules->length > 0 ) {
$child = $rules->item(0);
$parent = $child->parentNode;
$parent->removeChild($child);
$doc->formatOutput = true;
saveDomDocument($doc, $filename);
}
return true;
}
/**
* Add WordPress rewrite rule to the IIS 7+ configuration file.
*
* @since 2.8.0
*
* @param string $filename The file path to the configuration file
* @param string $rewrite_rule The XML fragment with URL Rewrite rule
* @return bool
*/
function iis7_add_rewrite_rule($filename, $rewrite_rule) {
if ( ! class_exists( 'DOMDocument', false ) ) {
return false;
}
// If configuration file does not exist then we create one.
if ( ! file_exists($filename) ) {
$fp = fopen( $filename, 'w');
fwrite($fp, '<configuration/>');
fclose($fp);
}
$doc = new DOMDocument();
$doc->preserveWhiteSpace = false;
if ( $doc->load($filename) === false )
return false;
$xpath = new DOMXPath($doc);
// First check if the rule already exists as in that case there is no need to re-add it
$wordpress_rules = $xpath->query('/configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'wordpress\')] | /configuration/system.webServer/rewrite/rules/rule[starts-with(@name,\'WordPress\')]');
if ( $wordpress_rules->length > 0 )
return true;
// Check the XPath to the rewrite rule and create XML nodes if they do not exist
$xmlnodes = $xpath->query('/configuration/system.webServer/rewrite/rules');
if ( $xmlnodes->length > 0 ) {
$rules_node = $xmlnodes->item(0);
} else {
$rules_node = $doc->createElement('rules');
$xmlnodes = $xpath->query('/configuration/system.webServer/rewrite');
if ( $xmlnodes->length > 0 ) {
$rewrite_node = $xmlnodes->item(0);
$rewrite_node->appendChild($rules_node);
} else {
$rewrite_node = $doc->createElement('rewrite');
$rewrite_node->appendChild($rules_node);
$xmlnodes = $xpath->query('/configuration/system.webServer');
if ( $xmlnodes->length > 0 ) {
$system_webServer_node = $xmlnodes->item(0);
$system_webServer_node->appendChild($rewrite_node);
} else {
$system_webServer_node = $doc->createElement('system.webServer');
$system_webServer_node->appendChild($rewrite_node);
$xmlnodes = $xpath->query('/configuration');
if ( $xmlnodes->length > 0 ) {
$config_node = $xmlnodes->item(0);
$config_node->appendChild($system_webServer_node);
} else {
$config_node = $doc->createElement('configuration');
$doc->appendChild($config_node);
$config_node->appendChild($system_webServer_node);
}
}
}
}
$rule_fragment = $doc->createDocumentFragment();
$rule_fragment->appendXML($rewrite_rule);
$rules_node->appendChild($rule_fragment);
$doc->encoding = "UTF-8";
$doc->formatOutput = true;
saveDomDocument($doc, $filename);
return true;
}
/**
* Saves the XML document into a file
*
* @since 2.8.0
*
* @param DOMDocument $doc
* @param string $filename
*/
function saveDomDocument($doc, $filename) {
$config = $doc->saveXML();
$config = preg_replace("/([^\r])\n/", "$1\r\n", $config);
$fp = fopen($filename, 'w');
fwrite($fp, $config);
fclose($fp);
}
/**
* Display the default admin color scheme picker (Used in user-edit.php)
*
* @since 3.0.0
*
* @global array $_wp_admin_css_colors
*
* @param int $user_id User ID.
*/
function admin_color_scheme_picker( $user_id ) {
global $_wp_admin_css_colors;
ksort( $_wp_admin_css_colors );
if ( isset( $_wp_admin_css_colors['fresh'] ) ) {
// Set Default ('fresh') and Light should go first.
$_wp_admin_css_colors = array_filter( array_merge( array( 'fresh' => '', 'light' => '' ), $_wp_admin_css_colors ) );
}
$current_color = get_user_option( 'admin_color', $user_id );
if ( empty( $current_color ) || ! isset( $_wp_admin_css_colors[ $current_color ] ) ) {
$current_color = 'fresh';
}
?>
<fieldset id="color-picker" class="scheme-list">
<legend class="screen-reader-text"><span><?php _e( 'Admin Color Scheme' ); ?></span></legend>
<?php
wp_nonce_field( 'save-color-scheme', 'color-nonce', false );
foreach ( $_wp_admin_css_colors as $color => $color_info ) :
?>
<div class="color-option <?php echo ( $color == $current_color ) ? 'selected' : ''; ?>">
<input name="admin_color" id="admin_color_<?php echo esc_attr( $color ); ?>" type="radio" value="<?php echo esc_attr( $color ); ?>" class="tog" <?php checked( $color, $current_color ); ?> />
<input type="hidden" class="css_url" value="<?php echo esc_url( $color_info->url ); ?>" />
<input type="hidden" class="icon_colors" value="<?php echo esc_attr( wp_json_encode( array( 'icons' => $color_info->icon_colors ) ) ); ?>" />
<label for="admin_color_<?php echo esc_attr( $color ); ?>"><?php echo esc_html( $color_info->name ); ?></label>
<table class="color-palette">
<tr>
<?php
foreach ( $color_info->colors as $html_color ) {
?>
<td style="background-color: <?php echo esc_attr( $html_color ); ?>">&nbsp;</td>
<?php
}
?>
</tr>
</table>
</div>
<?php
endforeach;
?>
</fieldset>
<?php
}
/**
*
* @global array $_wp_admin_css_colors
*/
function wp_color_scheme_settings() {
global $_wp_admin_css_colors;
$color_scheme = get_user_option( 'admin_color' );
// It's possible to have a color scheme set that is no longer registered.
if ( empty( $_wp_admin_css_colors[ $color_scheme ] ) ) {
$color_scheme = 'fresh';
}
if ( ! empty( $_wp_admin_css_colors[ $color_scheme ]->icon_colors ) ) {
$icon_colors = $_wp_admin_css_colors[ $color_scheme ]->icon_colors;
} elseif ( ! empty( $_wp_admin_css_colors['fresh']->icon_colors ) ) {
$icon_colors = $_wp_admin_css_colors['fresh']->icon_colors;
} else {
// Fall back to the default set of icon colors if the default scheme is missing.
$icon_colors = array( 'base' => '#82878c', 'focus' => '#00a0d2', 'current' => '#fff' );
}
echo '<script type="text/javascript">var _wpColorScheme = ' . wp_json_encode( array( 'icons' => $icon_colors ) ) . ";</script>\n";
}
/**
* @since 3.3.0
*/
function _ipad_meta() {
if ( wp_is_mobile() ) {
?>
<meta name="viewport" id="viewport-meta" content="width=device-width, initial-scale=1">
<?php
}
}
/**
* Check lock status for posts displayed on the Posts screen
*
* @since 3.6.0
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
* @param string $screen_id The screen id.
* @return array The Heartbeat response.
*/
function wp_check_locked_posts( $response, $data, $screen_id ) {
$checked = array();
if ( array_key_exists( 'wp-check-locked-posts', $data ) && is_array( $data['wp-check-locked-posts'] ) ) {
foreach ( $data['wp-check-locked-posts'] as $key ) {
if ( ! $post_id = absint( substr( $key, 5 ) ) )
continue;
if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) && current_user_can( 'edit_post', $post_id ) ) {
$send = array( 'text' => sprintf( __( '%s is currently editing' ), $user->display_name ) );
if ( ( $avatar = get_avatar( $user->ID, 18 ) ) && preg_match( "|src='([^']+)'|", $avatar, $matches ) )
$send['avatar_src'] = $matches[1];
$checked[$key] = $send;
}
}
}
if ( ! empty( $checked ) )
$response['wp-check-locked-posts'] = $checked;
return $response;
}
/**
* Check lock status on the New/Edit Post screen and refresh the lock
*
* @since 3.6.0
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
* @param string $screen_id The screen id.
* @return array The Heartbeat response.
*/
function wp_refresh_post_lock( $response, $data, $screen_id ) {
if ( array_key_exists( 'wp-refresh-post-lock', $data ) ) {
$received = $data['wp-refresh-post-lock'];
$send = array();
if ( ! $post_id = absint( $received['post_id'] ) )
return $response;
if ( ! current_user_can('edit_post', $post_id) )
return $response;
if ( ( $user_id = wp_check_post_lock( $post_id ) ) && ( $user = get_userdata( $user_id ) ) ) {
$error = array(
'text' => sprintf( __( '%s has taken over and is currently editing.' ), $user->display_name )
);
if ( $avatar = get_avatar( $user->ID, 64 ) ) {
if ( preg_match( "|src='([^']+)'|", $avatar, $matches ) )
$error['avatar_src'] = $matches[1];
}
$send['lock_error'] = $error;
} else {
if ( $new_lock = wp_set_post_lock( $post_id ) )
$send['new_lock'] = implode( ':', $new_lock );
}
$response['wp-refresh-post-lock'] = $send;
}
return $response;
}
/**
* Check nonce expiration on the New/Edit Post screen and refresh if needed
*
* @since 3.6.0
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
* @param string $screen_id The screen id.
* @return array The Heartbeat response.
*/
function wp_refresh_post_nonces( $response, $data, $screen_id ) {
if ( array_key_exists( 'wp-refresh-post-nonces', $data ) ) {
$received = $data['wp-refresh-post-nonces'];
$response['wp-refresh-post-nonces'] = array( 'check' => 1 );
if ( ! $post_id = absint( $received['post_id'] ) ) {
return $response;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $response;
}
$response['wp-refresh-post-nonces'] = array(
'replace' => array(
'getpermalinknonce' => wp_create_nonce('getpermalink'),
'samplepermalinknonce' => wp_create_nonce('samplepermalink'),
'closedpostboxesnonce' => wp_create_nonce('closedpostboxes'),
'_ajax_linking_nonce' => wp_create_nonce( 'internal-linking' ),
'_wpnonce' => wp_create_nonce( 'update-post_' . $post_id ),
),
'heartbeatNonce' => wp_create_nonce( 'heartbeat-nonce' ),
);
}
return $response;
}
/**
* Disable suspension of Heartbeat on the Add/Edit Post screens.
*
* @since 3.8.0
*
* @global string $pagenow
*
* @param array $settings An array of Heartbeat settings.
* @return array Filtered Heartbeat settings.
*/
function wp_heartbeat_set_suspension( $settings ) {
global $pagenow;
if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
$settings['suspension'] = 'disable';
}
return $settings;
}
/**
* Autosave with heartbeat
*
* @since 3.9.0
*
* @param array $response The Heartbeat response.
* @param array $data The $_POST data sent.
* @return array The Heartbeat response.
*/
function heartbeat_autosave( $response, $data ) {
if ( ! empty( $data['wp_autosave'] ) ) {
$saved = wp_autosave( $data['wp_autosave'] );
if ( is_wp_error( $saved ) ) {
$response['wp_autosave'] = array( 'success' => false, 'message' => $saved->get_error_message() );
} elseif ( empty( $saved ) ) {
$response['wp_autosave'] = array( 'success' => false, 'message' => __( 'Error while saving.' ) );
} else {
/* translators: draft saved date format, see http://php.net/date */
$draft_saved_date_format = __( 'g:i:s a' );
/* translators: %s: date and time */
$response['wp_autosave'] = array( 'success' => true, 'message' => sprintf( __( 'Draft saved at %s.' ), date_i18n( $draft_saved_date_format ) ) );
}
}
return $response;
}
/**
* Disables autocomplete on the 'post' form (Add/Edit Post screens) for WebKit browsers,
* as they disregard the autocomplete setting on the editor textarea. That can break the editor
* when the user navigates to it with the browser's Back button. See #28037
*
* @since 4.0.0
*
* @global bool $is_safari
* @global bool $is_chrome
*/
function post_form_autocomplete_off() {
global $is_safari, $is_chrome;
if ( $is_safari || $is_chrome ) {
echo ' autocomplete="off"';
}
}
/**
* Remove single-use URL parameters and create canonical link based on new URL.
*
* Remove specific query string parameters from a URL, create the canonical link,
* put it in the admin header, and change the current URL to match.
*
* @since 4.2.0
*/
function wp_admin_canonical_url() {
$removable_query_args = wp_removable_query_args();
if ( empty( $removable_query_args ) ) {
return;
}
// Ensure we're using an absolute URL.
$current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
$filtered_url = remove_query_arg( $removable_query_args, $current_url );
?>
<link id="wp-admin-canonical" rel="canonical" href="<?php echo esc_url( $filtered_url ); ?>" />
<script>
if ( window.history.replaceState ) {
window.history.replaceState( null, null, document.getElementById( 'wp-admin-canonical' ).href + window.location.hash );
}
</script>
<?php
}

View File

@@ -0,0 +1,43 @@
<?php
/**
* Multisite Administration hooks
*
* @package WordPress
* @subpackage Administration
* @since 4.3.0
*/
// Media Hooks.
add_filter( 'wp_handle_upload_prefilter', 'check_upload_size' );
// User Hooks
add_action( 'admin_notices', 'new_user_email_admin_notice' );
add_action( 'user_admin_notices', 'new_user_email_admin_notice' );
add_action( 'admin_page_access_denied', '_access_denied_splash', 99 );
add_action( 'add_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
add_action( 'personal_options_update', 'send_confirmation_on_profile_email' );
add_action( 'update_option_new_admin_email', 'update_option_new_admin_email', 10, 2 );
// Site Hooks.
add_action( 'wpmueditblogaction', 'upload_space_setting' );
// Taxonomy Hooks
add_filter( 'get_term', 'sync_category_tag_slugs', 10, 2 );
// Post Hooks.
add_filter( 'wp_insert_post_data', 'avoid_blog_page_permalink_collision', 10, 2 );
// Tools Hooks.
add_filter( 'import_allow_create_users', 'check_import_new_users' );
// Notices Hooks
add_action( 'admin_notices', 'site_admin_notice' );
add_action( 'network_admin_notices', 'site_admin_notice' );
// Update Hooks
add_action( 'network_admin_notices', 'update_nag', 3 );
add_action( 'network_admin_notices', 'maintenance_nag', 10 );

View File

@@ -0,0 +1,105 @@
<?php
/**
* Multisite: Deprecated admin functions from past versions and WordPress MU
*
* These functions should not be used and will be removed in a later version.
* It is suggested to use for the alternatives instead when available.
*
* @package WordPress
* @subpackage Deprecated
* @since 3.0.0
*/
/**
* Outputs the WPMU menu.
*
* @deprecated 3.0.0
*/
function wpmu_menu() {
_deprecated_function(__FUNCTION__, '3.0' );
// Deprecated. See #11763.
}
/**
* Determines if the available space defined by the admin has been exceeded by the user.
*
* @deprecated 3.0.0 Use is_upload_space_available()
* @see is_upload_space_available()
*/
function wpmu_checkAvailableSpace() {
_deprecated_function(__FUNCTION__, '3.0', 'is_upload_space_available()' );
if ( !is_upload_space_available() )
wp_die( __('Sorry, you must delete files before you can upload any more.') );
}
/**
* WPMU options.
*
* @deprecated 3.0.0
*/
function mu_options( $options ) {
_deprecated_function(__FUNCTION__, '3.0' );
return $options;
}
/**
* Deprecated functionality for activating a network-only plugin.
*
* @deprecated 3.0.0 Use activate_plugin()
* @see activate_plugin()
*/
function activate_sitewide_plugin() {
_deprecated_function(__FUNCTION__, '3.0', 'activate_plugin()' );
return false;
}
/**
* Deprecated functionality for deactivating a network-only plugin.
*
* @deprecated 3.0.0 Use deactivate_sitewide_plugin()
* @see deactivate_sitewide_plugin()
*/
function deactivate_sitewide_plugin( $plugin = false ) {
_deprecated_function(__FUNCTION__, '3.0', 'deactivate_plugin()' );
}
/**
* Deprecated functionality for determining if the current plugin is network-only.
*
* @deprecated 3.0.0 Use is_network_only_plugin()
* @see is_network_only_plugin()
*/
function is_wpmu_sitewide_plugin( $file ) {
_deprecated_function(__FUNCTION__, '3.0', 'is_network_only_plugin()' );
return is_network_only_plugin( $file );
}
/**
* Deprecated functionality for getting themes network-enabled themes.
*
* @deprecated 3.4.0 Use WP_Theme::get_allowed_on_network()
* @see WP_Theme::get_allowed_on_network()
*/
function get_site_allowed_themes() {
_deprecated_function( __FUNCTION__, '3.4', 'WP_Theme::get_allowed_on_network()' );
return array_map( 'intval', WP_Theme::get_allowed_on_network() );
}
/**
* Deprecated functionality for getting themes allowed on a specific site.
*
* @deprecated 3.4.0 Use WP_Theme::get_allowed_on_site()
* @see WP_Theme::get_allowed_on_site()
*/
function wpmu_get_blog_allowedthemes( $blog_id = 0 ) {
_deprecated_function( __FUNCTION__, '3.4', 'WP_Theme::get_allowed_on_site()' );
return array_map( 'intval', WP_Theme::get_allowed_on_site( $blog_id ) );
}
/**
* Deprecated functionality for determining whether a file is deprecated.
*
* @deprecated 3.5.0
*/
function ms_deprecated_blogs_file() {}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,581 @@
<?php
/**
* WordPress Network Administration API.
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Check for an existing network.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return Whether a network exists.
*/
function network_domain_check() {
global $wpdb;
$sql = $wpdb->prepare( "SHOW TABLES LIKE %s", $wpdb->esc_like( $wpdb->site ) );
if ( $wpdb->get_var( $sql ) ) {
return $wpdb->get_var( "SELECT domain FROM $wpdb->site ORDER BY id ASC LIMIT 1" );
}
return false;
}
/**
* Allow subdomain install
*
* @since 3.0.0
* @return bool Whether subdomain install is allowed
*/
function allow_subdomain_install() {
$domain = preg_replace( '|https?://([^/]+)|', '$1', get_option( 'home' ) );
if ( parse_url( get_option( 'home' ), PHP_URL_PATH ) || 'localhost' == $domain || preg_match( '|^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$|', $domain ) )
return false;
return true;
}
/**
* Allow subdirectory install.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @return bool Whether subdirectory install is allowed
*/
function allow_subdirectory_install() {
global $wpdb;
/**
* Filter whether to enable the subdirectory install feature in Multisite.
*
* @since 3.0.0
*
* @param bool $allow Whether to enable the subdirectory install feature in Multisite. Default is false.
*/
if ( apply_filters( 'allow_subdirectory_install', false ) )
return true;
if ( defined( 'ALLOW_SUBDIRECTORY_INSTALL' ) && ALLOW_SUBDIRECTORY_INSTALL )
return true;
$post = $wpdb->get_row( "SELECT ID FROM $wpdb->posts WHERE post_date < DATE_SUB(NOW(), INTERVAL 1 MONTH) AND post_status = 'publish'" );
if ( empty( $post ) )
return true;
return false;
}
/**
* Get base domain of network.
*
* @since 3.0.0
* @return string Base domain.
*/
function get_clean_basedomain() {
if ( $existing_domain = network_domain_check() )
return $existing_domain;
$domain = preg_replace( '|https?://|', '', get_option( 'siteurl' ) );
if ( $slash = strpos( $domain, '/' ) )
$domain = substr( $domain, 0, $slash );
return $domain;
}
/**
* Prints step 1 for Network installation process.
*
* @todo Realistically, step 1 should be a welcome screen explaining what a Network is and such. Navigating to Tools > Network
* should not be a sudden "Welcome to a new install process! Fill this out and click here." See also contextual help todo.
*
* @since 3.0.0
*
* @global bool $is_apache
*
* @param WP_Error $errors
*/
function network_step1( $errors = false ) {
global $is_apache;
if ( defined('DO_NOT_UPGRADE_GLOBAL_TABLES') ) {
echo '<div class="error"><p><strong>' . __('ERROR:') . '</strong> ' . __( 'The constant DO_NOT_UPGRADE_GLOBAL_TABLES cannot be defined when creating a network.' ) . '</p></div>';
echo '</div>';
include( ABSPATH . 'wp-admin/admin-footer.php' );
die();
}
$active_plugins = get_option( 'active_plugins' );
if ( ! empty( $active_plugins ) ) {
echo '<div class="updated"><p><strong>' . __('Warning:') . '</strong> ' . sprintf( __( 'Please <a href="%s">deactivate your plugins</a> before enabling the Network feature.' ), admin_url( 'plugins.php?plugin_status=active' ) ) . '</p></div><p>' . __( 'Once the network is created, you may reactivate your plugins.' ) . '</p>';
echo '</div>';
include( ABSPATH . 'wp-admin/admin-footer.php' );
die();
}
$hostname = get_clean_basedomain();
$has_ports = strstr( $hostname, ':' );
if ( ( false !== $has_ports && ! in_array( $has_ports, array( ':80', ':443' ) ) ) ) {
echo '<div class="error"><p><strong>' . __( 'ERROR:') . '</strong> ' . __( 'You cannot install a network of sites with your server address.' ) . '</p></div>';
echo '<p>' . sprintf(
/* translators: %s: port number */
__( 'You cannot use port numbers such as %s.' ),
'<code>' . $has_ports . '</code>'
) . '</p>';
echo '<a href="' . esc_url( admin_url() ) . '">' . __( 'Return to Dashboard' ) . '</a>';
echo '</div>';
include( ABSPATH . 'wp-admin/admin-footer.php' );
die();
}
echo '<form method="post">';
wp_nonce_field( 'install-network-1' );
$error_codes = array();
if ( is_wp_error( $errors ) ) {
echo '<div class="error"><p><strong>' . __( 'ERROR: The network could not be created.' ) . '</strong></p>';
foreach ( $errors->get_error_messages() as $error )
echo "<p>$error</p>";
echo '</div>';
$error_codes = $errors->get_error_codes();
}
$site_name = ( ! empty( $_POST['sitename'] ) && ! in_array( 'empty_sitename', $error_codes ) ) ? $_POST['sitename'] : sprintf( _x('%s Sites', 'Default network name' ), get_option( 'blogname' ) );
$admin_email = ( ! empty( $_POST['email'] ) && ! in_array( 'invalid_email', $error_codes ) ) ? $_POST['email'] : get_option( 'admin_email' );
?>
<p><?php _e( 'Welcome to the Network installation process!' ); ?></p>
<p><?php _e( 'Fill in the information below and you&#8217;ll be on your way to creating a network of WordPress sites. We will create configuration files in the next step.' ); ?></p>
<?php
if ( isset( $_POST['subdomain_install'] ) ) {
$subdomain_install = (bool) $_POST['subdomain_install'];
} elseif ( apache_mod_loaded('mod_rewrite') ) { // assume nothing
$subdomain_install = true;
} elseif ( !allow_subdirectory_install() ) {
$subdomain_install = true;
} else {
$subdomain_install = false;
if ( $got_mod_rewrite = got_mod_rewrite() ) { // dangerous assumptions
echo '<div class="updated inline"><p><strong>' . __( 'Note:' ) . '</strong> ';
/* translators: %s: mod_rewrite */
printf( __( 'Please make sure the Apache %s module is installed as it will be used at the end of this installation.' ),
'<code>mod_rewrite</code>'
);
echo '</p>';
} elseif ( $is_apache ) {
echo '<div class="error inline"><p><strong>' . __( 'Warning!' ) . '</strong> ';
/* translators: %s: mod_rewrite */
printf( __( 'It looks like the Apache %s module is not installed.' ),
'<code>mod_rewrite</code>'
);
echo '</p>';
}
if ( $got_mod_rewrite || $is_apache ) { // Protect against mod_rewrite mimicry (but ! Apache)
echo '<p>';
/* translators: 1: mod_rewrite, 2: mod_rewrite documentation URL, 3: Google search for mod_rewrite */
printf( __( 'If %1$s is disabled, ask your administrator to enable that module, or look at the <a href="%2$s">Apache documentation</a> or <a href="%3$s">elsewhere</a> for help setting it up.' ),
'<code>mod_rewrite</code>',
'http://httpd.apache.org/docs/mod/mod_rewrite.html',
'http://www.google.com/search?q=apache+mod_rewrite'
);
echo '</p></div>';
}
}
if ( allow_subdomain_install() && allow_subdirectory_install() ) : ?>
<h3><?php esc_html_e( 'Addresses of Sites in your Network' ); ?></h3>
<p><?php _e( 'Please choose whether you would like sites in your WordPress network to use sub-domains or sub-directories.' ); ?>
<strong><?php _e( 'You cannot change this later.' ); ?></strong></p>
<p><?php _e( 'You will need a wildcard DNS record if you are going to use the virtual host (sub-domain) functionality.' ); ?></p>
<?php // @todo: Link to an MS readme? ?>
<table class="form-table">
<tr>
<th><label><input type="radio" name="subdomain_install" value="1"<?php checked( $subdomain_install ); ?> /> <?php _e( 'Sub-domains' ); ?></label></th>
<td><?php printf(
/* translators: 1: hostname */
_x( 'like <code>site1.%1$s</code> and <code>site2.%1$s</code>', 'subdomain examples' ),
$hostname
); ?></td>
</tr>
<tr>
<th><label><input type="radio" name="subdomain_install" value="0"<?php checked( ! $subdomain_install ); ?> /> <?php _e( 'Sub-directories' ); ?></label></th>
<td><?php printf(
/* translators: 1: hostname */
_x( 'like <code>%1$s/site1</code> and <code>%1$s/site2</code>', 'subdirectory examples' ),
$hostname
); ?></td>
</tr>
</table>
<?php
endif;
if ( WP_CONTENT_DIR != ABSPATH . 'wp-content' && ( allow_subdirectory_install() || ! allow_subdomain_install() ) )
echo '<div class="error inline"><p><strong>' . __('Warning!') . '</strong> ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</p></div>';
$is_www = ( 0 === strpos( $hostname, 'www.' ) );
if ( $is_www ) :
?>
<h3><?php esc_html_e( 'Server Address' ); ?></h3>
<p><?php printf(
/* translators: 1: site url 2: host name 3. www */
__( 'We recommend you change your siteurl to %1$s before enabling the network feature. It will still be possible to visit your site using the %3$s prefix with an address like %2$s but any links will not have the %3$s prefix.' ),
'<code>' . substr( $hostname, 4 ) . '</code>',
'<code>' . $hostname . '</code>',
'<code>www</code>'
); ?></p>
<table class="form-table">
<tr>
<th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
<td>
<?php printf(
/* translators: %s: host name */
__( 'The internet address of your network will be %s.' ),
'<code>' . $hostname . '</code>'
); ?>
</td>
</tr>
</table>
<?php endif; ?>
<h3><?php esc_html_e( 'Network Details' ); ?></h3>
<table class="form-table">
<?php if ( 'localhost' == $hostname ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-directory Install' ); ?></th>
<td><?php
printf(
/* translators: 1: localhost 2: localhost.localdomain */
__( 'Because you are using %1$s, the sites in your WordPress network must use sub-directories. Consider using %2$s if you wish to use sub-domains.' ),
'<code>localhost</code>',
'<code>localhost.localdomain</code>'
);
// Uh oh:
if ( !allow_subdirectory_install() )
echo ' <strong>' . __( 'Warning!' ) . ' ' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
?></td>
</tr>
<?php elseif ( !allow_subdomain_install() ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-directory Install' ); ?></th>
<td><?php
_e( 'Because your install is in a directory, the sites in your WordPress network must use sub-directories.' );
// Uh oh:
if ( !allow_subdirectory_install() )
echo ' <strong>' . __( 'Warning!' ) . ' ' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
?></td>
</tr>
<?php elseif ( !allow_subdirectory_install() ) : ?>
<tr>
<th scope="row"><?php esc_html_e( 'Sub-domain Install' ); ?></th>
<td><?php _e( 'Because your install is not new, the sites in your WordPress network must use sub-domains.' );
echo ' <strong>' . __( 'The main site in a sub-directory install will need to use a modified permalink structure, potentially breaking existing links.' ) . '</strong>';
?></td>
</tr>
<?php endif; ?>
<?php if ( ! $is_www ) : ?>
<tr>
<th scope='row'><?php esc_html_e( 'Server Address' ); ?></th>
<td>
<?php printf(
/* translators: %s: host name */
__( 'The internet address of your network will be %s.' ),
'<code>' . $hostname . '</code>'
); ?>
</td>
</tr>
<?php endif; ?>
<tr>
<th scope='row'><?php esc_html_e( 'Network Title' ); ?></th>
<td>
<input name='sitename' type='text' size='45' value='<?php echo esc_attr( $site_name ); ?>' />
<p class="description">
<?php _e( 'What would you like to call your network?' ); ?>
</p>
</td>
</tr>
<tr>
<th scope='row'><?php esc_html_e( 'Network Admin Email' ); ?></th>
<td>
<input name='email' type='text' size='45' value='<?php echo esc_attr( $admin_email ); ?>' />
<p class="description">
<?php _e( 'Your email address.' ); ?>
</p>
</td>
</tr>
</table>
<?php submit_button( __( 'Install' ), 'primary', 'submit' ); ?>
</form>
<?php
}
/**
* Prints step 2 for Network installation process.
*
* @since 3.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param WP_Error $errors
*/
function network_step2( $errors = false ) {
global $wpdb;
$hostname = get_clean_basedomain();
$slashed_home = trailingslashit( get_option( 'home' ) );
$base = parse_url( $slashed_home, PHP_URL_PATH );
$document_root_fix = str_replace( '\\', '/', realpath( $_SERVER['DOCUMENT_ROOT'] ) );
$abspath_fix = str_replace( '\\', '/', ABSPATH );
$home_path = 0 === strpos( $abspath_fix, $document_root_fix ) ? $document_root_fix . $base : get_home_path();
$wp_siteurl_subdir = preg_replace( '#^' . preg_quote( $home_path, '#' ) . '#', '', $abspath_fix );
$rewrite_base = ! empty( $wp_siteurl_subdir ) ? ltrim( trailingslashit( $wp_siteurl_subdir ), '/' ) : '';
$location_of_wp_config = $abspath_fix;
if ( ! file_exists( ABSPATH . 'wp-config.php' ) && file_exists( dirname( ABSPATH ) . '/wp-config.php' ) ) {
$location_of_wp_config = dirname( $abspath_fix );
}
$location_of_wp_config = trailingslashit( $location_of_wp_config );
// Wildcard DNS message.
if ( is_wp_error( $errors ) )
echo '<div class="error">' . $errors->get_error_message() . '</div>';
if ( $_POST ) {
if ( allow_subdomain_install() )
$subdomain_install = allow_subdirectory_install() ? ! empty( $_POST['subdomain_install'] ) : true;
else
$subdomain_install = false;
} else {
if ( is_multisite() ) {
$subdomain_install = is_subdomain_install();
?>
<p><?php _e( 'The original configuration steps are shown here for reference.' ); ?></p>
<?php
} else {
$subdomain_install = (bool) $wpdb->get_var( "SELECT meta_value FROM $wpdb->sitemeta WHERE site_id = 1 AND meta_key = 'subdomain_install'" );
?>
<div class="error"><p><strong><?php _e('Warning:'); ?></strong> <?php _e( 'An existing WordPress network was detected.' ); ?></p></div>
<p><?php _e( 'Please complete the configuration steps. To create a new network, you will need to empty or remove the network database tables.' ); ?></p>
<?php
}
}
$subdir_match = $subdomain_install ? '' : '([_0-9a-zA-Z-]+/)?';
$subdir_replacement_01 = $subdomain_install ? '' : '$1';
$subdir_replacement_12 = $subdomain_install ? '$1' : '$2';
if ( $_POST || ! is_multisite() ) {
?>
<h3><?php esc_html_e( 'Enabling the Network' ); ?></h3>
<p><?php _e( 'Complete the following steps to enable the features for creating a network of sites.' ); ?></p>
<div class="updated inline"><p><?php
if ( file_exists( $home_path . '.htaccess' ) ) {
echo '<strong>' . __( 'Caution:' ) . '</strong> ';
printf(
/* translators: 1: wp-config.php 2: .htaccess */
__( 'We recommend you back up your existing %1$s and %2$s files.' ),
'<code>wp-config.php</code>',
'<code>.htaccess</code>'
);
} elseif ( file_exists( $home_path . 'web.config' ) ) {
echo '<strong>' . __( 'Caution:' ) . '</strong> ';
printf(
/* translators: 1: wp-config.php 2: web.config */
__( 'We recommend you back up your existing %1$s and %2$s files.' ),
'<code>wp-config.php</code>',
'<code>web.config</code>'
);
} else {
echo '<strong>' . __( 'Caution:' ) . '</strong> ';
printf(
/* translators: 1: wp-config.php */
__( 'We recommend you back up your existing %s file.' ),
'<code>wp-config.php</code>'
);
}
?></p></div>
<?php
}
?>
<ol>
<li><p><?php printf(
/* translators: 1: wp-config.php 2: location of wp-config file */
__( 'Add the following to your %1$s file in %2$s <strong>above</strong> the line reading <code>/* That&#8217;s all, stop editing! Happy blogging. */</code>:' ),
'<code>wp-config.php</code>',
'<code>' . $location_of_wp_config . '</code>'
); ?></p>
<textarea class="code" readonly="readonly" cols="100" rows="7">
define('MULTISITE', true);
define('SUBDOMAIN_INSTALL', <?php echo $subdomain_install ? 'true' : 'false'; ?>);
define('DOMAIN_CURRENT_SITE', '<?php echo $hostname; ?>');
define('PATH_CURRENT_SITE', '<?php echo $base; ?>');
define('SITE_ID_CURRENT_SITE', 1);
define('BLOG_ID_CURRENT_SITE', 1);
</textarea>
<?php
$keys_salts = array( 'AUTH_KEY' => '', 'SECURE_AUTH_KEY' => '', 'LOGGED_IN_KEY' => '', 'NONCE_KEY' => '', 'AUTH_SALT' => '', 'SECURE_AUTH_SALT' => '', 'LOGGED_IN_SALT' => '', 'NONCE_SALT' => '' );
foreach ( $keys_salts as $c => $v ) {
if ( defined( $c ) )
unset( $keys_salts[ $c ] );
}
if ( ! empty( $keys_salts ) ) {
$keys_salts_str = '';
$from_api = wp_remote_get( 'https://api.wordpress.org/secret-key/1.1/salt/' );
if ( is_wp_error( $from_api ) ) {
foreach ( $keys_salts as $c => $v ) {
$keys_salts_str .= "\ndefine( '$c', '" . wp_generate_password( 64, true, true ) . "' );";
}
} else {
$from_api = explode( "\n", wp_remote_retrieve_body( $from_api ) );
foreach ( $keys_salts as $c => $v ) {
$keys_salts_str .= "\ndefine( '$c', '" . substr( array_shift( $from_api ), 28, 64 ) . "' );";
}
}
$num_keys_salts = count( $keys_salts );
?>
<p>
<?php
if ( 1 == $num_keys_salts ) {
printf(
/* translators: 1: wp-config.php */
__( 'This unique authentication key is also missing from your %s file.' ),
'<code>wp-config.php</code>'
);
} else {
printf(
/* translators: 1: wp-config.php */
__( 'These unique authentication keys are also missing from your %s file.' ),
'<code>wp-config.php</code>'
);
}
?>
<?php _e( 'To make your installation more secure, you should also add:' ); ?>
</p>
<textarea class="code" readonly="readonly" cols="100" rows="<?php echo $num_keys_salts; ?>"><?php echo esc_textarea( $keys_salts_str ); ?></textarea>
<?php
}
?>
</li>
<?php
if ( iis7_supports_permalinks() ) :
// IIS doesn't support RewriteBase, all your RewriteBase are belong to us
$iis_subdir_match = ltrim( $base, '/' ) . $subdir_match;
$iis_rewrite_base = ltrim( $base, '/' ) . $rewrite_base;
$iis_subdir_replacement = $subdomain_install ? '' : '{R:1}';
$web_config_file = '<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="WordPress Rule 1" stopProcessing="true">
<match url="^index\.php$" ignoreCase="false" />
<action type="None" />
</rule>';
if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
$web_config_file .= '
<rule name="WordPress Rule for Files" stopProcessing="true">
<match url="^' . $iis_subdir_match . 'files/(.+)" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . WPINC . '/ms-files.php?file={R:1}" appendQueryString="false" />
</rule>';
}
$web_config_file .= '
<rule name="WordPress Rule 2" stopProcessing="true">
<match url="^' . $iis_subdir_match . 'wp-admin$" ignoreCase="false" />
<action type="Redirect" url="' . $iis_subdir_replacement . 'wp-admin/" redirectType="Permanent" />
</rule>
<rule name="WordPress Rule 3" stopProcessing="true">
<match url="^" ignoreCase="false" />
<conditions logicalGrouping="MatchAny">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" />
</conditions>
<action type="None" />
</rule>
<rule name="WordPress Rule 4" stopProcessing="true">
<match url="^' . $iis_subdir_match . '(wp-(content|admin|includes).*)" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . '{R:1}" />
</rule>
<rule name="WordPress Rule 5" stopProcessing="true">
<match url="^' . $iis_subdir_match . '([_0-9a-zA-Z-]+/)?(.*\.php)$" ignoreCase="false" />
<action type="Rewrite" url="' . $iis_rewrite_base . '{R:2}" />
</rule>
<rule name="WordPress Rule 6" stopProcessing="true">
<match url="." ignoreCase="false" />
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
';
echo '<li><p>';
printf(
/* translators: 1: a filename like .htaccess. 2: a file path. */
__( 'Add the following to your %1$s file in %2$s, <strong>replacing</strong> other WordPress rules:' ),
'<code>web.config</code>',
'<code>' . $home_path . '</code>'
);
echo '</p>';
if ( ! $subdomain_install && WP_CONTENT_DIR != ABSPATH . 'wp-content' )
echo '<p><strong>' . __('Warning:') . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
?>
<textarea class="code" readonly="readonly" cols="100" rows="20"><?php echo esc_textarea( $web_config_file ); ?>
</textarea></li>
</ol>
<?php else : // end iis7_supports_permalinks(). construct an htaccess file instead:
$ms_files_rewriting = '';
if ( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
$ms_files_rewriting = "\n# uploaded files\nRewriteRule ^";
$ms_files_rewriting .= $subdir_match . "files/(.+) {$rewrite_base}" . WPINC . "/ms-files.php?file={$subdir_replacement_12} [L]" . "\n";
}
$htaccess_file = <<<EOF
RewriteEngine On
RewriteBase {$base}
RewriteRule ^index\.php$ - [L]
{$ms_files_rewriting}
# add a trailing slash to /wp-admin
RewriteRule ^{$subdir_match}wp-admin$ {$subdir_replacement_01}wp-admin/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]
RewriteRule ^{$subdir_match}(wp-(content|admin|includes).*) {$rewrite_base}{$subdir_replacement_12} [L]
RewriteRule ^{$subdir_match}(.*\.php)$ {$rewrite_base}$subdir_replacement_12 [L]
RewriteRule . index.php [L]
EOF;
echo '<li><p>';
printf(
/* translators: 1: a filename like .htaccess. 2: a file path. */
__( 'Add the following to your %1$s file in %2$s, <strong>replacing</strong> other WordPress rules:' ),
'<code>.htaccess</code>',
'<code>' . $home_path . '</code>'
);
echo '</p>';
if ( ! $subdomain_install && WP_CONTENT_DIR != ABSPATH . 'wp-content' )
echo '<p><strong>' . __('Warning:') . ' ' . __( 'Subdirectory networks may not be fully compatible with custom wp-content directories.' ) . '</strong></p>';
?>
<textarea class="code" readonly="readonly" cols="100" rows="<?php echo substr_count( $htaccess_file, "\n" ) + 1; ?>">
<?php echo esc_textarea( $htaccess_file ); ?></textarea></li>
</ol>
<?php endif; // end IIS/Apache code branches.
if ( !is_multisite() ) { ?>
<p><?php _e( 'Once you complete these steps, your network is enabled and configured. You will have to log in again.' ); ?> <a href="<?php echo esc_url( wp_login_url() ); ?>"><?php _e( 'Log In' ); ?></a></p>
<?php
}
}

View File

@@ -0,0 +1,106 @@
<?php
/**
* @ignore
*/
function __() {}
/**
* @ignore
*/
function _x() {}
/**
* @ignore
*/
function add_filter() {}
/**
* @ignore
*/
function esc_attr() {}
/**
* @ignore
*/
function apply_filters() {}
/**
* @ignore
*/
function get_option() {}
/**
* @ignore
*/
function is_lighttpd_before_150() {}
/**
* @ignore
*/
function add_action() {}
/**
* @ignore
*/
function did_action() {}
/**
* @ignore
*/
function do_action_ref_array() {}
/**
* @ignore
*/
function get_bloginfo() {}
/**
* @ignore
*/
function is_admin() {return true;}
/**
* @ignore
*/
function site_url() {}
/**
* @ignore
*/
function admin_url() {}
/**
* @ignore
*/
function home_url() {}
/**
* @ignore
*/
function includes_url() {}
/**
* @ignore
*/
function wp_guess_url() {}
if ( ! function_exists( 'json_encode' ) ) :
/**
* @ignore
*/
function json_encode() {}
endif;
function get_file( $path ) {
if ( function_exists('realpath') ) {
$path = realpath( $path );
}
if ( ! $path || ! @is_file( $path ) ) {
return '';
}
return @file_get_contents( $path );
}

View File

@@ -0,0 +1,141 @@
<?php
/**
* WordPress Options Administration API.
*
* @package WordPress
* @subpackage Administration
* @since 4.4.0
*/
/**
* Output JavaScript to toggle display of additional settings if avatars are disabled.
*
* @since 4.2.0
*/
function options_discussion_add_js() {
?>
<script>
(function($){
var parent = $( '#show_avatars' ),
children = $( '.avatar-settings' );
parent.change(function(){
children.toggleClass( 'hide-if-js', ! this.checked );
});
})(jQuery);
</script>
<?php
}
/**
* Display JavaScript on the page.
*
* @since 3.5.0
*/
function options_general_add_js() {
?>
<script type="text/javascript">
jQuery(document).ready(function($){
var $siteName = $( '#wp-admin-bar-site-name' ).children( 'a' ).first(),
homeURL = ( <?php echo wp_json_encode( get_home_url() ); ?> || '' ).replace( /^(https?:\/\/)?(www\.)?/, '' );
$( '#blogname' ).on( 'input', function() {
var title = $.trim( $( this ).val() ) || homeURL;
// Truncate to 40 characters.
if ( 40 < title.length ) {
title = title.substring( 0, 40 ) + '\u2026';
}
$siteName.text( title );
});
$("input[name='date_format']").click(function(){
if ( "date_format_custom_radio" != $(this).attr("id") )
$( "input[name='date_format_custom']" ).val( $( this ).val() ).siblings( '.example' ).text( $( this ).parent( 'label' ).children( '.format-i18n' ).text() );
});
$("input[name='date_format_custom']").focus(function(){
$( '#date_format_custom_radio' ).prop( 'checked', true );
});
$("input[name='time_format']").click(function(){
if ( "time_format_custom_radio" != $(this).attr("id") )
$( "input[name='time_format_custom']" ).val( $( this ).val() ).siblings( '.example' ).text( $( this ).parent( 'label' ).children( '.format-i18n' ).text() );
});
$("input[name='time_format_custom']").focus(function(){
$( '#time_format_custom_radio' ).prop( 'checked', true );
});
$("input[name='date_format_custom'], input[name='time_format_custom']").change( function() {
var format = $(this);
format.siblings( '.spinner' ).addClass( 'is-active' );
$.post(ajaxurl, {
action: 'date_format_custom' == format.attr('name') ? 'date_format' : 'time_format',
date : format.val()
}, function(d) { format.siblings( '.spinner' ).removeClass( 'is-active' ); format.siblings('.example').text(d); } );
});
var languageSelect = $( '#WPLANG' );
$( 'form' ).submit( function() {
// Don't show a spinner for English and installed languages,
// as there is nothing to download.
if ( ! languageSelect.find( 'option:selected' ).data( 'installed' ) ) {
$( '#submit', this ).after( '<span class="spinner language-install-spinner" />' );
}
});
});
</script>
<?php
}
/**
* Display JavaScript on the page.
*
* @since 3.5.0
*/
function options_permalink_add_js() {
?>
<script type="text/javascript">
jQuery(document).ready(function() {
jQuery('.permalink-structure input:radio').change(function() {
if ( 'custom' == this.value )
return;
jQuery('#permalink_structure').val( this.value );
});
jQuery('#permalink_structure').focus(function() {
jQuery("#custom_selection").attr('checked', 'checked');
});
});
</script>
<?php
}
/**
* Display JavaScript on the page.
*
* @since 3.5.0
*/
function options_reading_add_js() {
?>
<script type="text/javascript">
jQuery(document).ready(function($){
var section = $('#front-static-pages'),
staticPage = section.find('input:radio[value="page"]'),
selects = section.find('select'),
check_disabled = function(){
selects.prop( 'disabled', ! staticPage.prop('checked') );
};
check_disabled();
section.find('input:radio').change(check_disabled);
});
</script>
<?php
}
/**
* Render the site charset setting.
*
* @since 3.5.0
*/
function options_reading_blog_charset() {
echo '<input name="blog_charset" type="text" id="blog_charset" value="' . esc_attr( get_option( 'blog_charset' ) ) . '" class="regular-text" />';
echo '<p class="description">' . __( 'The <a href="https://codex.wordpress.org/Glossary#Character_set">character encoding</a> of your site (UTF-8 is recommended)' ) . '</p>';
}

View File

@@ -0,0 +1,678 @@
<?php
/**
* WordPress Plugin Install Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Retrieves plugin installer pages from the WordPress.org Plugins API.
*
* It is possible for a plugin to override the Plugin API result with three
* filters. Assume this is for plugins, which can extend on the Plugin Info to
* offer more choices. This is very powerful and must be used with care when
* overriding the filters.
*
* The first filter, {@see 'plugins_api_args'}, is for the args and gives the action
* as the second parameter. The hook for {@see 'plugins_api_args'} must ensure that
* an object is returned.
*
* The second filter, {@see 'plugins_api'}, allows a plugin to override the WordPress.org
* Plugin Install API entirely. If `$action` is 'query_plugins' or 'plugin_information',
* an object MUST be passed. If `$action` is 'hot_tags` or 'hot_categories', an array MUST
* be passed.
*
* Finally, the third filter, {@see 'plugins_api_result'}, makes it possible to filter the
* response object or array, depending on the `$action` type.
*
* Supported arguments per action:
*
* | Argument Name | query_plugins | plugin_information | hot_tags | hot_categories |
* | -------------------- | :-----------: | :----------------: | :------: | :------------: |
* | `$slug` | No | Yes | No | No |
* | `$per_page` | Yes | No | No | No |
* | `$page` | Yes | No | No | No |
* | `$number` | No | No | Yes | Yes |
* | `$search` | Yes | No | No | No |
* | `$tag` | Yes | No | No | No |
* | `$author` | Yes | No | No | No |
* | `$user` | Yes | No | No | No |
* | `$browse` | Yes | No | No | No |
* | `$locale` | Yes | Yes | No | No |
* | `$installed_plugins` | Yes | No | No | No |
* | `$is_ssl` | Yes | Yes | No | No |
* | `$fields` | Yes | Yes | No | No |
*
* @since 2.7.0
*
* @param string $action API action to perform: 'query_plugins', 'plugin_information',
* 'hot_tags' or 'hot_categories'.
* @param array|object $args {
* Optional. Array or object of arguments to serialize for the Plugin Info API.
*
* @type string $slug The plugin slug. Default empty.
* @type int $per_page Number of plugins per page. Default 24.
* @type int $page Number of current page. Default 1.
* @type int $number Number of tags or categories to be queried.
* @type string $search A search term. Default empty.
* @type string $tag Tag to filter plugins. Default empty.
* @type string $author Username of an plugin author to filter plugins. Default empty.
* @type string $user Username to query for their favorites. Default empty.
* @type string $browse Browse view: 'popular', 'new', 'beta', 'recommended'.
* @type string $locale Locale to provide context-sensitive results. Default is the value
* of get_locale().
* @type string $installed_plugins Installed plugins to provide context-sensitive results.
* @type bool $is_ssl Whether links should be returned with https or not. Default false.
* @type array $fields {
* Array of fields which should or should not be returned.
*
* @type bool $short_description Whether to return the plugin short description. Default true.
* @type bool $description Whether to return the plugin full description. Default false.
* @type bool $sections Whether to return the plugin readme sections: description, installation,
* FAQ, screenshots, other notes, and changelog. Default false.
* @type bool $tested Whether to return the 'Compatible up to' value. Default true.
* @type bool $requires Whether to return the required WordPress version. Default true.
* @type bool $rating Whether to return the rating in percent and total number of ratings.
* Default true.
* @type bool $ratings Whether to return the number of rating for each star (1-5). Default true.
* @type bool $downloaded Whether to return the download count. Default true.
* @type bool $downloadlink Whether to return the download link for the package. Default true.
* @type bool $last_updated Whether to return the date of the last update. Default true.
* @type bool $added Whether to return the date when the plugin was added to the wordpress.org
* repository. Default true.
* @type bool $tags Whether to return the assigned tags. Default true.
* @type bool $compatibility Whether to return the WordPress compatibility list. Default true.
* @type bool $homepage Whether to return the plugin homepage link. Default true.
* @type bool $versions Whether to return the list of all available versions. Default false.
* @type bool $donate_link Whether to return the donation link. Default true.
* @type bool $reviews Whether to return the plugin reviews. Default false.
* @type bool $banners Whether to return the banner images links. Default false.
* @type bool $icons Whether to return the icon links. Default false.
* @type bool $active_installs Whether to return the number of active installs. Default false.
* @type bool $group Whether to return the assigned group. Default false.
* @type bool $contributors Whether to return the list of contributors. Default false.
* }
* }
* @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the
* {@link https://developer.wordpress.org/reference/functions/plugins_api/ function reference article}
* for more information on the make-up of possible return values depending on the value of `$action`.
*/
function plugins_api( $action, $args = array() ) {
if ( is_array( $args ) ) {
$args = (object) $args;
}
if ( ! isset( $args->per_page ) ) {
$args->per_page = 24;
}
if ( ! isset( $args->locale ) ) {
$args->locale = get_locale();
}
/**
* Filter the WordPress.org Plugin Install API arguments.
*
* Important: An object MUST be returned to this filter.
*
* @since 2.7.0
*
* @param object $args Plugin API arguments.
* @param string $action The type of information being requested from the Plugin Install API.
*/
$args = apply_filters( 'plugins_api_args', $args, $action );
/**
* Filter the response for the current WordPress.org Plugin Install API request.
*
* Passing a non-false value will effectively short-circuit the WordPress.org API request.
*
* If `$action` is 'query_plugins' or 'plugin_information', an object MUST be passed.
* If `$action` is 'hot_tags` or 'hot_categories', an array should be passed.
*
* @since 2.7.0
*
* @param false|object|array $result The result object or array. Default false.
* @param string $action The type of information being requested from the Plugin Install API.
* @param object $args Plugin API arguments.
*/
$res = apply_filters( 'plugins_api', false, $action, $args );
if ( false === $res ) {
$url = $http_url = 'http://api.wordpress.org/plugins/info/1.0/';
if ( $ssl = wp_http_supports( array( 'ssl' ) ) )
$url = set_url_scheme( $url, 'https' );
$http_args = array(
'timeout' => 15,
'body' => array(
'action' => $action,
'request' => serialize( $args )
)
);
$request = wp_remote_post( $url, $http_args );
if ( $ssl && is_wp_error( $request ) ) {
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
$request = wp_remote_post( $http_url, $http_args );
}
if ( is_wp_error($request) ) {
$res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() );
} else {
$res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
if ( ! is_object( $res ) && ! is_array( $res ) )
$res = new WP_Error('plugins_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) );
}
} elseif ( !is_wp_error($res) ) {
$res->external = true;
}
/**
* Filter the Plugin Install API response results.
*
* @since 2.7.0
*
* @param object|WP_Error $res Response object or WP_Error.
* @param string $action The type of information being requested from the Plugin Install API.
* @param object $args Plugin API arguments.
*/
return apply_filters( 'plugins_api_result', $res, $action, $args );
}
/**
* Retrieve popular WordPress plugin tags.
*
* @since 2.7.0
*
* @param array $args
* @return array
*/
function install_popular_tags( $args = array() ) {
$key = md5(serialize($args));
if ( false !== ($tags = get_site_transient('poptags_' . $key) ) )
return $tags;
$tags = plugins_api('hot_tags', $args);
if ( is_wp_error($tags) )
return $tags;
set_site_transient( 'poptags_' . $key, $tags, 3 * HOUR_IN_SECONDS );
return $tags;
}
/**
* @since 2.7.0
*/
function install_dashboard() {
?>
<p><?php printf( __( 'Plugins extend and expand the functionality of WordPress. You may automatically install plugins from the <a href="%1$s">WordPress Plugin Directory</a> or upload a plugin in .zip format via <a href="%2$s">this page</a>.' ), 'https://wordpress.org/plugins/', self_admin_url( 'plugin-install.php?tab=upload' ) ); ?></p>
<?php display_plugins_table(); ?>
<h2><?php _e( 'Popular tags' ) ?></h2>
<p><?php _e( 'You may also browse based on the most popular tags in the Plugin Directory:' ) ?></p>
<?php
$api_tags = install_popular_tags();
echo '<p class="popular-tags">';
if ( is_wp_error($api_tags) ) {
echo $api_tags->get_error_message();
} else {
//Set up the tags in a way which can be interpreted by wp_generate_tag_cloud()
$tags = array();
foreach ( (array) $api_tags as $tag ) {
$url = self_admin_url( 'plugin-install.php?tab=search&type=tag&s=' . urlencode( $tag['name'] ) );
$data = array(
'link' => esc_url( $url ),
'name' => $tag['name'],
'slug' => $tag['slug'],
'id' => sanitize_title_with_dashes( $tag['name'] ),
'count' => $tag['count']
);
$tags[ $tag['name'] ] = (object) $data;
}
echo wp_generate_tag_cloud($tags, array( 'single_text' => __('%s plugin'), 'multiple_text' => __('%s plugins') ) );
}
echo '</p><br class="clear" />';
}
/**
* Display search form for searching plugins.
*
* @since 2.7.0
*
* @param bool $type_selector
*/
function install_search_form( $type_selector = true ) {
$type = isset($_REQUEST['type']) ? wp_unslash( $_REQUEST['type'] ) : 'term';
$term = isset($_REQUEST['s']) ? wp_unslash( $_REQUEST['s'] ) : '';
$input_attrs = '';
$button_type = 'button screen-reader-text';
// assume no $type_selector means it's a simplified search form
if ( ! $type_selector ) {
$input_attrs = 'class="wp-filter-search" placeholder="' . esc_attr__( 'Search Plugins' ) . '" ';
}
?><form class="search-form search-plugins" method="get">
<input type="hidden" name="tab" value="search" />
<?php if ( $type_selector ) : ?>
<select name="type" id="typeselector">
<option value="term"<?php selected('term', $type) ?>><?php _e('Keyword'); ?></option>
<option value="author"<?php selected('author', $type) ?>><?php _e('Author'); ?></option>
<option value="tag"<?php selected('tag', $type) ?>><?php _ex('Tag', 'Plugin Installer'); ?></option>
</select>
<?php endif; ?>
<label><span class="screen-reader-text"><?php _e('Search Plugins'); ?></span>
<input type="search" name="s" value="<?php echo esc_attr($term) ?>" <?php echo $input_attrs; ?>/>
</label>
<?php submit_button( __( 'Search Plugins' ), $button_type, false, false, array( 'id' => 'search-submit' ) ); ?>
</form><?php
}
/**
* Upload from zip
* @since 2.8.0
*/
function install_plugins_upload() {
?>
<div class="upload-plugin">
<p class="install-help"><?php _e('If you have a plugin in a .zip format, you may install it by uploading it here.'); ?></p>
<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-plugin'); ?>">
<?php wp_nonce_field( 'plugin-upload' ); ?>
<label class="screen-reader-text" for="pluginzip"><?php _e( 'Plugin zip file' ); ?></label>
<input type="file" id="pluginzip" name="pluginzip" />
<?php submit_button( __( 'Install Now' ), 'button', 'install-plugin-submit', false ); ?>
</form>
</div>
<?php
}
/**
* Show a username form for the favorites page
* @since 3.5.0
*
*/
function install_plugins_favorites_form() {
$user = get_user_option( 'wporg_favorites' );
$action = 'save_wporg_username_' . get_current_user_id();
?>
<p class="install-help"><?php _e( 'If you have marked plugins as favorites on WordPress.org, you can browse them here.' ); ?></p>
<form method="get">
<input type="hidden" name="tab" value="favorites" />
<p>
<label for="user"><?php _e( 'Your WordPress.org username:' ); ?></label>
<input type="search" id="user" name="user" value="<?php echo esc_attr( $user ); ?>" />
<input type="submit" class="button" value="<?php esc_attr_e( 'Get Favorites' ); ?>" />
<input type="hidden" id="wporg-username-nonce" name="_wpnonce" value="<?php echo esc_attr( wp_create_nonce( $action ) ); ?>" />
</p>
</form>
<?php
}
/**
* Display plugin content based on plugin list.
*
* @since 2.7.0
*
* @global WP_List_Table $wp_list_table
*/
function display_plugins_table() {
global $wp_list_table;
switch ( current_filter() ) {
case 'install_plugins_favorites' :
if ( empty( $_GET['user'] ) && ! get_user_option( 'wporg_favorites' ) ) {
return;
}
break;
case 'install_plugins_recommended' :
echo '<p>' . __( 'These suggestions are based on the plugins you and other users have installed.' ) . '</p>';
break;
case 'install_plugins_beta' :
printf(
'<p>' . __( 'You are using a development version of WordPress. These feature plugins are also under development. <a href="%s">Learn more</a>.' ) . '</p>',
'https://make.wordpress.org/core/handbook/about/release-cycle/features-as-plugins/'
);
break;
}
?>
<form id="plugin-filter" method="post">
<?php $wp_list_table->display(); ?>
</form>
<?php
}
/**
* Determine the status we can perform on a plugin.
*
* @since 3.0.0
*
* @param array|object $api
* @param bool $loop
* @return type
*/
function install_plugin_install_status($api, $loop = false) {
// This function is called recursively, $loop prevents further loops.
if ( is_array($api) )
$api = (object) $api;
// Default to a "new" plugin
$status = 'install';
$url = false;
$update_file = false;
/*
* Check to see if this plugin is known to be installed,
* and has an update awaiting it.
*/
$update_plugins = get_site_transient('update_plugins');
if ( isset( $update_plugins->response ) ) {
foreach ( (array)$update_plugins->response as $file => $plugin ) {
if ( $plugin->slug === $api->slug ) {
$status = 'update_available';
$update_file = $file;
$version = $plugin->new_version;
if ( current_user_can('update_plugins') )
$url = wp_nonce_url(self_admin_url('update.php?action=upgrade-plugin&plugin=' . $update_file), 'upgrade-plugin_' . $update_file);
break;
}
}
}
if ( 'install' == $status ) {
if ( is_dir( WP_PLUGIN_DIR . '/' . $api->slug ) ) {
$installed_plugin = get_plugins('/' . $api->slug);
if ( empty($installed_plugin) ) {
if ( current_user_can('install_plugins') )
$url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $api->slug), 'install-plugin_' . $api->slug);
} else {
$key = array_keys( $installed_plugin );
$key = reset( $key ); //Use the first plugin regardless of the name, Could have issues for multiple-plugins in one directory if they share different version numbers
$update_file = $api->slug . '/' . $key;
if ( version_compare($api->version, $installed_plugin[ $key ]['Version'], '=') ){
$status = 'latest_installed';
} elseif ( version_compare($api->version, $installed_plugin[ $key ]['Version'], '<') ) {
$status = 'newer_installed';
$version = $installed_plugin[ $key ]['Version'];
} else {
//If the above update check failed, Then that probably means that the update checker has out-of-date information, force a refresh
if ( ! $loop ) {
delete_site_transient('update_plugins');
wp_update_plugins();
return install_plugin_install_status($api, true);
}
}
}
} else {
// "install" & no directory with that slug
if ( current_user_can('install_plugins') )
$url = wp_nonce_url(self_admin_url('update.php?action=install-plugin&plugin=' . $api->slug), 'install-plugin_' . $api->slug);
}
}
if ( isset($_GET['from']) )
$url .= '&amp;from=' . urlencode( wp_unslash( $_GET['from'] ) );
$file = $update_file;
return compact( 'status', 'url', 'version', 'file' );
}
/**
* Display plugin information in dialog box form.
*
* @since 2.7.0
*
* @global string $tab
* @global string $wp_version
*/
function install_plugin_information() {
global $tab;
if ( empty( $_REQUEST['plugin'] ) ) {
return;
}
$api = plugins_api( 'plugin_information', array(
'slug' => wp_unslash( $_REQUEST['plugin'] ),
'is_ssl' => is_ssl(),
'fields' => array(
'banners' => true,
'reviews' => true,
'downloaded' => false,
'active_installs' => true
)
) );
if ( is_wp_error( $api ) ) {
wp_die( $api );
}
$plugins_allowedtags = array(
'a' => array( 'href' => array(), 'title' => array(), 'target' => array() ),
'abbr' => array( 'title' => array() ), 'acronym' => array( 'title' => array() ),
'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(),
'div' => array( 'class' => array() ), 'span' => array( 'class' => array() ),
'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(),
'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(),
'img' => array( 'src' => array(), 'class' => array(), 'alt' => array() )
);
$plugins_section_titles = array(
'description' => _x( 'Description', 'Plugin installer section title' ),
'installation' => _x( 'Installation', 'Plugin installer section title' ),
'faq' => _x( 'FAQ', 'Plugin installer section title' ),
'screenshots' => _x( 'Screenshots', 'Plugin installer section title' ),
'changelog' => _x( 'Changelog', 'Plugin installer section title' ),
'reviews' => _x( 'Reviews', 'Plugin installer section title' ),
'other_notes' => _x( 'Other Notes', 'Plugin installer section title' )
);
// Sanitize HTML
foreach ( (array) $api->sections as $section_name => $content ) {
$api->sections[$section_name] = wp_kses( $content, $plugins_allowedtags );
}
foreach ( array( 'version', 'author', 'requires', 'tested', 'homepage', 'downloaded', 'slug' ) as $key ) {
if ( isset( $api->$key ) ) {
$api->$key = wp_kses( $api->$key, $plugins_allowedtags );
}
}
$_tab = esc_attr( $tab );
$section = isset( $_REQUEST['section'] ) ? wp_unslash( $_REQUEST['section'] ) : 'description'; // Default to the Description tab, Do not translate, API returns English.
if ( empty( $section ) || ! isset( $api->sections[ $section ] ) ) {
$section_titles = array_keys( (array) $api->sections );
$section = reset( $section_titles );
}
iframe_header( __( 'Plugin Install' ) );
$_with_banner = '';
if ( ! empty( $api->banners ) && ( ! empty( $api->banners['low'] ) || ! empty( $api->banners['high'] ) ) ) {
$_with_banner = 'with-banner';
$low = empty( $api->banners['low'] ) ? $api->banners['high'] : $api->banners['low'];
$high = empty( $api->banners['high'] ) ? $api->banners['low'] : $api->banners['high'];
?>
<style type="text/css">
#plugin-information-title.with-banner {
background-image: url( <?php echo esc_url( $low ); ?> );
}
@media only screen and ( -webkit-min-device-pixel-ratio: 1.5 ) {
#plugin-information-title.with-banner {
background-image: url( <?php echo esc_url( $high ); ?> );
}
}
</style>
<?php
}
echo '<div id="plugin-information-scrollable">';
echo "<div id='{$_tab}-title' class='{$_with_banner}'><div class='vignette'></div><h2>{$api->name}</h2></div>";
echo "<div id='{$_tab}-tabs' class='{$_with_banner}'>\n";
foreach ( (array) $api->sections as $section_name => $content ) {
if ( 'reviews' === $section_name && ( empty( $api->ratings ) || 0 === array_sum( (array) $api->ratings ) ) ) {
continue;
}
if ( isset( $plugins_section_titles[ $section_name ] ) ) {
$title = $plugins_section_titles[ $section_name ];
} else {
$title = ucwords( str_replace( '_', ' ', $section_name ) );
}
$class = ( $section_name === $section ) ? ' class="current"' : '';
$href = add_query_arg( array('tab' => $tab, 'section' => $section_name) );
$href = esc_url( $href );
$san_section = esc_attr( $section_name );
echo "\t<a name='$san_section' href='$href' $class>$title</a>\n";
}
echo "</div>\n";
?>
<div id="<?php echo $_tab; ?>-content" class='<?php echo $_with_banner; ?>'>
<div class="fyi">
<ul>
<?php if ( ! empty( $api->version ) ) { ?>
<li><strong><?php _e( 'Version:' ); ?></strong> <?php echo $api->version; ?></li>
<?php } if ( ! empty( $api->author ) ) { ?>
<li><strong><?php _e( 'Author:' ); ?></strong> <?php echo links_add_target( $api->author, '_blank' ); ?></li>
<?php } if ( ! empty( $api->last_updated ) ) { ?>
<li><strong><?php _e( 'Last Updated:' ); ?></strong>
<?php printf( __( '%s ago' ), human_time_diff( strtotime( $api->last_updated ) ) ); ?>
</li>
<?php } if ( ! empty( $api->requires ) ) { ?>
<li><strong><?php _e( 'Requires WordPress Version:' ); ?></strong> <?php printf( __( '%s or higher' ), $api->requires ); ?></li>
<?php } if ( ! empty( $api->tested ) ) { ?>
<li><strong><?php _e( 'Compatible up to:' ); ?></strong> <?php echo $api->tested; ?></li>
<?php } if ( ! empty( $api->active_installs ) ) { ?>
<li><strong><?php _e( 'Active Installs:' ); ?></strong> <?php
if ( $api->active_installs >= 1000000 ) {
_ex( '1+ Million', 'Active plugin installs' );
} else {
echo number_format_i18n( $api->active_installs ) . '+';
}
?></li>
<?php } if ( ! empty( $api->slug ) && empty( $api->external ) ) { ?>
<li><a target="_blank" href="https://wordpress.org/plugins/<?php echo $api->slug; ?>/"><?php _e( 'WordPress.org Plugin Page &#187;' ); ?></a></li>
<?php } if ( ! empty( $api->homepage ) ) { ?>
<li><a target="_blank" href="<?php echo esc_url( $api->homepage ); ?>"><?php _e( 'Plugin Homepage &#187;' ); ?></a></li>
<?php } if ( ! empty( $api->donate_link ) && empty( $api->contributors ) ) { ?>
<li><a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a></li>
<?php } ?>
</ul>
<?php if ( ! empty( $api->rating ) ) { ?>
<h3><?php _e( 'Average Rating' ); ?></h3>
<?php wp_star_rating( array( 'rating' => $api->rating, 'type' => 'percent', 'number' => $api->num_ratings ) ); ?>
<p aria-hidden="true" class="fyi-description"><?php printf( _n( '(based on %s rating)', '(based on %s ratings)', $api->num_ratings ), number_format_i18n( $api->num_ratings ) ); ?></p>
<?php }
if ( ! empty( $api->ratings ) && array_sum( (array) $api->ratings ) > 0 ) { ?>
<h3><?php _e( 'Reviews' ); ?></h3>
<p class="fyi-description"><?php _e( 'Read all reviews on WordPress.org or write your own!' ); ?></p>
<?php
foreach ( $api->ratings as $key => $ratecount ) {
// Avoid div-by-zero.
$_rating = $api->num_ratings ? ( $ratecount / $api->num_ratings ) : 0;
/* translators: 1: number of stars (used to determine singular/plural), 2: number of reviews */
$aria_label = esc_attr( sprintf( _n( 'Reviews with %1$d star: %2$s. Opens in a new window.', 'Reviews with %1$d stars: %2$s. Opens in a new window.', $key ),
$key,
number_format_i18n( $ratecount )
) );
?>
<div class="counter-container">
<span class="counter-label"><a href="https://wordpress.org/support/view/plugin-reviews/<?php echo $api->slug; ?>?filter=<?php echo $key; ?>"
target="_blank" aria-label="<?php echo $aria_label; ?>"><?php printf( _n( '%d star', '%d stars', $key ), $key ); ?></a></span>
<span class="counter-back">
<span class="counter-bar" style="width: <?php echo 92 * $_rating; ?>px;"></span>
</span>
<span class="counter-count" aria-hidden="true"><?php echo number_format_i18n( $ratecount ); ?></span>
</div>
<?php
}
}
if ( ! empty( $api->contributors ) ) { ?>
<h3><?php _e( 'Contributors' ); ?></h3>
<ul class="contributors">
<?php
foreach ( (array) $api->contributors as $contrib_username => $contrib_profile ) {
if ( empty( $contrib_username ) && empty( $contrib_profile ) ) {
continue;
}
if ( empty( $contrib_username ) ) {
$contrib_username = preg_replace( '/^.+\/(.+)\/?$/', '\1', $contrib_profile );
}
$contrib_username = sanitize_user( $contrib_username );
if ( empty( $contrib_profile ) ) {
echo "<li><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' alt='' />{$contrib_username}</li>";
} else {
echo "<li><a href='{$contrib_profile}' target='_blank'><img src='https://wordpress.org/grav-redirect.php?user={$contrib_username}&amp;s=36' width='18' height='18' alt='' />{$contrib_username}</a></li>";
}
}
?>
</ul>
<?php if ( ! empty( $api->donate_link ) ) { ?>
<a target="_blank" href="<?php echo esc_url( $api->donate_link ); ?>"><?php _e( 'Donate to this plugin &#187;' ); ?></a>
<?php } ?>
<?php } ?>
</div>
<div id="section-holder" class="wrap">
<?php
if ( ! empty( $api->tested ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->tested ) ), $api->tested, '>' ) ) {
echo '<div class="notice notice-warning notice-alt"><p>' . __( '<strong>Warning:</strong> This plugin has <strong>not been tested</strong> with your current version of WordPress.' ) . '</p></div>';
} elseif ( ! empty( $api->requires ) && version_compare( substr( $GLOBALS['wp_version'], 0, strlen( $api->requires ) ), $api->requires, '<' ) ) {
echo '<div class="notice notice-warning notice-alt"><p>' . __( '<strong>Warning:</strong> This plugin has <strong>not been marked as compatible</strong> with your version of WordPress.' ) . '</p></div>';
}
foreach ( (array) $api->sections as $section_name => $content ) {
$content = links_add_base_url( $content, 'https://wordpress.org/plugins/' . $api->slug . '/' );
$content = links_add_target( $content, '_blank' );
$san_section = esc_attr( $section_name );
$display = ( $section_name === $section ) ? 'block' : 'none';
echo "\t<div id='section-{$san_section}' class='section' style='display: {$display};'>\n";
echo $content;
echo "\t</div>\n";
}
echo "</div>\n";
echo "</div>\n";
echo "</div>\n"; // #plugin-information-scrollable
echo "<div id='$tab-footer'>\n";
if ( ! empty( $api->download_link ) && ( current_user_can( 'install_plugins' ) || current_user_can( 'update_plugins' ) ) ) {
$status = install_plugin_install_status( $api );
switch ( $status['status'] ) {
case 'install':
if ( $status['url'] ) {
echo '<a class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Now' ) . '</a>';
}
break;
case 'update_available':
if ( $status['url'] ) {
echo '<a data-slug="' . esc_attr( $api->slug ) . '" data-plugin="' . esc_attr( $status['file'] ) . '" id="plugin_update_from_iframe" class="button button-primary right" href="' . $status['url'] . '" target="_parent">' . __( 'Install Update Now' ) .'</a>';
}
break;
case 'newer_installed':
echo '<a class="button button-primary right disabled">' . sprintf( __( 'Newer Version (%s) Installed'), $status['version'] ) . '</a>';
break;
case 'latest_installed':
echo '<a class="button button-primary right disabled">' . __( 'Latest Version Installed' ) . '</a>';
break;
}
}
echo "</div>\n";
iframe_footer();
exit;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,403 @@
<?php
/**
* WordPress Administration Revisions API
*
* @package WordPress
* @subpackage Administration
* @since 3.6.0
*/
/**
* Get the revision UI diff.
*
* @since 3.6.0
*
* @param object|int $post The post object. Also accepts a post ID.
* @param int $compare_from The revision ID to compare from.
* @param int $compare_to The revision ID to come to.
*
* @return array|bool Associative array of a post's revisioned fields and their diffs.
* Or, false on failure.
*/
function wp_get_revision_ui_diff( $post, $compare_from, $compare_to ) {
if ( ! $post = get_post( $post ) )
return false;
if ( $compare_from ) {
if ( ! $compare_from = get_post( $compare_from ) )
return false;
} else {
// If we're dealing with the first revision...
$compare_from = false;
}
if ( ! $compare_to = get_post( $compare_to ) )
return false;
// If comparing revisions, make sure we're dealing with the right post parent.
// The parent post may be a 'revision' when revisions are disabled and we're looking at autosaves.
if ( $compare_from && $compare_from->post_parent !== $post->ID && $compare_from->ID !== $post->ID )
return false;
if ( $compare_to->post_parent !== $post->ID && $compare_to->ID !== $post->ID )
return false;
if ( $compare_from && strtotime( $compare_from->post_date_gmt ) > strtotime( $compare_to->post_date_gmt ) ) {
$temp = $compare_from;
$compare_from = $compare_to;
$compare_to = $temp;
}
// Add default title if title field is empty
if ( $compare_from && empty( $compare_from->post_title ) )
$compare_from->post_title = __( '(no title)' );
if ( empty( $compare_to->post_title ) )
$compare_to->post_title = __( '(no title)' );
$return = array();
foreach ( _wp_post_revision_fields( $post ) as $field => $name ) {
/**
* Contextually filter a post revision field.
*
* The dynamic portion of the hook name, `$field`, corresponds to each of the post
* fields of the revision object being iterated over in a foreach statement.
*
* @since 3.6.0
*
* @param string $compare_from->$field The current revision field to compare to or from.
* @param string $field The current revision field.
* @param WP_Post $compare_from The revision post object to compare to or from.
* @param string null The context of whether the current revision is the old
* or the new one. Values are 'to' or 'from'.
*/
$content_from = $compare_from ? apply_filters( "_wp_post_revision_field_$field", $compare_from->$field, $field, $compare_from, 'from' ) : '';
/** This filter is documented in wp-admin/includes/revision.php */
$content_to = apply_filters( "_wp_post_revision_field_$field", $compare_to->$field, $field, $compare_to, 'to' );
$args = array(
'show_split_view' => true
);
/**
* Filter revisions text diff options.
*
* Filter the options passed to {@see wp_text_diff()} when viewing a post revision.
*
* @since 4.1.0
*
* @param array $args {
* Associative array of options to pass to {@see wp_text_diff()}.
*
* @type bool $show_split_view True for split view (two columns), false for
* un-split view (single column). Default true.
* }
* @param string $field The current revision field.
* @param WP_Post $compare_from The revision post to compare from.
* @param WP_Post $compare_to The revision post to compare to.
*/
$args = apply_filters( 'revision_text_diff_options', $args, $field, $compare_from, $compare_to );
$diff = wp_text_diff( $content_from, $content_to, $args );
if ( ! $diff && 'post_title' === $field ) {
// It's a better user experience to still show the Title, even if it didn't change.
// No, you didn't see this.
$diff = '<table class="diff"><colgroup><col class="content diffsplit left"><col class="content diffsplit middle"><col class="content diffsplit right"></colgroup><tbody><tr>';
$diff .= '<td>' . esc_html( $compare_from->post_title ) . '</td><td></td><td>' . esc_html( $compare_to->post_title ) . '</td>';
$diff .= '</tr></tbody>';
$diff .= '</table>';
}
if ( $diff ) {
$return[] = array(
'id' => $field,
'name' => $name,
'diff' => $diff,
);
}
}
/**
* Filter the fields displayed in the post revision diff UI.
*
* @since 4.1.0
*
* @param array $return Revision UI fields. Each item is an array of id, name and diff.
* @param WP_Post $compare_from The revision post to compare from.
* @param WP_Post $compare_to The revision post to compare to.
*/
return apply_filters( 'wp_get_revision_ui_diff', $return, $compare_from, $compare_to );
}
/**
* Prepare revisions for JavaScript.
*
* @since 3.6.0
*
* @param object|int $post The post object. Also accepts a post ID.
* @param int $selected_revision_id The selected revision ID.
* @param int $from Optional. The revision ID to compare from.
*
* @return array An associative array of revision data and related settings.
*/
function wp_prepare_revisions_for_js( $post, $selected_revision_id, $from = null ) {
$post = get_post( $post );
$authors = array();
$now_gmt = time();
$revisions = wp_get_post_revisions( $post->ID, array( 'order' => 'ASC', 'check_enabled' => false ) );
// If revisions are disabled, we only want autosaves and the current post.
if ( ! wp_revisions_enabled( $post ) ) {
foreach ( $revisions as $revision_id => $revision ) {
if ( ! wp_is_post_autosave( $revision ) )
unset( $revisions[ $revision_id ] );
}
$revisions = array( $post->ID => $post ) + $revisions;
}
$show_avatars = get_option( 'show_avatars' );
cache_users( wp_list_pluck( $revisions, 'post_author' ) );
$can_restore = current_user_can( 'edit_post', $post->ID );
$current_id = false;
foreach ( $revisions as $revision ) {
$modified = strtotime( $revision->post_modified );
$modified_gmt = strtotime( $revision->post_modified_gmt );
if ( $can_restore ) {
$restore_link = str_replace( '&amp;', '&', wp_nonce_url(
add_query_arg(
array( 'revision' => $revision->ID,
'action' => 'restore' ),
admin_url( 'revision.php' )
),
"restore-post_{$revision->ID}"
) );
}
if ( ! isset( $authors[ $revision->post_author ] ) ) {
$authors[ $revision->post_author ] = array(
'id' => (int) $revision->post_author,
'avatar' => $show_avatars ? get_avatar( $revision->post_author, 32 ) : '',
'name' => get_the_author_meta( 'display_name', $revision->post_author ),
);
}
$autosave = (bool) wp_is_post_autosave( $revision );
$current = ! $autosave && $revision->post_modified_gmt === $post->post_modified_gmt;
if ( $current && ! empty( $current_id ) ) {
// If multiple revisions have the same post_modified_gmt, highest ID is current.
if ( $current_id < $revision->ID ) {
$revisions[ $current_id ]['current'] = false;
$current_id = $revision->ID;
} else {
$current = false;
}
} elseif ( $current ) {
$current_id = $revision->ID;
}
$revisions_data = array(
'id' => $revision->ID,
'title' => get_the_title( $post->ID ),
'author' => $authors[ $revision->post_author ],
'date' => date_i18n( __( 'M j, Y @ H:i' ), $modified ),
'dateShort' => date_i18n( _x( 'j M @ H:i', 'revision date short format' ), $modified ),
'timeAgo' => sprintf( __( '%s ago' ), human_time_diff( $modified_gmt, $now_gmt ) ),
'autosave' => $autosave,
'current' => $current,
'restoreUrl' => $can_restore ? $restore_link : false,
);
/**
* Filter the array of revisions used on the revisions screen.
*
* @since 4.4.0
*
* @param array $revisions_data {
* The bootstrapped data for the revisions screen.
*
* @type int $id Revision ID.
* @type string $title Title for the revision's parent WP_Post object.
* @type int $author Revision post author ID.
* @type string $date Date the revision was modified.
* @type string $dateShort Short-form version of the date the revision was modified.
* @type string $timeAgo GMT-aware amount of time ago the revision was modified.
* @type bool $autosave Whether the revision is an autosave.
* @type bool $current Whether the revision is both not an autosave and the post
* modified date matches the revision modified date (GMT-aware).
* @type bool|false $restoreUrl URL if the revision can be restored, false otherwise.
* }
* @param WP_Post $revision The revision's WP_Post object.
* @param WP_Post $post The revision's parent WP_Post object.
*/
$revisions[ $revision->ID ] = apply_filters( 'wp_prepare_revision_for_js', $revisions_data, $revision, $post );
}
/**
* If we only have one revision, the initial revision is missing; This happens
* when we have an autsosave and the user has clicked 'View the Autosave'
*/
if ( 1 === sizeof( $revisions ) ) {
$revisions[ $post->ID ] = array(
'id' => $post->ID,
'title' => get_the_title( $post->ID ),
'author' => $authors[ $post->post_author ],
'date' => date_i18n( __( 'M j, Y @ H:i' ), strtotime( $post->post_modified ) ),
'dateShort' => date_i18n( _x( 'j M @ H:i', 'revision date short format' ), strtotime( $post->post_modified ) ),
'timeAgo' => sprintf( __( '%s ago' ), human_time_diff( strtotime( $post->post_modified_gmt ), $now_gmt ) ),
'autosave' => false,
'current' => true,
'restoreUrl' => false,
);
$current_id = $post->ID;
}
/*
* If a post has been saved since the last revision (no revisioned fields
* were changed), we may not have a "current" revision. Mark the latest
* revision as "current".
*/
if ( empty( $current_id ) ) {
if ( $revisions[ $revision->ID ]['autosave'] ) {
$revision = end( $revisions );
while ( $revision['autosave'] ) {
$revision = prev( $revisions );
}
$current_id = $revision['id'];
} else {
$current_id = $revision->ID;
}
$revisions[ $current_id ]['current'] = true;
}
// Now, grab the initial diff.
$compare_two_mode = is_numeric( $from );
if ( ! $compare_two_mode ) {
$found = array_search( $selected_revision_id, array_keys( $revisions ) );
if ( $found ) {
$from = array_keys( array_slice( $revisions, $found - 1, 1, true ) );
$from = reset( $from );
} else {
$from = 0;
}
}
$from = absint( $from );
$diffs = array( array(
'id' => $from . ':' . $selected_revision_id,
'fields' => wp_get_revision_ui_diff( $post->ID, $from, $selected_revision_id ),
));
return array(
'postId' => $post->ID,
'nonce' => wp_create_nonce( 'revisions-ajax-nonce' ),
'revisionData' => array_values( $revisions ),
'to' => $selected_revision_id,
'from' => $from,
'diffData' => $diffs,
'baseUrl' => parse_url( admin_url( 'revision.php' ), PHP_URL_PATH ),
'compareTwoMode' => absint( $compare_two_mode ), // Apparently booleans are not allowed
'revisionIds' => array_keys( $revisions ),
);
}
/**
* Print JavaScript templates required for the revisions experience.
*
* @since 4.1.0
*
* @global WP_Post $post The global `$post` object.
*/
function wp_print_revision_templates() {
global $post;
?><script id="tmpl-revisions-frame" type="text/html">
<div class="revisions-control-frame"></div>
<div class="revisions-diff-frame"></div>
</script>
<script id="tmpl-revisions-buttons" type="text/html">
<div class="revisions-previous">
<input class="button" type="button" value="<?php echo esc_attr_x( 'Previous', 'Button label for a previous revision' ); ?>" />
</div>
<div class="revisions-next">
<input class="button" type="button" value="<?php echo esc_attr_x( 'Next', 'Button label for a next revision' ); ?>" />
</div>
</script>
<script id="tmpl-revisions-checkbox" type="text/html">
<div class="revision-toggle-compare-mode">
<label>
<input type="checkbox" class="compare-two-revisions"
<#
if ( 'undefined' !== typeof data && data.model.attributes.compareTwoMode ) {
#> checked="checked"<#
}
#>
/>
<?php esc_attr_e( 'Compare any two revisions' ); ?>
</label>
</div>
</script>
<script id="tmpl-revisions-meta" type="text/html">
<# if ( ! _.isUndefined( data.attributes ) ) { #>
<div class="diff-title">
<# if ( 'from' === data.type ) { #>
<strong><?php _ex( 'From:', 'Followed by post revision info' ); ?></strong>
<# } else if ( 'to' === data.type ) { #>
<strong><?php _ex( 'To:', 'Followed by post revision info' ); ?></strong>
<# } #>
<div class="author-card<# if ( data.attributes.autosave ) { #> autosave<# } #>">
{{{ data.attributes.author.avatar }}}
<div class="author-info">
<# if ( data.attributes.autosave ) { #>
<span class="byline"><?php printf( __( 'Autosave by %s' ),
'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
<# } else if ( data.attributes.current ) { #>
<span class="byline"><?php printf( __( 'Current Revision by %s' ),
'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
<# } else { #>
<span class="byline"><?php printf( __( 'Revision by %s' ),
'<span class="author-name">{{ data.attributes.author.name }}</span>' ); ?></span>
<# } #>
<span class="time-ago">{{ data.attributes.timeAgo }}</span>
<span class="date">({{ data.attributes.dateShort }})</span>
</div>
<# if ( 'to' === data.type && data.attributes.restoreUrl ) { #>
<input <?php if ( wp_check_post_lock( $post->ID ) ) { ?>
disabled="disabled"
<?php } else { ?>
<# if ( data.attributes.current ) { #>
disabled="disabled"
<# } #>
<?php } ?>
<# if ( data.attributes.autosave ) { #>
type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Autosave' ); ?>" />
<# } else { #>
type="button" class="restore-revision button button-primary" value="<?php esc_attr_e( 'Restore This Revision' ); ?>" />
<# } #>
<# } #>
</div>
<# if ( 'tooltip' === data.type ) { #>
<div class="revisions-tooltip-arrow"><span></span></div>
<# } #>
<# } #>
</script>
<script id="tmpl-revisions-diff" type="text/html">
<div class="loading-indicator"><span class="spinner"></span></div>
<div class="diff-error"><?php _e( 'Sorry, something went wrong. The requested comparison could not be loaded.' ); ?></div>
<div class="diff">
<# _.each( data.fields, function( field ) { #>
<h3>{{ field.name }}</h3>
{{{ field.diff }}}
<# }); #>
</div>
</script><?php
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,224 @@
<?php
/**
* WordPress Administration Screen API.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Get the column headers for a screen
*
* @since 2.7.0
*
* @staticvar array $column_headers
*
* @param string|WP_Screen $screen The screen you want the headers for
* @return array Containing the headers in the format id => UI String
*/
function get_column_headers( $screen ) {
if ( is_string( $screen ) )
$screen = convert_to_screen( $screen );
static $column_headers = array();
if ( ! isset( $column_headers[ $screen->id ] ) ) {
/**
* Filter the column headers for a list table on a specific screen.
*
* The dynamic portion of the hook name, `$screen->id`, refers to the
* ID of a specific screen. For example, the screen ID for the Posts
* list table is edit-post, so the filter for that screen would be
* manage_edit-post_columns.
*
* @since 3.0.0
*
* @param array $columns An array of column headers. Default empty.
*/
$column_headers[ $screen->id ] = apply_filters( "manage_{$screen->id}_columns", array() );
}
return $column_headers[ $screen->id ];
}
/**
* Get a list of hidden columns.
*
* @since 2.7.0
*
* @param string|WP_Screen $screen The screen you want the hidden columns for
* @return array
*/
function get_hidden_columns( $screen ) {
if ( is_string( $screen ) ) {
$screen = convert_to_screen( $screen );
}
$hidden = get_user_option( 'manage' . $screen->id . 'columnshidden' );
$use_defaults = ! is_array( $hidden );
if ( $use_defaults ) {
$hidden = array();
/**
* Filter the default list of hidden columns.
*
* @since 4.4.0
*
* @param array $hidden An array of columns hidden by default.
* @param WP_Screen $screen WP_Screen object of the current screen.
*/
$hidden = apply_filters( 'default_hidden_columns', $hidden, $screen );
}
/**
* Filter the list of hidden columns.
*
* @since 4.4.0
* @since 4.4.1 Added the `use_defaults` parameter.
*
* @param array $hidden An array of hidden columns.
* @param WP_Screen $screen WP_Screen object of the current screen.
* @param bool $use_defaults Whether to show the default columns.
*/
return apply_filters( 'hidden_columns', $hidden, $screen, $use_defaults );
}
/**
* Prints the meta box preferences for screen meta.
*
* @since 2.7.0
*
* @global array $wp_meta_boxes
*
* @param WP_Screen $screen
*/
function meta_box_prefs( $screen ) {
global $wp_meta_boxes;
if ( is_string( $screen ) )
$screen = convert_to_screen( $screen );
if ( empty($wp_meta_boxes[$screen->id]) )
return;
$hidden = get_hidden_meta_boxes($screen);
foreach ( array_keys( $wp_meta_boxes[ $screen->id ] ) as $context ) {
foreach ( array( 'high', 'core', 'default', 'low' ) as $priority ) {
if ( ! isset( $wp_meta_boxes[ $screen->id ][ $context ][ $priority ] ) ) {
continue;
}
foreach ( $wp_meta_boxes[ $screen->id ][ $context ][ $priority ] as $box ) {
if ( false == $box || ! $box['title'] )
continue;
// Submit box cannot be hidden
if ( 'submitdiv' == $box['id'] || 'linksubmitdiv' == $box['id'] )
continue;
$box_id = $box['id'];
echo '<label for="' . $box_id . '-hide">';
echo '<input class="hide-postbox-tog" name="' . $box_id . '-hide" type="checkbox" id="' . $box_id . '-hide" value="' . $box_id . '"' . (! in_array($box_id, $hidden) ? ' checked="checked"' : '') . ' />';
echo "{$box['title']}</label>\n";
}
}
}
}
/**
* Get Hidden Meta Boxes
*
* @since 2.7.0
*
* @param string|WP_Screen $screen Screen identifier
* @return array Hidden Meta Boxes
*/
function get_hidden_meta_boxes( $screen ) {
if ( is_string( $screen ) )
$screen = convert_to_screen( $screen );
$hidden = get_user_option( "metaboxhidden_{$screen->id}" );
$use_defaults = ! is_array( $hidden );
// Hide slug boxes by default
if ( $use_defaults ) {
$hidden = array();
if ( 'post' == $screen->base ) {
if ( 'post' == $screen->post_type || 'page' == $screen->post_type || 'attachment' == $screen->post_type )
$hidden = array('slugdiv', 'trackbacksdiv', 'postcustom', 'postexcerpt', 'commentstatusdiv', 'commentsdiv', 'authordiv', 'revisionsdiv');
else
$hidden = array( 'slugdiv' );
}
/**
* Filter the default list of hidden meta boxes.
*
* @since 3.1.0
*
* @param array $hidden An array of meta boxes hidden by default.
* @param WP_Screen $screen WP_Screen object of the current screen.
*/
$hidden = apply_filters( 'default_hidden_meta_boxes', $hidden, $screen );
}
/**
* Filter the list of hidden meta boxes.
*
* @since 3.3.0
*
* @param array $hidden An array of hidden meta boxes.
* @param WP_Screen $screen WP_Screen object of the current screen.
* @param bool $use_defaults Whether to show the default meta boxes.
* Default true.
*/
return apply_filters( 'hidden_meta_boxes', $hidden, $screen, $use_defaults );
}
/**
* Register and configure an admin screen option
*
* @since 3.1.0
*
* @param string $option An option name.
* @param mixed $args Option-dependent arguments.
*/
function add_screen_option( $option, $args = array() ) {
$current_screen = get_current_screen();
if ( ! $current_screen )
return;
$current_screen->add_option( $option, $args );
}
/**
* Get the current screen object
*
* @since 3.1.0
*
* @global WP_Screen $current_screen
*
* @return WP_Screen Current screen object
*/
function get_current_screen() {
global $current_screen;
if ( ! isset( $current_screen ) )
return null;
return $current_screen;
}
/**
* Set the current screen object
*
* @since 3.0.0
*
* @param mixed $hook_name Optional. The hook name (also known as the hook suffix) used to determine the screen,
* or an existing screen object.
*/
function set_current_screen( $hook_name = '' ) {
WP_Screen::get( $hook_name )->set_current_screen();
}

View File

@@ -0,0 +1,290 @@
<?php
/**
* WordPress Taxonomy Administration API.
*
* @package WordPress
* @subpackage Administration
*/
//
// Category
//
/**
* Check whether a category exists.
*
* @since 2.0.0
*
* @see term_exists()
*
* @param int|string $cat_name Category name.
* @param int $parent Optional. ID of parent term.
* @return mixed
*/
function category_exists( $cat_name, $parent = null ) {
$id = term_exists($cat_name, 'category', $parent);
if ( is_array($id) )
$id = $id['term_id'];
return $id;
}
/**
* Get category object for given ID and 'edit' filter context.
*
* @since 2.0.0
*
* @param int $id
* @return object
*/
function get_category_to_edit( $id ) {
$category = get_term( $id, 'category', OBJECT, 'edit' );
_make_cat_compat( $category );
return $category;
}
/**
* Add a new category to the database if it does not already exist.
*
* @since 2.0.0
*
* @param int|string $cat_name
* @param int $parent
* @return int|WP_Error
*/
function wp_create_category( $cat_name, $parent = 0 ) {
if ( $id = category_exists($cat_name, $parent) )
return $id;
return wp_insert_category( array('cat_name' => $cat_name, 'category_parent' => $parent) );
}
/**
* Create categories for the given post.
*
* @since 2.0.0
*
* @param array $categories List of categories to create.
* @param int $post_id Optional. The post ID. Default empty.
* @return array List of categories to create for the given post.
*/
function wp_create_categories( $categories, $post_id = '' ) {
$cat_ids = array ();
foreach ( $categories as $category ) {
if ( $id = category_exists( $category ) ) {
$cat_ids[] = $id;
} elseif ( $id = wp_create_category( $category ) ) {
$cat_ids[] = $id;
}
}
if ( $post_id )
wp_set_post_categories($post_id, $cat_ids);
return $cat_ids;
}
/**
* Updates an existing Category or creates a new Category.
*
* @since 2.0.0
* @since 2.5.0 $wp_error parameter was added.
* @since 3.0.0 The 'taxonomy' argument was added.
*
* @param array $catarr {
* Array of arguments for inserting a new category.
*
* @type int $cat_ID Category ID. A non-zero value updates an existing category.
* Default 0.
* @type string $taxonomy Taxonomy slug. Default 'category'.
* @type string $cat_name Category name. Default empty.
* @type string $category_description Category description. Default empty.
* @type string $category_nicename Category nice (display) name. Default empty.
* @type int|string $category_parent Category parent ID. Default empty.
* }
* @param bool $wp_error Optional. Default false.
* @return int|object The ID number of the new or updated Category on success. Zero or a WP_Error on failure,
* depending on param $wp_error.
*/
function wp_insert_category( $catarr, $wp_error = false ) {
$cat_defaults = array( 'cat_ID' => 0, 'taxonomy' => 'category', 'cat_name' => '', 'category_description' => '', 'category_nicename' => '', 'category_parent' => '' );
$catarr = wp_parse_args( $catarr, $cat_defaults );
if ( trim( $catarr['cat_name'] ) == '' ) {
if ( ! $wp_error ) {
return 0;
} else {
return new WP_Error( 'cat_name', __( 'You did not enter a category name.' ) );
}
}
$catarr['cat_ID'] = (int) $catarr['cat_ID'];
// Are we updating or creating?
$update = ! empty ( $catarr['cat_ID'] );
$name = $catarr['cat_name'];
$description = $catarr['category_description'];
$slug = $catarr['category_nicename'];
$parent = (int) $catarr['category_parent'];
if ( $parent < 0 ) {
$parent = 0;
}
if ( empty( $parent )
|| ! term_exists( $parent, $catarr['taxonomy'] )
|| ( $catarr['cat_ID'] && term_is_ancestor_of( $catarr['cat_ID'], $parent, $catarr['taxonomy'] ) ) ) {
$parent = 0;
}
$args = compact('name', 'slug', 'parent', 'description');
if ( $update ) {
$catarr['cat_ID'] = wp_update_term( $catarr['cat_ID'], $catarr['taxonomy'], $args );
} else {
$catarr['cat_ID'] = wp_insert_term( $catarr['cat_name'], $catarr['taxonomy'], $args );
}
if ( is_wp_error( $catarr['cat_ID'] ) ) {
if ( $wp_error ) {
return $catarr['cat_ID'];
} else {
return 0;
}
}
return $catarr['cat_ID']['term_id'];
}
/**
* Aliases wp_insert_category() with minimal args.
*
* If you want to update only some fields of an existing category, call this
* function with only the new values set inside $catarr.
*
* @since 2.0.0
*
* @param array $catarr The 'cat_ID' value is required. All other keys are optional.
* @return int|bool The ID number of the new or updated Category on success. Zero or FALSE on failure.
*/
function wp_update_category($catarr) {
$cat_ID = (int) $catarr['cat_ID'];
if ( isset($catarr['category_parent']) && ($cat_ID == $catarr['category_parent']) )
return false;
// First, get all of the original fields
$category = get_term( $cat_ID, 'category', ARRAY_A );
_make_cat_compat( $category );
// Escape data pulled from DB.
$category = wp_slash($category);
// Merge old and new fields with new fields overwriting old ones.
$catarr = array_merge($category, $catarr);
return wp_insert_category($catarr);
}
//
// Tags
//
/**
* Check whether a post tag with a given name exists.
*
* @since 2.3.0
*
* @param int|string $tag_name
* @return mixed
*/
function tag_exists($tag_name) {
return term_exists($tag_name, 'post_tag');
}
/**
* Add a new tag to the database if it does not already exist.
*
* @since 2.3.0
*
* @param int|string $tag_name
* @return array|WP_Error
*/
function wp_create_tag($tag_name) {
return wp_create_term( $tag_name, 'post_tag');
}
/**
* Get comma-separated list of tags available to edit.
*
* @since 2.3.0
*
* @param int $post_id
* @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
* @return string|bool|WP_Error
*/
function get_tags_to_edit( $post_id, $taxonomy = 'post_tag' ) {
return get_terms_to_edit( $post_id, $taxonomy);
}
/**
* Get comma-separated list of terms available to edit for the given post ID.
*
* @since 2.8.0
*
* @param int $post_id
* @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
* @return string|bool|WP_Error
*/
function get_terms_to_edit( $post_id, $taxonomy = 'post_tag' ) {
$post_id = (int) $post_id;
if ( !$post_id )
return false;
$terms = get_object_term_cache( $post_id, $taxonomy );
if ( false === $terms ) {
$terms = wp_get_object_terms( $post_id, $taxonomy );
wp_cache_add( $post_id, $terms, $taxonomy . '_relationships' );
}
if ( ! $terms ) {
return false;
}
if ( is_wp_error( $terms ) ) {
return $terms;
}
$term_names = array();
foreach ( $terms as $term ) {
$term_names[] = $term->name;
}
$terms_to_edit = esc_attr( join( ',', $term_names ) );
/**
* Filter the comma-separated list of terms available to edit.
*
* @since 2.8.0
*
* @see get_terms_to_edit()
*
* @param array $terms_to_edit An array of terms.
* @param string $taxonomy The taxonomy for which to retrieve terms. Default 'post_tag'.
*/
$terms_to_edit = apply_filters( 'terms_to_edit', $terms_to_edit, $taxonomy );
return $terms_to_edit;
}
/**
* Add a new term to the database if it does not already exist.
*
* @since 2.8.0
*
* @param int|string $tag_name
* @param string $taxonomy Optional. The taxonomy for which to retrieve terms. Default 'post_tag'.
* @return array|WP_Error
*/
function wp_create_term($tag_name, $taxonomy = 'post_tag') {
if ( $id = term_exists($tag_name, $taxonomy) )
return $id;
return wp_insert_term($tag_name, $taxonomy);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,212 @@
<?php
/**
* WordPress Theme Install Administration API
*
* @package WordPress
* @subpackage Administration
*/
$themes_allowedtags = array('a' => array('href' => array(), 'title' => array(), 'target' => array()),
'abbr' => array('title' => array()), 'acronym' => array('title' => array()),
'code' => array(), 'pre' => array(), 'em' => array(), 'strong' => array(),
'div' => array(), 'p' => array(), 'ul' => array(), 'ol' => array(), 'li' => array(),
'h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(),
'img' => array('src' => array(), 'class' => array(), 'alt' => array())
);
$theme_field_defaults = array( 'description' => true, 'sections' => false, 'tested' => true, 'requires' => true,
'rating' => true, 'downloaded' => true, 'downloadlink' => true, 'last_updated' => true, 'homepage' => true,
'tags' => true, 'num_ratings' => true
);
/**
* Retrieve list of WordPress theme features (aka theme tags)
*
* @since 2.8.0
*
* @deprecated since 3.1.0 Use get_theme_feature_list() instead.
*
* @return array
*/
function install_themes_feature_list() {
_deprecated_function( __FUNCTION__, '3.1', 'get_theme_feature_list()' );
if ( !$cache = get_transient( 'wporg_theme_feature_list' ) )
set_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS );
if ( $cache )
return $cache;
$feature_list = themes_api( 'feature_list', array() );
if ( is_wp_error( $feature_list ) )
return array();
set_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS );
return $feature_list;
}
/**
* Display search form for searching themes.
*
* @since 2.8.0
*
* @param bool $type_selector
*/
function install_theme_search_form( $type_selector = true ) {
$type = isset( $_REQUEST['type'] ) ? wp_unslash( $_REQUEST['type'] ) : 'term';
$term = isset( $_REQUEST['s'] ) ? wp_unslash( $_REQUEST['s'] ) : '';
if ( ! $type_selector )
echo '<p class="install-help">' . __( 'Search for themes by keyword.' ) . '</p>';
?>
<form id="search-themes" method="get">
<input type="hidden" name="tab" value="search" />
<?php if ( $type_selector ) : ?>
<label class="screen-reader-text" for="typeselector"><?php _e('Type of search'); ?></label>
<select name="type" id="typeselector">
<option value="term" <?php selected('term', $type) ?>><?php _e('Keyword'); ?></option>
<option value="author" <?php selected('author', $type) ?>><?php _e('Author'); ?></option>
<option value="tag" <?php selected('tag', $type) ?>><?php _ex('Tag', 'Theme Installer'); ?></option>
</select>
<label class="screen-reader-text" for="s"><?php
switch ( $type ) {
case 'term':
_e( 'Search by keyword' );
break;
case 'author':
_e( 'Search by author' );
break;
case 'tag':
_e( 'Search by tag' );
break;
}
?></label>
<?php else : ?>
<label class="screen-reader-text" for="s"><?php _e('Search by keyword'); ?></label>
<?php endif; ?>
<input type="search" name="s" id="s" size="30" value="<?php echo esc_attr($term) ?>" autofocus="autofocus" />
<?php submit_button( __( 'Search' ), 'button', 'search', false ); ?>
</form>
<?php
}
/**
* Display tags filter for themes.
*
* @since 2.8.0
*/
function install_themes_dashboard() {
install_theme_search_form( false );
?>
<h4><?php _e('Feature Filter') ?></h4>
<p class="install-help"><?php _e( 'Find a theme based on specific features.' ); ?></p>
<form method="get">
<input type="hidden" name="tab" value="search" />
<?php
$feature_list = get_theme_feature_list();
echo '<div class="feature-filter">';
foreach ( (array) $feature_list as $feature_name => $features ) {
$feature_name = esc_html( $feature_name );
echo '<div class="feature-name">' . $feature_name . '</div>';
echo '<ol class="feature-group">';
foreach ( $features as $feature => $feature_name ) {
$feature_name = esc_html( $feature_name );
$feature = esc_attr($feature);
?>
<li>
<input type="checkbox" name="features[]" id="feature-id-<?php echo $feature; ?>" value="<?php echo $feature; ?>" />
<label for="feature-id-<?php echo $feature; ?>"><?php echo $feature_name; ?></label>
</li>
<?php } ?>
</ol>
<br class="clear" />
<?php
} ?>
</div>
<br class="clear" />
<?php submit_button( __( 'Find Themes' ), 'button', 'search' ); ?>
</form>
<?php
}
/**
* @since 2.8.0
*/
function install_themes_upload() {
?>
<p class="install-help"><?php _e('If you have a theme in a .zip format, you may install it by uploading it here.'); ?></p>
<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-theme'); ?>">
<?php wp_nonce_field( 'theme-upload' ); ?>
<label class="screen-reader-text" for="themezip"><?php _e( 'Theme zip file' ); ?></label>
<input type="file" id="themezip" name="themezip" />
<?php submit_button( __( 'Install Now' ), 'button', 'install-theme-submit', false ); ?>
</form>
<?php
}
/**
* Prints a theme on the Install Themes pages.
*
* @deprecated 3.4.0
*
* @global WP_Theme_Install_List_Table $wp_list_table
*
* @param object $theme
*/
function display_theme( $theme ) {
_deprecated_function( __FUNCTION__, '3.4' );
global $wp_list_table;
if ( ! isset( $wp_list_table ) ) {
$wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
}
$wp_list_table->prepare_items();
$wp_list_table->single_row( $theme );
}
/**
* Display theme content based on theme list.
*
* @since 2.8.0
*
* @global WP_Theme_Install_List_Table $wp_list_table
*/
function display_themes() {
global $wp_list_table;
if ( ! isset( $wp_list_table ) ) {
$wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
}
$wp_list_table->prepare_items();
$wp_list_table->display();
}
/**
* Display theme information in dialog box form.
*
* @since 2.8.0
*
* @global WP_Theme_Install_List_Table $wp_list_table
*/
function install_theme_information() {
global $wp_list_table;
$theme = themes_api( 'theme_information', array( 'slug' => wp_unslash( $_REQUEST['theme'] ) ) );
if ( is_wp_error( $theme ) )
wp_die( $theme );
iframe_header( __('Theme Install') );
if ( ! isset( $wp_list_table ) ) {
$wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
}
$wp_list_table->theme_installer_single( $theme );
iframe_footer();
exit;
}

View File

@@ -0,0 +1,652 @@
<?php
/**
* WordPress Theme Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Remove a theme
*
* @since 2.8.0
*
* @global WP_Filesystem_Base $wp_filesystem Subclass
*
* @param string $stylesheet Stylesheet of the theme to delete
* @param string $redirect Redirect to page when complete.
* @return void|bool|WP_Error When void, echoes content.
*/
function delete_theme($stylesheet, $redirect = '') {
global $wp_filesystem;
if ( empty($stylesheet) )
return false;
ob_start();
if ( empty( $redirect ) )
$redirect = wp_nonce_url('themes.php?action=delete&stylesheet=' . urlencode( $stylesheet ), 'delete-theme_' . $stylesheet);
if ( false === ($credentials = request_filesystem_credentials($redirect)) ) {
$data = ob_get_clean();
if ( ! empty($data) ){
include_once( ABSPATH . 'wp-admin/admin-header.php');
echo $data;
include( ABSPATH . 'wp-admin/admin-footer.php');
exit;
}
return;
}
if ( ! WP_Filesystem($credentials) ) {
request_filesystem_credentials($redirect, '', true); // Failed to connect, Error and request again
$data = ob_get_clean();
if ( ! empty($data) ) {
include_once( ABSPATH . 'wp-admin/admin-header.php');
echo $data;
include( ABSPATH . 'wp-admin/admin-footer.php');
exit;
}
return;
}
if ( ! is_object($wp_filesystem) )
return new WP_Error('fs_unavailable', __('Could not access filesystem.'));
if ( is_wp_error($wp_filesystem->errors) && $wp_filesystem->errors->get_error_code() )
return new WP_Error('fs_error', __('Filesystem error.'), $wp_filesystem->errors);
// Get the base plugin folder.
$themes_dir = $wp_filesystem->wp_themes_dir();
if ( empty( $themes_dir ) ) {
return new WP_Error( 'fs_no_themes_dir', __( 'Unable to locate WordPress theme directory.' ) );
}
$themes_dir = trailingslashit( $themes_dir );
$theme_dir = trailingslashit( $themes_dir . $stylesheet );
$deleted = $wp_filesystem->delete( $theme_dir, true );
if ( ! $deleted ) {
return new WP_Error( 'could_not_remove_theme', sprintf( __( 'Could not fully remove the theme %s.' ), $stylesheet ) );
}
$theme_translations = wp_get_installed_translations( 'themes' );
// Remove language files, silently.
if ( ! empty( $theme_translations[ $stylesheet ] ) ) {
$translations = $theme_translations[ $stylesheet ];
foreach ( $translations as $translation => $data ) {
$wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.po' );
$wp_filesystem->delete( WP_LANG_DIR . '/themes/' . $stylesheet . '-' . $translation . '.mo' );
}
}
// Force refresh of theme update information.
delete_site_transient( 'update_themes' );
return true;
}
/**
* Get the Page Templates available in this theme
*
* @since 1.5.0
*
* @param WP_Post|null $post Optional. The post being edited, provided for context.
* @return array Key is the template name, value is the filename of the template
*/
function get_page_templates( $post = null ) {
return array_flip( wp_get_theme()->get_page_templates( $post ) );
}
/**
* Tidies a filename for url display by the theme editor.
*
* @since 2.9.0
* @access private
*
* @param string $fullpath Full path to the theme file
* @param string $containingfolder Path of the theme parent folder
* @return string
*/
function _get_template_edit_filename($fullpath, $containingfolder) {
return str_replace(dirname(dirname( $containingfolder )) , '', $fullpath);
}
/**
* Check if there is an update for a theme available.
*
* Will display link, if there is an update available.
*
* @since 2.7.0
* @see get_theme_update_available()
*
* @param WP_Theme $theme Theme data object.
*/
function theme_update_available( $theme ) {
echo get_theme_update_available( $theme );
}
/**
* Retrieve the update link if there is a theme update available.
*
* Will return a link if there is an update available.
*
* @since 3.8.0
*
* @staticvar object $themes_update
*
* @param WP_Theme $theme WP_Theme object.
* @return false|string HTML for the update link, or false if invalid info was passed.
*/
function get_theme_update_available( $theme ) {
static $themes_update = null;
if ( !current_user_can('update_themes' ) )
return false;
if ( !isset($themes_update) )
$themes_update = get_site_transient('update_themes');
if ( ! ( $theme instanceof WP_Theme ) ) {
return false;
}
$stylesheet = $theme->get_stylesheet();
$html = '';
if ( isset($themes_update->response[ $stylesheet ]) ) {
$update = $themes_update->response[ $stylesheet ];
$theme_name = $theme->display('Name');
$details_url = add_query_arg(array('TB_iframe' => 'true', 'width' => 1024, 'height' => 800), $update['url']); //Theme browser inside WP? replace this, Also, theme preview JS will override this on the available list.
$update_url = wp_nonce_url( admin_url( 'update.php?action=upgrade-theme&amp;theme=' . urlencode( $stylesheet ) ), 'upgrade-theme_' . $stylesheet );
if ( !is_multisite() ) {
if ( ! current_user_can('update_themes') ) {
/* translators: 1: theme name, 2: theme details URL, 3: accessibility text, 4: version number */
$html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" aria-label="%3$s">View version %4$s details</a>.' ) . '</strong></p>',
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ),
$update['new_version']
);
} elseif ( empty( $update['package'] ) ) {
/* translators: 1: theme name, 2: theme details URL, 3: accessibility text, 4: version number */
$html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" aria-label="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ) . '</strong></p>',
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ),
$update['new_version']
);
} else {
/* translators: 1: theme name, 2: theme details URL, 3: accessibility text, 4: version number, 5: update URL, 6: accessibility text */
$html = sprintf( '<p><strong>' . __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox" aria-label="%3$s">View version %4$s details</a> or <a href="%5$s" aria-label="%6$s">update now</a>.' ) . '</strong></p>',
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $update['new_version'] ) ),
$update['new_version'],
$update_url,
/* translators: %s: theme name */
esc_attr( sprintf( __( 'Update %s now' ), $theme_name ) )
);
}
}
}
return $html;
}
/**
* Retrieve list of WordPress theme features (aka theme tags)
*
* @since 3.1.0
*
* @param bool $api Optional. Whether try to fetch tags from the WordPress.org API. Defaults to true.
* @return array Array of features keyed by category with translations keyed by slug.
*/
function get_theme_feature_list( $api = true ) {
// Hard-coded list is used if api not accessible.
$features = array(
__( 'Colors' ) => array(
'black' => __( 'Black' ),
'blue' => __( 'Blue' ),
'brown' => __( 'Brown' ),
'gray' => __( 'Gray' ),
'green' => __( 'Green' ),
'orange' => __( 'Orange' ),
'pink' => __( 'Pink' ),
'purple' => __( 'Purple' ),
'red' => __( 'Red' ),
'silver' => __( 'Silver' ),
'tan' => __( 'Tan' ),
'white' => __( 'White' ),
'yellow' => __( 'Yellow' ),
'dark' => __( 'Dark' ),
'light' => __( 'Light' ),
),
__( 'Layout' ) => array(
'fixed-layout' => __( 'Fixed Layout' ),
'fluid-layout' => __( 'Fluid Layout' ),
'responsive-layout' => __( 'Responsive Layout' ),
'one-column' => __( 'One Column' ),
'two-columns' => __( 'Two Columns' ),
'three-columns' => __( 'Three Columns' ),
'four-columns' => __( 'Four Columns' ),
'left-sidebar' => __( 'Left Sidebar' ),
'right-sidebar' => __( 'Right Sidebar' ),
),
__( 'Features' ) => array(
'accessibility-ready' => __( 'Accessibility Ready' ),
'blavatar' => __( 'Blavatar' ),
'buddypress' => __( 'BuddyPress' ),
'custom-background' => __( 'Custom Background' ),
'custom-colors' => __( 'Custom Colors' ),
'custom-header' => __( 'Custom Header' ),
'custom-menu' => __( 'Custom Menu' ),
'editor-style' => __( 'Editor Style' ),
'featured-image-header' => __( 'Featured Image Header' ),
'featured-images' => __( 'Featured Images' ),
'flexible-header' => __( 'Flexible Header' ),
'front-page-post-form' => __( 'Front Page Posting' ),
'full-width-template' => __( 'Full Width Template' ),
'microformats' => __( 'Microformats' ),
'post-formats' => __( 'Post Formats' ),
'rtl-language-support' => __( 'RTL Language Support' ),
'sticky-post' => __( 'Sticky Post' ),
'theme-options' => __( 'Theme Options' ),
'threaded-comments' => __( 'Threaded Comments' ),
'translation-ready' => __( 'Translation Ready' ),
),
__( 'Subject' ) => array(
'holiday' => __( 'Holiday' ),
'photoblogging' => __( 'Photoblogging' ),
'seasonal' => __( 'Seasonal' ),
)
);
if ( ! $api || ! current_user_can( 'install_themes' ) )
return $features;
if ( !$feature_list = get_site_transient( 'wporg_theme_feature_list' ) )
set_site_transient( 'wporg_theme_feature_list', array(), 3 * HOUR_IN_SECONDS );
if ( !$feature_list ) {
$feature_list = themes_api( 'feature_list', array() );
if ( is_wp_error( $feature_list ) )
return $features;
}
if ( !$feature_list )
return $features;
set_site_transient( 'wporg_theme_feature_list', $feature_list, 3 * HOUR_IN_SECONDS );
$category_translations = array(
'Colors' => __( 'Colors' ),
'Layout' => __( 'Layout' ),
'Features' => __( 'Features' ),
'Subject' => __( 'Subject' )
);
// Loop over the wporg canonical list and apply translations
$wporg_features = array();
foreach ( (array) $feature_list as $feature_category => $feature_items ) {
if ( isset($category_translations[$feature_category]) )
$feature_category = $category_translations[$feature_category];
$wporg_features[$feature_category] = array();
foreach ( $feature_items as $feature ) {
if ( isset($features[$feature_category][$feature]) )
$wporg_features[$feature_category][$feature] = $features[$feature_category][$feature];
else
$wporg_features[$feature_category][$feature] = $feature;
}
}
return $wporg_features;
}
/**
* Retrieves theme installer pages from the WordPress.org Themes API.
*
* It is possible for a theme to override the Themes API result with three
* filters. Assume this is for themes, which can extend on the Theme Info to
* offer more choices. This is very powerful and must be used with care, when
* overriding the filters.
*
* The first filter, {@see 'themes_api_args'}, is for the args and gives the action
* as the second parameter. The hook for {@see 'themes_api_args'} must ensure that
* an object is returned.
*
* The second filter, {@see 'themes_api'}, allows a plugin to override the WordPress.org
* Theme API entirely. If `$action` is 'query_themes', 'theme_information', or 'feature_list',
* an object MUST be passed. If `$action` is 'hot_tags`, an array should be passed.
*
* Finally, the third filter, {@see 'themes_api_result'}, makes it possible to filter the
* response object or array, depending on the `$action` type.
*
* Supported arguments per action:
*
* | Argument Name | 'query_themes' | 'theme_information' | 'hot_tags' | 'feature_list' |
* | -------------------| :------------: | :-----------------: | :--------: | :--------------: |
* | `$slug` | No | Yes | No | No |
* | `$per_page` | Yes | No | No | No |
* | `$page` | Yes | No | No | No |
* | `$number` | No | No | Yes | No |
* | `$search` | Yes | No | No | No |
* | `$tag` | Yes | No | No | No |
* | `$author` | Yes | No | No | No |
* | `$user` | Yes | No | No | No |
* | `$browse` | Yes | No | No | No |
* | `$locale` | Yes | Yes | No | No |
* | `$fields` | Yes | Yes | No | No |
*
* @since 2.8.0
*
* @param string $action API action to perform: 'query_themes', 'theme_information',
* 'hot_tags' or 'feature_list'.
* @param array|object $args {
* Optional. Array or object of arguments to serialize for the Plugin Info API.
*
* @type string $slug The plugin slug. Default empty.
* @type int $per_page Number of themes per page. Default 24.
* @type int $page Number of current page. Default 1.
* @type int $number Number of tags to be queried.
* @type string $search A search term. Default empty.
* @type string $tag Tag to filter themes. Default empty.
* @type string $author Username of an author to filter themes. Default empty.
* @type string $user Username to query for their favorites. Default empty.
* @type string $browse Browse view: 'featured', 'popular', 'updated', 'favorites'.
* @type string $locale Locale to provide context-sensitive results. Default is the value of get_locale().
* @type array $fields {
* Array of fields which should or should not be returned.
*
* @type bool $description Whether to return the theme full description. Default false.
* @type bool $sections Whether to return the theme readme sections: description, installation,
* FAQ, screenshots, other notes, and changelog. Default false.
* @type bool $rating Whether to return the rating in percent and total number of ratings.
* Default false.
* @type bool $ratings Whether to return the number of rating for each star (1-5). Default false.
* @type bool $downloaded Whether to return the download count. Default false.
* @type bool $downloadlink Whether to return the download link for the package. Default false.
* @type bool $last_updated Whether to return the date of the last update. Default false.
* @type bool $tags Whether to return the assigned tags. Default false.
* @type bool $homepage Whether to return the theme homepage link. Default false.
* @type bool $screenshots Whether to return the screenshots. Default false.
* @type int $screenshot_count Number of screenshots to return. Default 1.
* @type bool $screenshot_url Whether to return the URL of the first screenshot. Default false.
* @type bool $photon_screenshots Whether to return the screenshots via Photon. Default false.
* @type bool $template Whether to return the slug of the parent theme. Default false.
* @type bool $parent Whether to return the slug, name and homepage of the parent theme. Default false.
* @type bool $versions Whether to return the list of all available versions. Default false.
* @type bool $theme_url Whether to return theme's URL. Default false.
* @type bool $extended_author Whether to return nicename or nicename and display name. Default false.
* }
* }
* @return object|array|WP_Error Response object or array on success, WP_Error on failure. See the
* {@link https://developer.wordpress.org/reference/functions/themes_api/ function reference article}
* for more information on the make-up of possible return objects depending on the value of `$action`.
*/
function themes_api( $action, $args = array() ) {
if ( is_array( $args ) ) {
$args = (object) $args;
}
if ( ! isset( $args->per_page ) ) {
$args->per_page = 24;
}
if ( ! isset( $args->locale ) ) {
$args->locale = get_locale();
}
/**
* Filter arguments used to query for installer pages from the WordPress.org Themes API.
*
* Important: An object MUST be returned to this filter.
*
* @since 2.8.0
*
* @param object $args Arguments used to query for installer pages from the WordPress.org Themes API.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
*/
$args = apply_filters( 'themes_api_args', $args, $action );
/**
* Filter whether to override the WordPress.org Themes API.
*
* Passing a non-false value will effectively short-circuit the WordPress.org API request.
*
* If `$action` is 'query_themes', 'theme_information', or 'feature_list', an object MUST
* be passed. If `$action` is 'hot_tags`, an array should be passed.
*
* @since 2.8.0
*
* @param false|object|array $override Whether to override the WordPress.org Themes API. Default false.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
* @param object $args Arguments used to query for installer pages from the Themes API.
*/
$res = apply_filters( 'themes_api', false, $action, $args );
if ( ! $res ) {
$url = $http_url = 'http://api.wordpress.org/themes/info/1.0/';
if ( $ssl = wp_http_supports( array( 'ssl' ) ) )
$url = set_url_scheme( $url, 'https' );
$http_args = array(
'body' => array(
'action' => $action,
'request' => serialize( $args )
)
);
$request = wp_remote_post( $url, $http_args );
if ( $ssl && is_wp_error( $request ) ) {
if ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) {
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
}
$request = wp_remote_post( $http_url, $http_args );
}
if ( is_wp_error($request) ) {
$res = new WP_Error('themes_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() );
} else {
$res = maybe_unserialize( wp_remote_retrieve_body( $request ) );
if ( ! is_object( $res ) && ! is_array( $res ) )
$res = new WP_Error('themes_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) );
}
}
/**
* Filter the returned WordPress.org Themes API response.
*
* @since 2.8.0
*
* @param array|object $res WordPress.org Themes API response.
* @param string $action Requested action. Likely values are 'theme_information',
* 'feature_list', or 'query_themes'.
* @param object $args Arguments used to query for installer pages from the WordPress.org Themes API.
*/
return apply_filters( 'themes_api_result', $res, $action, $args );
}
/**
* Prepare themes for JavaScript.
*
* @since 3.8.0
*
* @param array $themes Optional. Array of WP_Theme objects to prepare.
* Defaults to all allowed themes.
*
* @return array An associative array of theme data, sorted by name.
*/
function wp_prepare_themes_for_js( $themes = null ) {
$current_theme = get_stylesheet();
/**
* Filter theme data before it is prepared for JavaScript.
*
* Passing a non-empty array will result in wp_prepare_themes_for_js() returning
* early with that value instead.
*
* @since 4.2.0
*
* @param array $prepared_themes An associative array of theme data. Default empty array.
* @param null|array $themes An array of WP_Theme objects to prepare, if any.
* @param string $current_theme The current theme slug.
*/
$prepared_themes = (array) apply_filters( 'pre_prepare_themes_for_js', array(), $themes, $current_theme );
if ( ! empty( $prepared_themes ) ) {
return $prepared_themes;
}
// Make sure the current theme is listed first.
$prepared_themes[ $current_theme ] = array();
if ( null === $themes ) {
$themes = wp_get_themes( array( 'allowed' => true ) );
if ( ! isset( $themes[ $current_theme ] ) ) {
$themes[ $current_theme ] = wp_get_theme();
}
}
$updates = array();
if ( current_user_can( 'update_themes' ) ) {
$updates_transient = get_site_transient( 'update_themes' );
if ( isset( $updates_transient->response ) ) {
$updates = $updates_transient->response;
}
}
WP_Theme::sort_by_name( $themes );
$parents = array();
foreach ( $themes as $theme ) {
$slug = $theme->get_stylesheet();
$encoded_slug = urlencode( $slug );
$parent = false;
if ( $theme->parent() ) {
$parent = $theme->parent()->display( 'Name' );
$parents[ $slug ] = $theme->parent()->get_stylesheet();
}
$customize_action = null;
if ( current_user_can( 'edit_theme_options' ) && current_user_can( 'customize' ) ) {
$customize_action = esc_url( add_query_arg(
array(
'return' => urlencode( esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ) ),
),
wp_customize_url( $slug )
) );
}
$prepared_themes[ $slug ] = array(
'id' => $slug,
'name' => $theme->display( 'Name' ),
'screenshot' => array( $theme->get_screenshot() ), // @todo multiple
'description' => $theme->display( 'Description' ),
'author' => $theme->display( 'Author', false, true ),
'authorAndUri' => $theme->display( 'Author' ),
'version' => $theme->display( 'Version' ),
'tags' => $theme->display( 'Tags' ),
'parent' => $parent,
'active' => $slug === $current_theme,
'hasUpdate' => isset( $updates[ $slug ] ),
'update' => get_theme_update_available( $theme ),
'actions' => array(
'activate' => current_user_can( 'switch_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=activate&amp;stylesheet=' . $encoded_slug ), 'switch-theme_' . $slug ) : null,
'customize' => $customize_action,
'delete' => current_user_can( 'delete_themes' ) ? wp_nonce_url( admin_url( 'themes.php?action=delete&amp;stylesheet=' . $encoded_slug ), 'delete-theme_' . $slug ) : null,
),
);
}
// Remove 'delete' action if theme has an active child
if ( ! empty( $parents ) && array_key_exists( $current_theme, $parents ) ) {
unset( $prepared_themes[ $parents[ $current_theme ] ]['actions']['delete'] );
}
/**
* Filter the themes prepared for JavaScript, for themes.php.
*
* Could be useful for changing the order, which is by name by default.
*
* @since 3.8.0
*
* @param array $prepared_themes Array of themes.
*/
$prepared_themes = apply_filters( 'wp_prepare_themes_for_js', $prepared_themes );
$prepared_themes = array_values( $prepared_themes );
return array_filter( $prepared_themes );
}
/**
* Print JS templates for the theme-browsing UI in the Customizer.
*
* @since 4.2.0
*/
function customize_themes_print_templates() {
$preview_url = esc_url( add_query_arg( 'theme', '__THEME__' ) ); // Token because esc_url() strips curly braces.
$preview_url = str_replace( '__THEME__', '{{ data.id }}', $preview_url );
?>
<script type="text/html" id="tmpl-customize-themes-details-view">
<div class="theme-backdrop"></div>
<div class="theme-wrap wp-clearfix">
<div class="theme-header">
<button type="button" class="left dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show previous theme' ); ?></span></button>
<button type="button" class="right dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Show next theme' ); ?></span></button>
<button type="button" class="close dashicons dashicons-no"><span class="screen-reader-text"><?php _e( 'Close details dialog' ); ?></span></button>
</div>
<div class="theme-about wp-clearfix">
<div class="theme-screenshots">
<# if ( data.screenshot[0] ) { #>
<div class="screenshot"><img src="{{ data.screenshot[0] }}" alt="" /></div>
<# } else { #>
<div class="screenshot blank"></div>
<# } #>
</div>
<div class="theme-info">
<# if ( data.active ) { #>
<span class="current-label"><?php _e( 'Current Theme' ); ?></span>
<# } #>
<h2 class="theme-name">{{{ data.name }}}<span class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></span></h2>
<h3 class="theme-author"><?php printf( __( 'By %s' ), '{{{ data.authorAndUri }}}' ); ?></h3>
<p class="theme-description">{{{ data.description }}}</p>
<# if ( data.parent ) { #>
<p class="parent-theme"><?php printf( __( 'This is a child theme of %s.' ), '<strong>{{{ data.parent }}}</strong>' ); ?></p>
<# } #>
<# if ( data.tags ) { #>
<p class="theme-tags"><span><?php _e( 'Tags:' ); ?></span> {{ data.tags }}</p>
<# } #>
</div>
</div>
<# if ( ! data.active ) { #>
<div class="theme-actions">
<div class="inactive-theme">
<a href="<?php echo $preview_url; ?>" target="_top" class="button button-primary"><?php _e( 'Live Preview' ); ?></a>
</div>
</div>
<# } #>
</div>
</script>
<?php
}

View File

@@ -0,0 +1,243 @@
<?php
/**
* WordPress Translation Install Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Retrieve translations from WordPress Translation API.
*
* @since 4.0.0
*
* @param string $type Type of translations. Accepts 'plugins', 'themes', 'core'.
* @param array|object $args Translation API arguments. Optional.
* @return object|WP_Error On success an object of translations, WP_Error on failure.
*/
function translations_api( $type, $args = null ) {
include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version
if ( ! in_array( $type, array( 'plugins', 'themes', 'core' ) ) ) {
return new WP_Error( 'invalid_type', __( 'Invalid translation type.' ) );
}
/**
* Allows a plugin to override the WordPress.org Translation Install API entirely.
*
* @since 4.0.0
*
* @param bool|array $result The result object. Default false.
* @param string $type The type of translations being requested.
* @param object $args Translation API arguments.
*/
$res = apply_filters( 'translations_api', false, $type, $args );
if ( false === $res ) {
$url = $http_url = 'http://api.wordpress.org/translations/' . $type . '/1.0/';
if ( $ssl = wp_http_supports( array( 'ssl' ) ) ) {
$url = set_url_scheme( $url, 'https' );
}
$options = array(
'timeout' => 3,
'body' => array(
'wp_version' => $wp_version,
'locale' => get_locale(),
'version' => $args['version'], // Version of plugin, theme or core
),
);
if ( 'core' !== $type ) {
$options['body']['slug'] = $args['slug']; // Plugin or theme slug
}
$request = wp_remote_post( $url, $options );
if ( $ssl && is_wp_error( $request ) ) {
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
$request = wp_remote_post( $http_url, $options );
}
if ( is_wp_error( $request ) ) {
$res = new WP_Error( 'translations_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), $request->get_error_message() );
} else {
$res = json_decode( wp_remote_retrieve_body( $request ), true );
if ( ! is_object( $res ) && ! is_array( $res ) ) {
$res = new WP_Error( 'translations_api_failed', __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ), wp_remote_retrieve_body( $request ) );
}
}
}
/**
* Filter the Translation Install API response results.
*
* @since 4.0.0
*
* @param object|WP_Error $res Response object or WP_Error.
* @param string $type The type of translations being requested.
* @param object $args Translation API arguments.
*/
return apply_filters( 'translations_api_result', $res, $type, $args );
}
/**
* Get available translations from the WordPress.org API.
*
* @since 4.0.0
*
* @see translations_api()
*
* @return array Array of translations, each an array of data. If the API response results
* in an error, an empty array will be returned.
*/
function wp_get_available_translations() {
if ( ! wp_installing() && false !== ( $translations = get_site_transient( 'available_translations' ) ) ) {
return $translations;
}
include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version
$api = translations_api( 'core', array( 'version' => $wp_version ) );
if ( is_wp_error( $api ) || empty( $api['translations'] ) ) {
return array();
}
$translations = array();
// Key the array with the language code for now.
foreach ( $api['translations'] as $translation ) {
$translations[ $translation['language'] ] = $translation;
}
if ( ! defined( 'WP_INSTALLING' ) ) {
set_site_transient( 'available_translations', $translations, 3 * HOUR_IN_SECONDS );
}
return $translations;
}
/**
* Output the select form for the language selection on the installation screen.
*
* @since 4.0.0
*
* @global string $wp_local_package
*
* @param array $languages Array of available languages (populated via the Translation API).
*/
function wp_install_language_form( $languages ) {
global $wp_local_package;
$installed_languages = get_available_languages();
echo "<label class='screen-reader-text' for='language'>Select a default language</label>\n";
echo "<select size='14' name='language' id='language'>\n";
echo '<option value="" lang="en" selected="selected" data-continue="Continue" data-installed="1">English (United States)</option>';
echo "\n";
if ( ! empty( $wp_local_package ) && isset( $languages[ $wp_local_package ] ) ) {
if ( isset( $languages[ $wp_local_package ] ) ) {
$language = $languages[ $wp_local_package ];
printf( '<option value="%s" lang="%s" data-continue="%s"%s>%s</option>' . "\n",
esc_attr( $language['language'] ),
esc_attr( current( $language['iso'] ) ),
esc_attr( $language['strings']['continue'] ),
in_array( $language['language'], $installed_languages ) ? ' data-installed="1"' : '',
esc_html( $language['native_name'] ) );
unset( $languages[ $wp_local_package ] );
}
}
foreach ( $languages as $language ) {
printf( '<option value="%s" lang="%s" data-continue="%s"%s>%s</option>' . "\n",
esc_attr( $language['language'] ),
esc_attr( current( $language['iso'] ) ),
esc_attr( $language['strings']['continue'] ),
in_array( $language['language'], $installed_languages ) ? ' data-installed="1"' : '',
esc_html( $language['native_name'] ) );
}
echo "</select>\n";
echo '<p class="step"><span class="spinner"></span><input id="language-continue" type="submit" class="button button-primary button-large" value="Continue" /></p>';
}
/**
* Download a language pack.
*
* @since 4.0.0
*
* @see wp_get_available_translations()
*
* @param string $download Language code to download.
* @return string|bool Returns the language code if successfully downloaded
* (or already installed), or false on failure.
*/
function wp_download_language_pack( $download ) {
// Check if the translation is already installed.
if ( in_array( $download, get_available_languages() ) ) {
return $download;
}
if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
return false;
}
// Confirm the translation is one we can download.
$translations = wp_get_available_translations();
if ( ! $translations ) {
return false;
}
foreach ( $translations as $translation ) {
if ( $translation['language'] === $download ) {
$translation_to_load = true;
break;
}
}
if ( empty( $translation_to_load ) ) {
return false;
}
$translation = (object) $translation;
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$skin = new Automatic_Upgrader_Skin;
$upgrader = new Language_Pack_Upgrader( $skin );
$translation->type = 'core';
$result = $upgrader->upgrade( $translation, array( 'clear_update_cache' => false ) );
if ( ! $result || is_wp_error( $result ) ) {
return false;
}
return $translation->language;
}
/**
* Check if WordPress has access to the filesystem without asking for
* credentials.
*
* @since 4.0.0
*
* @return bool Returns true on success, false on failure.
*/
function wp_can_install_language_pack() {
if ( defined( 'DISALLOW_FILE_MODS' ) && DISALLOW_FILE_MODS ) {
return false;
}
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
$skin = new Automatic_Upgrader_Skin;
$upgrader = new Language_Pack_Upgrader( $skin );
$upgrader->init();
$check = $upgrader->fs_connect( array( WP_CONTENT_DIR, WP_LANG_DIR ) );
if ( ! $check || is_wp_error( $check ) ) {
return false;
}
return true;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,559 @@
<?php
/**
* WordPress Administration Update API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Selects the first update version from the update_core option.
*
* @return object|array|false The response from the API on success, false on failure.
*/
function get_preferred_from_update_core() {
$updates = get_core_updates();
if ( ! is_array( $updates ) )
return false;
if ( empty( $updates ) )
return (object) array( 'response' => 'latest' );
return $updates[0];
}
/**
* Get available core updates.
*
* @param array $options Set $options['dismissed'] to true to show dismissed upgrades too,
* set $options['available'] to false to skip not-dismissed updates.
* @return array|false Array of the update objects on success, false on failure.
*/
function get_core_updates( $options = array() ) {
$options = array_merge( array( 'available' => true, 'dismissed' => false ), $options );
$dismissed = get_site_option( 'dismissed_update_core' );
if ( ! is_array( $dismissed ) )
$dismissed = array();
$from_api = get_site_transient( 'update_core' );
if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) )
return false;
$updates = $from_api->updates;
$result = array();
foreach ( $updates as $update ) {
if ( $update->response == 'autoupdate' )
continue;
if ( array_key_exists( $update->current . '|' . $update->locale, $dismissed ) ) {
if ( $options['dismissed'] ) {
$update->dismissed = true;
$result[] = $update;
}
} else {
if ( $options['available'] ) {
$update->dismissed = false;
$result[] = $update;
}
}
}
return $result;
}
/**
* Gets the best available (and enabled) Auto-Update for WordPress Core.
*
* If there's 1.2.3 and 1.3 on offer, it'll choose 1.3 if the install allows it, else, 1.2.3
*
* @since 3.7.0
*
* @return array|false False on failure, otherwise the core update offering.
*/
function find_core_auto_update() {
$updates = get_site_transient( 'update_core' );
if ( ! $updates || empty( $updates->updates ) )
return false;
include_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
$auto_update = false;
$upgrader = new WP_Automatic_Updater;
foreach ( $updates->updates as $update ) {
if ( 'autoupdate' != $update->response )
continue;
if ( ! $upgrader->should_update( 'core', $update, ABSPATH ) )
continue;
if ( ! $auto_update || version_compare( $update->current, $auto_update->current, '>' ) )
$auto_update = $update;
}
return $auto_update;
}
/**
* Gets and caches the checksums for the given version of WordPress.
*
* @since 3.7.0
*
* @param string $version Version string to query.
* @param string $locale Locale to query.
* @return bool|array False on failure. An array of checksums on success.
*/
function get_core_checksums( $version, $locale ) {
$url = $http_url = 'http://api.wordpress.org/core/checksums/1.0/?' . http_build_query( compact( 'version', 'locale' ), null, '&' );
if ( $ssl = wp_http_supports( array( 'ssl' ) ) )
$url = set_url_scheme( $url, 'https' );
$options = array(
'timeout' => ( ( defined('DOING_CRON') && DOING_CRON ) ? 30 : 3 ),
);
$response = wp_remote_get( $url, $options );
if ( $ssl && is_wp_error( $response ) ) {
trigger_error( __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ) . ' ' . __( '(WordPress could not establish a secure connection to WordPress.org. Please contact your server administrator.)' ), headers_sent() || WP_DEBUG ? E_USER_WARNING : E_USER_NOTICE );
$response = wp_remote_get( $http_url, $options );
}
if ( is_wp_error( $response ) || 200 != wp_remote_retrieve_response_code( $response ) )
return false;
$body = trim( wp_remote_retrieve_body( $response ) );
$body = json_decode( $body, true );
if ( ! is_array( $body ) || ! isset( $body['checksums'] ) || ! is_array( $body['checksums'] ) )
return false;
return $body['checksums'];
}
/**
*
* @param object $update
* @return bool
*/
function dismiss_core_update( $update ) {
$dismissed = get_site_option( 'dismissed_update_core' );
$dismissed[ $update->current . '|' . $update->locale ] = true;
return update_site_option( 'dismissed_update_core', $dismissed );
}
/**
*
* @param string $version
* @param string $locale
* @return bool
*/
function undismiss_core_update( $version, $locale ) {
$dismissed = get_site_option( 'dismissed_update_core' );
$key = $version . '|' . $locale;
if ( ! isset( $dismissed[$key] ) )
return false;
unset( $dismissed[$key] );
return update_site_option( 'dismissed_update_core', $dismissed );
}
/**
*
* @param string $version
* @param string $locale
* @return object|false
*/
function find_core_update( $version, $locale ) {
$from_api = get_site_transient( 'update_core' );
if ( ! isset( $from_api->updates ) || ! is_array( $from_api->updates ) )
return false;
$updates = $from_api->updates;
foreach ( $updates as $update ) {
if ( $update->current == $version && $update->locale == $locale )
return $update;
}
return false;
}
/**
*
* @param string $msg
* @return string
*/
function core_update_footer( $msg = '' ) {
if ( !current_user_can('update_core') )
return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
$cur = get_preferred_from_update_core();
if ( ! is_object( $cur ) )
$cur = new stdClass;
if ( ! isset( $cur->current ) )
$cur->current = '';
if ( ! isset( $cur->url ) )
$cur->url = '';
if ( ! isset( $cur->response ) )
$cur->response = '';
switch ( $cur->response ) {
case 'development' :
return sprintf( __( 'You are using a development version (%1$s). Cool! Please <a href="%2$s">stay updated</a>.' ), get_bloginfo( 'version', 'display' ), network_admin_url( 'update-core.php' ) );
case 'upgrade' :
return '<strong><a href="' . network_admin_url( 'update-core.php' ) . '">' . sprintf( __( 'Get Version %s' ), $cur->current ) . '</a></strong>';
case 'latest' :
default :
return sprintf( __( 'Version %s' ), get_bloginfo( 'version', 'display' ) );
}
}
/**
*
* @global string $pagenow
* @return false|void
*/
function update_nag() {
if ( is_multisite() && !current_user_can('update_core') )
return false;
global $pagenow;
if ( 'update-core.php' == $pagenow )
return;
$cur = get_preferred_from_update_core();
if ( ! isset( $cur->response ) || $cur->response != 'upgrade' )
return false;
if ( current_user_can('update_core') ) {
$msg = sprintf( __( '<a href="https://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! <a href="%2$s" aria-label="Please update WordPress now">Please update now</a>.' ), $cur->current, network_admin_url( 'update-core.php' ) );
} else {
$msg = sprintf( __('<a href="https://codex.wordpress.org/Version_%1$s">WordPress %1$s</a> is available! Please notify the site administrator.'), $cur->current );
}
echo "<div class='update-nag'>$msg</div>";
}
// Called directly from dashboard
function update_right_now_message() {
$theme_name = wp_get_theme();
if ( current_user_can( 'switch_themes' ) ) {
$theme_name = sprintf( '<a href="themes.php">%1$s</a>', $theme_name );
}
$msg = '';
if ( current_user_can('update_core') ) {
$cur = get_preferred_from_update_core();
if ( isset( $cur->response ) && $cur->response == 'upgrade' )
$msg .= '<a href="' . network_admin_url( 'update-core.php' ) . '" class="button" aria-describedby="wp-version">' . sprintf( __( 'Update to %s' ), $cur->current ? $cur->current : __( 'Latest' ) ) . '</a> ';
}
/* translators: 1: version number, 2: theme name */
$content = __( 'WordPress %1$s running %2$s theme.' );
/**
* Filter the text displayed in the 'At a Glance' dashboard widget.
*
* Prior to 3.8.0, the widget was named 'Right Now'.
*
* @since 4.4.0
*
* @param string $content Default text.
*/
$content = apply_filters( 'update_right_now_text', $content );
$msg .= sprintf( '<span id="wp-version">' . $content . '</span>', get_bloginfo( 'version', 'display' ), $theme_name );
echo "<p id='wp-version-message'>$msg</p>";
}
/**
* @since 2.9.0
*
* @return array
*/
function get_plugin_updates() {
$all_plugins = get_plugins();
$upgrade_plugins = array();
$current = get_site_transient( 'update_plugins' );
foreach ( (array)$all_plugins as $plugin_file => $plugin_data) {
if ( isset( $current->response[ $plugin_file ] ) ) {
$upgrade_plugins[ $plugin_file ] = (object) $plugin_data;
$upgrade_plugins[ $plugin_file ]->update = $current->response[ $plugin_file ];
}
}
return $upgrade_plugins;
}
/**
* @since 2.9.0
*/
function wp_plugin_update_rows() {
if ( !current_user_can('update_plugins' ) )
return;
$plugins = get_site_transient( 'update_plugins' );
if ( isset($plugins->response) && is_array($plugins->response) ) {
$plugins = array_keys( $plugins->response );
foreach ( $plugins as $plugin_file ) {
add_action( "after_plugin_row_$plugin_file", 'wp_plugin_update_row', 10, 2 );
}
}
}
/**
*
* @param string $file
* @param array $plugin_data
* @return false|void
*/
function wp_plugin_update_row( $file, $plugin_data ) {
$current = get_site_transient( 'update_plugins' );
if ( !isset( $current->response[ $file ] ) )
return false;
$r = $current->response[ $file ];
$plugins_allowedtags = array('a' => array('href' => array(),'title' => array()),'abbr' => array('title' => array()),'acronym' => array('title' => array()),'code' => array(),'em' => array(),'strong' => array());
$plugin_name = wp_kses( $plugin_data['Name'], $plugins_allowedtags );
$details_url = self_admin_url('plugin-install.php?tab=plugin-information&plugin=' . $r->slug . '&section=changelog&TB_iframe=true&width=600&height=800');
$wp_list_table = _get_list_table('WP_Plugins_List_Table');
if ( is_network_admin() || !is_multisite() ) {
if ( is_network_admin() ) {
$active_class = is_plugin_active_for_network( $file ) ? ' active': '';
} else {
$active_class = is_plugin_active( $file ) ? ' active' : '';
}
echo '<tr class="plugin-update-tr' . $active_class . '" id="' . esc_attr( $r->slug . '-update' ) . '" data-slug="' . esc_attr( $r->slug ) . '" data-plugin="' . esc_attr( $file ) . '"><td colspan="' . esc_attr( $wp_list_table->get_column_count() ) . '" class="plugin-update colspanchange"><div class="update-message">';
if ( ! current_user_can( 'update_plugins' ) ) {
/* translators: 1: plugin name, 2: details URL, 3: accessibility text, 4: version number */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a>.' ),
$plugin_name,
esc_url( $details_url ),
/* translators: 1: plugin name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $r->new_version ) ),
$r->new_version
);
} elseif ( empty( $r->package ) ) {
/* translators: 1: plugin name, 2: details URL, 3: accessibility text, 4: version number */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this plugin.</em>' ),
$plugin_name,
esc_url( $details_url ),
/* translators: 1: plugin name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $r->new_version ) ),
$r->new_version
);
} else {
/* translators: 1: plugin name, 2: details URL, 3: accessibility text, 4: version number, 5: update URL, 6: accessibility text */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a> or <a href="%5$s" class="update-link" aria-label="%6$s">update now</a>.' ),
$plugin_name,
esc_url( $details_url ),
/* translators: 1: plugin name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $plugin_name, $r->new_version ) ),
$r->new_version,
wp_nonce_url( self_admin_url( 'update.php?action=upgrade-plugin&plugin=' ) . $file, 'upgrade-plugin_' . $file ),
/* translators: %s: plugin name */
esc_attr( sprintf( __( 'Update %s now' ), $plugin_name ) )
);
}
/**
* Fires at the end of the update message container in each
* row of the plugins list table.
*
* The dynamic portion of the hook name, `$file`, refers to the path
* of the plugin's primary file relative to the plugins directory.
*
* @since 2.8.0
*
* @param array $plugin_data {
* An array of plugin metadata.
*
* @type string $name The human-readable name of the plugin.
* @type string $plugin_uri Plugin URI.
* @type string $version Plugin version.
* @type string $description Plugin description.
* @type string $author Plugin author.
* @type string $author_uri Plugin author URI.
* @type string $text_domain Plugin text domain.
* @type string $domain_path Relative path to the plugin's .mo file(s).
* @type bool $network Whether the plugin can only be activated network wide.
* @type string $title The human-readable title of the plugin.
* @type string $author_name Plugin author's name.
* @type bool $update Whether there's an available update. Default null.
* }
* @param array $r {
* An array of metadata about the available plugin update.
*
* @type int $id Plugin ID.
* @type string $slug Plugin slug.
* @type string $new_version New plugin version.
* @type string $url Plugin URL.
* @type string $package Plugin update package URL.
* }
*/
do_action( "in_plugin_update_message-{$file}", $plugin_data, $r );
echo '</div></td></tr>';
}
}
/**
*
* @return array
*/
function get_theme_updates() {
$current = get_site_transient('update_themes');
if ( ! isset( $current->response ) )
return array();
$update_themes = array();
foreach ( $current->response as $stylesheet => $data ) {
$update_themes[ $stylesheet ] = wp_get_theme( $stylesheet );
$update_themes[ $stylesheet ]->update = $data;
}
return $update_themes;
}
/**
* @since 3.1.0
*/
function wp_theme_update_rows() {
if ( !current_user_can('update_themes' ) )
return;
$themes = get_site_transient( 'update_themes' );
if ( isset($themes->response) && is_array($themes->response) ) {
$themes = array_keys( $themes->response );
foreach ( $themes as $theme ) {
add_action( "after_theme_row_$theme", 'wp_theme_update_row', 10, 2 );
}
}
}
/**
*
* @param string $theme_key
* @param WP_Theme $theme
* @return false|void
*/
function wp_theme_update_row( $theme_key, $theme ) {
$current = get_site_transient( 'update_themes' );
if ( !isset( $current->response[ $theme_key ] ) )
return false;
$r = $current->response[ $theme_key ];
$theme_name = $theme['Name'];
$details_url = add_query_arg( array( 'TB_iframe' => 'true', 'width' => 1024, 'height' => 800 ), $current->response[ $theme_key ]['url'] );
$wp_list_table = _get_list_table('WP_MS_Themes_List_Table');
$active = $theme->is_allowed( 'network' ) ? ' active': '';
echo '<tr class="plugin-update-tr' . $active . '" id="' . esc_attr( $theme->get_stylesheet() . '-update' ) . '" data-slug="' . esc_attr( $theme->get_stylesheet() ) . '"><td colspan="' . $wp_list_table->get_column_count() . '" class="plugin-update colspanchange"><div class="update-message">';
if ( ! current_user_can('update_themes') ) {
/* translators: 1: theme name, 2: details URL, 3: accessibility text, 4: version number */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a>.'),
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $r['new_version'] ) ),
$r['new_version']
);
} elseif ( empty( $r['package'] ) ) {
/* translators: 1: theme name, 2: details URL, 3: accessibility text, 4: version number */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a>. <em>Automatic update is unavailable for this theme.</em>' ),
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $r['new_version'] ) ),
$r['new_version']
);
} else {
/* translators: 1: theme name, 2: details URL, 3: accessibility text, 4: version number, 5: update URL, 6: accessibility text */
printf( __( 'There is a new version of %1$s available. <a href="%2$s" class="thickbox open-plugin-details-modal" aria-label="%3$s">View version %4$s details</a> or <a href="%5$s" class="update-link" aria-label="%6$s">update now</a>.' ),
$theme_name,
esc_url( $details_url ),
/* translators: 1: theme name, 2: version number */
esc_attr( sprintf( __( 'View %1$s version %2$s details' ), $theme_name, $r['new_version'] ) ),
$r['new_version'],
wp_nonce_url( self_admin_url( 'update.php?action=upgrade-theme&theme=' ) . $theme_key, 'upgrade-theme_' . $theme_key ),
/* translators: %s: theme name */
esc_attr( sprintf( __( 'Update %s now' ), $theme_name ) )
);
}
/**
* Fires at the end of the update message container in each
* row of the themes list table.
*
* The dynamic portion of the hook name, `$theme_key`, refers to
* the theme slug as found in the WordPress.org themes repository.
*
* @since 3.1.0
*
* @param WP_Theme $theme The WP_Theme object.
* @param array $r {
* An array of metadata about the available theme update.
*
* @type string $new_version New theme version.
* @type string $url Theme URL.
* @type string $package Theme update package URL.
* }
*/
do_action( "in_theme_update_message-{$theme_key}", $theme, $r );
echo '</div></td></tr>';
}
/**
*
* @global int $upgrading
* @return false|void
*/
function maintenance_nag() {
include( ABSPATH . WPINC . '/version.php' ); // include an unmodified $wp_version
global $upgrading;
$nag = isset( $upgrading );
if ( ! $nag ) {
$failed = get_site_option( 'auto_core_update_failed' );
/*
* If an update failed critically, we may have copied over version.php but not other files.
* In that case, if the install claims we're running the version we attempted, nag.
* This is serious enough to err on the side of nagging.
*
* If we simply failed to update before we tried to copy any files, then assume things are
* OK if they are now running the latest.
*
* This flag is cleared whenever a successful update occurs using Core_Upgrader.
*/
$comparison = ! empty( $failed['critical'] ) ? '>=' : '>';
if ( version_compare( $failed['attempted'], $wp_version, $comparison ) )
$nag = true;
}
if ( ! $nag )
return false;
if ( current_user_can('update_core') )
$msg = sprintf( __('An automated WordPress update has failed to complete - <a href="%s">please attempt the update again now</a>.'), 'update-core.php' );
else
$msg = __('An automated WordPress update has failed to complete! Please notify the site administrator.');
echo "<div class='update-nag'>$msg</div>";
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,523 @@
<?php
/**
* WordPress user administration API.
*
* @package WordPress
* @subpackage Administration
*/
/**
* Creates a new user from the "Users" form using $_POST information.
*
* @since 2.0.0
*
* @return int|WP_Error WP_Error or User ID.
*/
function add_user() {
return edit_user();
}
/**
* Edit user settings based on contents of $_POST
*
* Used on user-edit.php and profile.php to manage and process user options, passwords etc.
*
* @since 2.0.0
*
* @param int $user_id Optional. User ID.
* @return int|WP_Error user id of the updated user
*/
function edit_user( $user_id = 0 ) {
$wp_roles = wp_roles();
$user = new stdClass;
if ( $user_id ) {
$update = true;
$user->ID = (int) $user_id;
$userdata = get_userdata( $user_id );
$user->user_login = wp_slash( $userdata->user_login );
} else {
$update = false;
}
if ( !$update && isset( $_POST['user_login'] ) )
$user->user_login = sanitize_user($_POST['user_login'], true);
$pass1 = $pass2 = '';
if ( isset( $_POST['pass1'] ) )
$pass1 = $_POST['pass1'];
if ( isset( $_POST['pass2'] ) )
$pass2 = $_POST['pass2'];
if ( isset( $_POST['role'] ) && current_user_can( 'edit_users' ) ) {
$new_role = sanitize_text_field( $_POST['role'] );
$potential_role = isset($wp_roles->role_objects[$new_role]) ? $wp_roles->role_objects[$new_role] : false;
// Don't let anyone with 'edit_users' (admins) edit their own role to something without it.
// Multisite super admins can freely edit their blog roles -- they possess all caps.
if ( ( is_multisite() && current_user_can( 'manage_sites' ) ) || $user_id != get_current_user_id() || ($potential_role && $potential_role->has_cap( 'edit_users' ) ) )
$user->role = $new_role;
// If the new role isn't editable by the logged-in user die with error
$editable_roles = get_editable_roles();
if ( ! empty( $new_role ) && empty( $editable_roles[$new_role] ) )
wp_die(__('You can&#8217;t give users that role.'));
}
if ( isset( $_POST['email'] ))
$user->user_email = sanitize_text_field( wp_unslash( $_POST['email'] ) );
if ( isset( $_POST['url'] ) ) {
if ( empty ( $_POST['url'] ) || $_POST['url'] == 'http://' ) {
$user->user_url = '';
} else {
$user->user_url = esc_url_raw( $_POST['url'] );
$protocols = implode( '|', array_map( 'preg_quote', wp_allowed_protocols() ) );
$user->user_url = preg_match('/^(' . $protocols . '):/is', $user->user_url) ? $user->user_url : 'http://'.$user->user_url;
}
}
if ( isset( $_POST['first_name'] ) )
$user->first_name = sanitize_text_field( $_POST['first_name'] );
if ( isset( $_POST['last_name'] ) )
$user->last_name = sanitize_text_field( $_POST['last_name'] );
if ( isset( $_POST['nickname'] ) )
$user->nickname = sanitize_text_field( $_POST['nickname'] );
if ( isset( $_POST['display_name'] ) )
$user->display_name = sanitize_text_field( $_POST['display_name'] );
if ( isset( $_POST['description'] ) )
$user->description = trim( $_POST['description'] );
foreach ( wp_get_user_contact_methods( $user ) as $method => $name ) {
if ( isset( $_POST[$method] ))
$user->$method = sanitize_text_field( $_POST[$method] );
}
if ( $update ) {
$user->rich_editing = isset( $_POST['rich_editing'] ) && 'false' == $_POST['rich_editing'] ? 'false' : 'true';
$user->admin_color = isset( $_POST['admin_color'] ) ? sanitize_text_field( $_POST['admin_color'] ) : 'fresh';
$user->show_admin_bar_front = isset( $_POST['admin_bar_front'] ) ? 'true' : 'false';
}
$user->comment_shortcuts = isset( $_POST['comment_shortcuts'] ) && 'true' == $_POST['comment_shortcuts'] ? 'true' : '';
$user->use_ssl = 0;
if ( !empty($_POST['use_ssl']) )
$user->use_ssl = 1;
$errors = new WP_Error();
/* checking that username has been typed */
if ( $user->user_login == '' )
$errors->add( 'user_login', __( '<strong>ERROR</strong>: Please enter a username.' ) );
/* checking that nickname has been typed */
if ( $update && empty( $user->nickname ) ) {
$errors->add( 'nickname', __( '<strong>ERROR</strong>: Please enter a nickname.' ) );
}
/**
* Fires before the password and confirm password fields are checked for congruity.
*
* @since 1.5.1
*
* @param string $user_login The username.
* @param string &$pass1 The password, passed by reference.
* @param string &$pass2 The confirmed password, passed by reference.
*/
do_action_ref_array( 'check_passwords', array( $user->user_login, &$pass1, &$pass2 ) );
// Check for blank password when adding a user.
if ( ! $update && empty( $pass1 ) ) {
$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter a password.' ), array( 'form-field' => 'pass1' ) );
}
// Check for "\" in password.
if ( false !== strpos( wp_unslash( $pass1 ), "\\" ) ) {
$errors->add( 'pass', __( '<strong>ERROR</strong>: Passwords may not contain the character "\\".' ), array( 'form-field' => 'pass1' ) );
}
// Checking the password has been typed twice the same.
if ( ( $update || ! empty( $pass1 ) ) && $pass1 != $pass2 ) {
$errors->add( 'pass', __( '<strong>ERROR</strong>: Please enter the same password in both password fields.' ), array( 'form-field' => 'pass1' ) );
}
if ( !empty( $pass1 ) )
$user->user_pass = $pass1;
if ( !$update && isset( $_POST['user_login'] ) && !validate_username( $_POST['user_login'] ) )
$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is invalid because it uses illegal characters. Please enter a valid username.' ));
if ( !$update && username_exists( $user->user_login ) )
$errors->add( 'user_login', __( '<strong>ERROR</strong>: This username is already registered. Please choose another one.' ));
/** This filter is documented in wp-includes/user.php */
$illegal_logins = (array) apply_filters( 'illegal_user_logins', array() );
if ( in_array( strtolower( $user->user_login ), array_map( 'strtolower', $illegal_logins ) ) ) {
$errors->add( 'invalid_username', __( '<strong>ERROR</strong>: Sorry, that username is not allowed.' ) );
}
/* checking email address */
if ( empty( $user->user_email ) ) {
$errors->add( 'empty_email', __( '<strong>ERROR</strong>: Please enter an email address.' ), array( 'form-field' => 'email' ) );
} elseif ( !is_email( $user->user_email ) ) {
$errors->add( 'invalid_email', __( '<strong>ERROR</strong>: The email address isn&#8217;t correct.' ), array( 'form-field' => 'email' ) );
} elseif ( ( $owner_id = email_exists($user->user_email) ) && ( !$update || ( $owner_id != $user->ID ) ) ) {
$errors->add( 'email_exists', __('<strong>ERROR</strong>: This email is already registered, please choose another one.'), array( 'form-field' => 'email' ) );
}
/**
* Fires before user profile update errors are returned.
*
* @since 2.8.0
*
* @param WP_Error &$errors WP_Error object, passed by reference.
* @param bool $update Whether this is a user update.
* @param WP_User &$user WP_User object, passed by reference.
*/
do_action_ref_array( 'user_profile_update_errors', array( &$errors, $update, &$user ) );
if ( $errors->get_error_codes() )
return $errors;
if ( $update ) {
$user_id = wp_update_user( $user );
} else {
$user_id = wp_insert_user( $user );
$notify = isset( $_POST['send_user_notification'] ) ? 'both' : 'admin';
/**
* Fires after a new user has been created.
*
* @since 4.4.0
*
* @param int $user_id ID of the newly created user.
* @param string $notify Type of notification that should happen. See {@see wp_send_new_user_notifications()}
* for more information on possible values.
*/
do_action( 'edit_user_created_user', $user_id, $notify );
}
return $user_id;
}
/**
* Fetch a filtered list of user roles that the current user is
* allowed to edit.
*
* Simple function who's main purpose is to allow filtering of the
* list of roles in the $wp_roles object so that plugins can remove
* inappropriate ones depending on the situation or user making edits.
* Specifically because without filtering anyone with the edit_users
* capability can edit others to be administrators, even if they are
* only editors or authors. This filter allows admins to delegate
* user management.
*
* @since 2.8.0
*
* @return array
*/
function get_editable_roles() {
$all_roles = wp_roles()->roles;
/**
* Filter the list of editable roles.
*
* @since 2.8.0
*
* @param array $all_roles List of roles.
*/
$editable_roles = apply_filters( 'editable_roles', $all_roles );
return $editable_roles;
}
/**
* Retrieve user data and filter it.
*
* @since 2.0.5
*
* @param int $user_id User ID.
* @return WP_User|bool WP_User object on success, false on failure.
*/
function get_user_to_edit( $user_id ) {
$user = get_userdata( $user_id );
if ( $user )
$user->filter = 'edit';
return $user;
}
/**
* Retrieve the user's drafts.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $user_id User ID.
* @return array
*/
function get_users_drafts( $user_id ) {
global $wpdb;
$query = $wpdb->prepare("SELECT ID, post_title FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'draft' AND post_author = %d ORDER BY post_modified DESC", $user_id);
/**
* Filter the user's drafts query string.
*
* @since 2.0.0
*
* @param string $query The user's drafts query string.
*/
$query = apply_filters( 'get_users_drafts', $query );
return $wpdb->get_results( $query );
}
/**
* Remove user and optionally reassign posts and links to another user.
*
* If the $reassign parameter is not assigned to a User ID, then all posts will
* be deleted of that user. The action 'delete_user' that is passed the User ID
* being deleted will be run after the posts are either reassigned or deleted.
* The user meta will also be deleted that are for that User ID.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $id User ID.
* @param int $reassign Optional. Reassign posts and links to new User ID.
* @return bool True when finished.
*/
function wp_delete_user( $id, $reassign = null ) {
global $wpdb;
if ( ! is_numeric( $id ) ) {
return false;
}
$id = (int) $id;
$user = new WP_User( $id );
if ( !$user->exists() )
return false;
// Normalize $reassign to null or a user ID. 'novalue' was an older default.
if ( 'novalue' === $reassign ) {
$reassign = null;
} elseif ( null !== $reassign ) {
$reassign = (int) $reassign;
}
/**
* Fires immediately before a user is deleted from the database.
*
* @since 2.0.0
*
* @param int $id ID of the user to delete.
* @param int|null $reassign ID of the user to reassign posts and links to.
* Default null, for no reassignment.
*/
do_action( 'delete_user', $id, $reassign );
if ( null === $reassign ) {
$post_types_to_delete = array();
foreach ( get_post_types( array(), 'objects' ) as $post_type ) {
if ( $post_type->delete_with_user ) {
$post_types_to_delete[] = $post_type->name;
} elseif ( null === $post_type->delete_with_user && post_type_supports( $post_type->name, 'author' ) ) {
$post_types_to_delete[] = $post_type->name;
}
}
/**
* Filter the list of post types to delete with a user.
*
* @since 3.4.0
*
* @param array $post_types_to_delete Post types to delete.
* @param int $id User ID.
*/
$post_types_to_delete = apply_filters( 'post_types_to_delete_with_user', $post_types_to_delete, $id );
$post_types_to_delete = implode( "', '", $post_types_to_delete );
$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $id ) );
if ( $post_ids ) {
foreach ( $post_ids as $post_id )
wp_delete_post( $post_id );
}
// Clean links
$link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
if ( $link_ids ) {
foreach ( $link_ids as $link_id )
wp_delete_link($link_id);
}
} else {
$post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d", $id ) );
$wpdb->update( $wpdb->posts, array('post_author' => $reassign), array('post_author' => $id) );
if ( ! empty( $post_ids ) ) {
foreach ( $post_ids as $post_id )
clean_post_cache( $post_id );
}
$link_ids = $wpdb->get_col( $wpdb->prepare("SELECT link_id FROM $wpdb->links WHERE link_owner = %d", $id) );
$wpdb->update( $wpdb->links, array('link_owner' => $reassign), array('link_owner' => $id) );
if ( ! empty( $link_ids ) ) {
foreach ( $link_ids as $link_id )
clean_bookmark_cache( $link_id );
}
}
// FINALLY, delete user
if ( is_multisite() ) {
remove_user_from_blog( $id, get_current_blog_id() );
} else {
$meta = $wpdb->get_col( $wpdb->prepare( "SELECT umeta_id FROM $wpdb->usermeta WHERE user_id = %d", $id ) );
foreach ( $meta as $mid )
delete_metadata_by_mid( 'user', $mid );
$wpdb->delete( $wpdb->users, array( 'ID' => $id ) );
}
clean_user_cache( $user );
/**
* Fires immediately after a user is deleted from the database.
*
* @since 2.9.0
*
* @param int $id ID of the deleted user.
* @param int|null $reassign ID of the user to reassign posts and links to.
* Default null, for no reassignment.
*/
do_action( 'deleted_user', $id, $reassign );
return true;
}
/**
* Remove all capabilities from user.
*
* @since 2.1.0
*
* @param int $id User ID.
*/
function wp_revoke_user($id) {
$id = (int) $id;
$user = new WP_User($id);
$user->remove_all_caps();
}
/**
* @since 2.8.0
*
* @global int $user_ID
*
* @param false $errors Deprecated.
*/
function default_password_nag_handler($errors = false) {
global $user_ID;
// Short-circuit it.
if ( ! get_user_option('default_password_nag') )
return;
// get_user_setting = JS saved UI setting. else no-js-fallback code.
if ( 'hide' == get_user_setting('default_password_nag') || isset($_GET['default_password_nag']) && '0' == $_GET['default_password_nag'] ) {
delete_user_setting('default_password_nag');
update_user_option($user_ID, 'default_password_nag', false, true);
}
}
/**
* @since 2.8.0
*
* @param int $user_ID
* @param object $old_data
*/
function default_password_nag_edit_user($user_ID, $old_data) {
// Short-circuit it.
if ( ! get_user_option('default_password_nag', $user_ID) )
return;
$new_data = get_userdata($user_ID);
// Remove the nag if the password has been changed.
if ( $new_data->user_pass != $old_data->user_pass ) {
delete_user_setting('default_password_nag');
update_user_option($user_ID, 'default_password_nag', false, true);
}
}
/**
* @since 2.8.0
*
* @global string $pagenow
*/
function default_password_nag() {
global $pagenow;
// Short-circuit it.
if ( 'profile.php' == $pagenow || ! get_user_option('default_password_nag') )
return;
echo '<div class="error default-password-nag">';
echo '<p>';
echo '<strong>' . __('Notice:') . '</strong> ';
_e('You&rsquo;re using the auto-generated password for your account. Would you like to change it?');
echo '</p><p>';
printf( '<a href="%s">' . __('Yes, take me to my profile page') . '</a> | ', get_edit_profile_url() . '#password' );
printf( '<a href="%s" id="default-password-nag-no">' . __('No thanks, do not remind me again') . '</a>', '?default_password_nag=0' );
echo '</p></div>';
}
/**
* @since 3.5.0
* @access private
*/
function delete_users_add_js() { ?>
<script>
jQuery(document).ready( function($) {
var submit = $('#submit').prop('disabled', true);
$('input[name="delete_option"]').one('change', function() {
submit.prop('disabled', false);
});
$('#reassign_user').focus( function() {
$('#delete_option1').prop('checked', true).trigger('change');
});
});
</script>
<?php
}
/**
* Optional SSL preference that can be turned on by hooking to the 'personal_options' action.
*
* @since 2.7.0
*
* @param object $user User data object
*/
function use_ssl_preference($user) {
?>
<tr class="user-use-ssl-wrap">
<th scope="row"><?php _e('Use https')?></th>
<td><label for="use_ssl"><input name="use_ssl" type="checkbox" id="use_ssl" value="1" <?php checked('1', $user->use_ssl); ?> /> <?php _e('Always use https when visiting the admin'); ?></label></td>
</tr>
<?php
}
/**
*
* @param string $text
* @return string
*/
function admin_created_user_email( $text ) {
$roles = get_editable_roles();
$role = $roles[ $_REQUEST['role'] ];
/* translators: 1: Site name, 2: site URL, 3: role */
return sprintf( __( 'Hi,
You\'ve been invited to join \'%1$s\' at
%2$s with the role of %3$s.
If you do not want to join this site please ignore
this email. This invitation will expire in a few days.
Please click the following link to activate your user account:
%%s' ), get_bloginfo( 'name' ), home_url(), wp_specialchars_decode( translate_user_role( $role['name'] ) ) );
}

View File

@@ -0,0 +1,281 @@
<?php
/**
* WordPress Widgets Administration API
*
* @package WordPress
* @subpackage Administration
*/
/**
* Display list of the available widgets.
*
* @since 2.5.0
*
* @global array $wp_registered_widgets
* @global array $wp_registered_widget_controls
*/
function wp_list_widgets() {
global $wp_registered_widgets, $wp_registered_widget_controls;
$sort = $wp_registered_widgets;
usort( $sort, '_sort_name_callback' );
$done = array();
foreach ( $sort as $widget ) {
if ( in_array( $widget['callback'], $done, true ) ) // We already showed this multi-widget
continue;
$sidebar = is_active_widget( $widget['callback'], $widget['id'], false, false );
$done[] = $widget['callback'];
if ( ! isset( $widget['params'][0] ) )
$widget['params'][0] = array();
$args = array( 'widget_id' => $widget['id'], 'widget_name' => $widget['name'], '_display' => 'template' );
if ( isset($wp_registered_widget_controls[$widget['id']]['id_base']) && isset($widget['params'][0]['number']) ) {
$id_base = $wp_registered_widget_controls[$widget['id']]['id_base'];
$args['_temp_id'] = "$id_base-__i__";
$args['_multi_num'] = next_widget_id_number($id_base);
$args['_add'] = 'multi';
} else {
$args['_add'] = 'single';
if ( $sidebar )
$args['_hide'] = '1';
}
$args = wp_list_widget_controls_dynamic_sidebar( array( 0 => $args, 1 => $widget['params'][0] ) );
call_user_func_array( 'wp_widget_control', $args );
}
}
/**
* Callback to sort array by a 'name' key.
*
* @since 3.1.0
* @access private
*
* @return int
*/
function _sort_name_callback( $a, $b ) {
return strnatcasecmp( $a['name'], $b['name'] );
}
/**
* Show the widgets and their settings for a sidebar.
* Used in the admin widget config screen.
*
* @since 2.5.0
*
* @param string $sidebar Sidebar ID.
* @param string $sidebar_name Optional. Sidebar name. Default empty.
*/
function wp_list_widget_controls( $sidebar, $sidebar_name = '' ) {
add_filter( 'dynamic_sidebar_params', 'wp_list_widget_controls_dynamic_sidebar' );
$description = wp_sidebar_description( $sidebar );
echo '<div id="' . esc_attr( $sidebar ) . '" class="widgets-sortables">';
if ( $sidebar_name ) {
?>
<div class="sidebar-name">
<div class="sidebar-name-arrow"><br /></div>
<h2><?php echo esc_html( $sidebar_name ); ?> <span class="spinner"></span></h2>
</div>
<?php
}
if ( ! empty( $description ) ) {
?>
<div class="sidebar-description">
<p class="description"><?php echo $description; ?></p>
</div>
<?php
}
dynamic_sidebar( $sidebar );
echo '</div>';
}
/**
* Retrieves the widget control arguments.
*
* @since 2.5.0
*
* @global array $wp_registered_widgets
*
* @staticvar int $i
*
* @param array $params
* @return array
*/
function wp_list_widget_controls_dynamic_sidebar( $params ) {
global $wp_registered_widgets;
static $i = 0;
$i++;
$widget_id = $params[0]['widget_id'];
$id = isset($params[0]['_temp_id']) ? $params[0]['_temp_id'] : $widget_id;
$hidden = isset($params[0]['_hide']) ? ' style="display:none;"' : '';
$params[0]['before_widget'] = "<div id='widget-{$i}_{$id}' class='widget'$hidden>";
$params[0]['after_widget'] = "</div>";
$params[0]['before_title'] = "%BEG_OF_TITLE%"; // deprecated
$params[0]['after_title'] = "%END_OF_TITLE%"; // deprecated
if ( is_callable( $wp_registered_widgets[$widget_id]['callback'] ) ) {
$wp_registered_widgets[$widget_id]['_callback'] = $wp_registered_widgets[$widget_id]['callback'];
$wp_registered_widgets[$widget_id]['callback'] = 'wp_widget_control';
}
return $params;
}
/**
*
* @global array $wp_registered_widgets
*
* @param string $id_base
* @return int
*/
function next_widget_id_number( $id_base ) {
global $wp_registered_widgets;
$number = 1;
foreach ( $wp_registered_widgets as $widget_id => $widget ) {
if ( preg_match( '/' . $id_base . '-([0-9]+)$/', $widget_id, $matches ) )
$number = max($number, $matches[1]);
}
$number++;
return $number;
}
/**
* Meta widget used to display the control form for a widget.
*
* Called from dynamic_sidebar().
*
* @since 2.5.0
*
* @global array $wp_registered_widgets
* @global array $wp_registered_widget_controls
* @global array $sidebars_widgets
*
* @param array $sidebar_args
* @return array
*/
function wp_widget_control( $sidebar_args ) {
global $wp_registered_widgets, $wp_registered_widget_controls, $sidebars_widgets;
$widget_id = $sidebar_args['widget_id'];
$sidebar_id = isset($sidebar_args['id']) ? $sidebar_args['id'] : false;
$key = $sidebar_id ? array_search( $widget_id, $sidebars_widgets[$sidebar_id] ) : '-1'; // position of widget in sidebar
$control = isset($wp_registered_widget_controls[$widget_id]) ? $wp_registered_widget_controls[$widget_id] : array();
$widget = $wp_registered_widgets[$widget_id];
$id_format = $widget['id'];
$widget_number = isset($control['params'][0]['number']) ? $control['params'][0]['number'] : '';
$id_base = isset($control['id_base']) ? $control['id_base'] : $widget_id;
$multi_number = isset($sidebar_args['_multi_num']) ? $sidebar_args['_multi_num'] : '';
$add_new = isset($sidebar_args['_add']) ? $sidebar_args['_add'] : '';
$before_form = isset( $sidebar_args['before_form'] ) ? $sidebar_args['before_form'] : '<form method="post">';
$after_form = isset( $sidebar_args['after_form'] ) ? $sidebar_args['after_form'] : '</form>';
$before_widget_content = isset( $sidebar_args['before_widget_content'] ) ? $sidebar_args['before_widget_content'] : '<div class="widget-content">';
$after_widget_content = isset( $sidebar_args['after_widget_content'] ) ? $sidebar_args['after_widget_content'] : '</div>';
$query_arg = array( 'editwidget' => $widget['id'] );
if ( $add_new ) {
$query_arg['addnew'] = 1;
if ( $multi_number ) {
$query_arg['num'] = $multi_number;
$query_arg['base'] = $id_base;
}
} else {
$query_arg['sidebar'] = $sidebar_id;
$query_arg['key'] = $key;
}
/*
* We aren't showing a widget control, we're outputting a template
* for a multi-widget control.
*/
if ( isset($sidebar_args['_display']) && 'template' == $sidebar_args['_display'] && $widget_number ) {
// number == -1 implies a template where id numbers are replaced by a generic '__i__'
$control['params'][0]['number'] = -1;
// With id_base widget id's are constructed like {$id_base}-{$id_number}.
if ( isset($control['id_base']) )
$id_format = $control['id_base'] . '-__i__';
}
$wp_registered_widgets[$widget_id]['callback'] = $wp_registered_widgets[$widget_id]['_callback'];
unset($wp_registered_widgets[$widget_id]['_callback']);
$widget_title = esc_html( strip_tags( $sidebar_args['widget_name'] ) );
$has_form = 'noform';
echo $sidebar_args['before_widget']; ?>
<div class="widget-top">
<div class="widget-title-action">
<a class="widget-action hide-if-no-js" href="#available-widgets"></a>
<a class="widget-control-edit hide-if-js" href="<?php echo esc_url( add_query_arg( $query_arg ) ); ?>">
<span class="edit"><?php _ex( 'Edit', 'widget' ); ?></span>
<span class="add"><?php _ex( 'Add', 'widget' ); ?></span>
<span class="screen-reader-text"><?php echo $widget_title; ?></span>
</a>
</div>
<div class="widget-title"><h3><?php echo $widget_title; ?><span class="in-widget-title"></span></h3></div>
</div>
<div class="widget-inside">
<?php echo $before_form; ?>
<?php echo $before_widget_content; ?>
<?php
if ( isset( $control['callback'] ) ) {
$has_form = call_user_func_array( $control['callback'], $control['params'] );
} else {
echo "\t\t<p>" . __('There are no options for this widget.') . "</p>\n";
}
?>
<?php echo $after_widget_content; ?>
<input type="hidden" name="widget-id" class="widget-id" value="<?php echo esc_attr($id_format); ?>" />
<input type="hidden" name="id_base" class="id_base" value="<?php echo esc_attr($id_base); ?>" />
<input type="hidden" name="widget-width" class="widget-width" value="<?php if (isset( $control['width'] )) echo esc_attr($control['width']); ?>" />
<input type="hidden" name="widget-height" class="widget-height" value="<?php if (isset( $control['height'] )) echo esc_attr($control['height']); ?>" />
<input type="hidden" name="widget_number" class="widget_number" value="<?php echo esc_attr($widget_number); ?>" />
<input type="hidden" name="multi_number" class="multi_number" value="<?php echo esc_attr($multi_number); ?>" />
<input type="hidden" name="add_new" class="add_new" value="<?php echo esc_attr($add_new); ?>" />
<div class="widget-control-actions">
<div class="alignleft">
<a class="widget-control-remove" href="#remove"><?php _e('Delete'); ?></a> |
<a class="widget-control-close" href="#close"><?php _e('Close'); ?></a>
</div>
<div class="alignright<?php if ( 'noform' === $has_form ) echo ' widget-control-noform'; ?>">
<?php submit_button( __( 'Save' ), 'button-primary widget-control-save right', 'savewidget', false, array( 'id' => 'widget-' . esc_attr( $id_format ) . '-savewidget' ) ); ?>
<span class="spinner"></span>
</div>
<br class="clear" />
</div>
<?php echo $after_form; ?>
</div>
<div class="widget-description">
<?php echo ( $widget_description = wp_widget_description($widget_id) ) ? "$widget_description\n" : "$widget_title\n"; ?>
</div>
<?php
echo $sidebar_args['after_widget'];
return $sidebar_args;
}
/**
*
* @param string $classes
* @return string
*/
function wp_widgets_access_body_class($classes) {
return "$classes widgets_access ";
}