File: /home/honghock/www/wp-content/plugins/broken-link-checker-seo/app/Traits/Helpers/Wp.php
<?php
namespace AIOSEO\BrokenLinkChecker\Traits\Helpers;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\BrokenLinkChecker\Utils;
/**
* Contains all WP related helper methods.
*
* @since 1.0.0
*/
trait Wp {
/**
* Returns all registered post statuses.
*
* @since 1.0.0
*
* @param boolean $statusesOnly Whether or not to only return statuses.
* @return array List of post statuses.
*/
public function getPublicPostStatuses( $statusesOnly = false ) {
$allStatuses = get_post_stati( [ 'show_in_admin_all_list' => true ], 'objects' );
$postStatuses = [];
foreach ( $allStatuses as $status => $data ) {
if (
! $data->public &&
! $data->protected &&
! $data->private
) {
continue;
}
if ( $statusesOnly ) {
$postStatuses[] = $status;
continue;
}
$postStatuses[] = [
'label' => $data->label,
'status' => $status
];
}
return $postStatuses;
}
/**
* Returns a list of public post types with slugs/icons.
*
* @since 1.0.0
*
* @param boolean $namesOnly Whether only the names should be returned.
* @param boolean $hasArchivesOnly Whether or not to only include post types which have archives.
* @param boolean $rewriteType Whether or not to rewrite the type slugs.
* @return array List of public post types.
*/
public function getPublicPostTypes( $namesOnly = false, $hasArchivesOnly = false, $rewriteType = false ) {
$postTypes = [];
$postTypeObjects = get_post_types( [ 'public' => true ], 'objects' );
$woocommerce = class_exists( 'woocommerce' );
foreach ( $postTypeObjects as $postTypeObject ) {
if ( empty( $postTypeObject->label ) ) {
continue;
}
// We don't want to include archives for the WooCommerce shop page.
if (
$hasArchivesOnly &&
(
! $postTypeObject->has_archive ||
( 'product' === $postTypeObject->name && $woocommerce )
)
) {
continue;
}
if ( $namesOnly ) {
$postTypes[] = $postTypeObject->name;
continue;
}
if ( 'attachment' === $postTypeObject->name ) {
// We have to check if the 'init' action has been fired to avoid a PHP notice
// in WP 6.7+ due to loading translations too early.
if ( did_action( 'init' ) ) {
$postTypeObject->label = __( 'Attachments', 'aioseo-broken-link-checker' );
}
}
if ( 'product' === $postTypeObject->name && $woocommerce ) {
$postTypeObject->menu_icon = 'dashicons-products';
}
$name = $postTypeObject->name;
if ( 'type' === $postTypeObject->name && $rewriteType ) {
$name = '_aioseo_type';
}
$postTypes[] = [
'name' => $name,
'label' => ucwords( $postTypeObject->label ),
'singular' => ucwords( $postTypeObject->labels->singular_name ),
'icon' => $postTypeObject->menu_icon,
'hasExcerpt' => post_type_supports( $postTypeObject->name, 'excerpt' ),
'hasArchive' => $postTypeObject->has_archive,
'hierarchical' => $postTypeObject->hierarchical,
'taxonomies' => get_object_taxonomies( $name ),
'slug' => isset( $postTypeObject->rewrite['slug'] ) ? $postTypeObject->rewrite['slug'] : $name
];
}
return apply_filters( 'aioseo_blc_public_post_types', $postTypes, $namesOnly, $hasArchivesOnly );
}
/**
* Checks if the current user can edit posts of the given post type.
*
* @since 1.0.0
*
* @param string $postType The name of the post type.
* @return bool Whether the user can edit posts of the given post type.
*/
public function canEditPostType( $postType ) {
$capabilities = $this->getPostTypeCapabilities( $postType );
return current_user_can( $capabilities['edit_posts'] );
}
/**
* Returns a list of capabilities for the given post type.
*
* @since 1.0.0
*
* @param string $postType The name of the post type.
* @return array The capabilities.
*/
public function getPostTypeCapabilities( $postType ) {
static $capabilities = [];
if ( isset( $capabilities[ $postType ] ) ) {
return $capabilities[ $postType ];
}
$postTypeObject = get_post_type_object( $postType );
if ( ! is_a( $postTypeObject, 'WP_Post_Type' ) ) {
$capabilities[ $postType ] = [];
return $capabilities[ $postType ];
}
if ( ! is_array( $postTypeObject->capability_type ) ) {
$postTypeObject->capability_type = [
$postTypeObject->capability_type,
$postTypeObject->capability_type . 's'
];
}
// Singular base for meta capabilities, plural base for primitive capabilities.
list( $singularBase, $pluralBase ) = $postTypeObject->capability_type;
$capabilities[ $postType ] = [
'edit_post' => 'edit_' . $singularBase,
'read_post' => 'read_' . $singularBase,
'delete_post' => 'delete_' . $singularBase,
'edit_posts' => 'edit_' . $pluralBase,
'edit_others_posts' => 'edit_others_' . $pluralBase,
'delete_posts' => 'delete_' . $pluralBase,
'publish_posts' => 'publish_' . $pluralBase,
'read_private_posts' => 'read_private_' . $pluralBase,
];
return $capabilities[ $postType ];
}
/**
* Returns the current post object.
*
* @since 1.0.0
*
* @param int|null $postId The post ID.
* @return \WP_Post|null The post object.
*/
public function getPost( $postId = null ) {
$postId = is_a( $postId, 'WP_Post' ) ? $postId->ID : $postId;
if ( $this->isWooCommerceShopPage( $postId ) ) {
return get_post( wc_get_page_id( 'shop' ) );
}
if ( is_front_page() || is_home() ) {
$showOnFront = 'page' === get_option( 'show_on_front' );
if ( $showOnFront ) {
if ( is_front_page() ) {
$pageOnFront = (int) get_option( 'page_on_front' );
return get_post( $pageOnFront );
} elseif ( is_home() ) {
$pageForPosts = (int) get_option( 'page_for_posts' );
return get_post( $pageForPosts );
}
}
}
// We need to check these conditions and cannot always return get_post() because we'll return the first post on archive pages (dynamic homepage, term pages, etc.).
// https://github.com/awesomemotive/aioseo/issues/2419
if (
$this->isScreenBase( 'post' ) ||
$postId ||
is_singular()
) {
return get_post( $postId );
}
return null;
}
/**
* Returns true if the request is a non-legacy REST API request.
* This function was copied from WooCommerce and improved.
*
* @since 1.0.0
*
* @return bool True if this is a REST API request.
*/
public function isRestApiRequest() {
if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
return true;
}
global $wp_rewrite; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( empty( $wp_rewrite ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
return false;
}
if ( empty( $_SERVER['REQUEST_URI'] ) ) {
return false;
}
$restUrl = wp_parse_url( get_rest_url() );
$restUrl = $restUrl['path'] . ( ! empty( $restUrl['query'] ) ? '?' . $restUrl['query'] : '' );
$isRestApiRequest = ( 0 === strpos( $_SERVER['REQUEST_URI'], $restUrl ) );
return apply_filters( 'aioseo_is_rest_api_request', $isRestApiRequest );
}
/**
* Checks whether the current request is an AJAX, CRON or REST request.
*
* @since 1.0.0
*
* @return bool Wether the request is an AJAX, CRON or REST request.
*/
public function isAjaxCronRestRequest() {
return wp_doing_ajax() || wp_doing_cron() || $this->isRestApiRequest();
}
/**
* Check if the post passed in is a valid post, not a revision or autosave.
*
* @since 1.0.0
*
* @param \WP_Post $post The Post object to check.
* @param array $allowedPostStatuses Allowed post statuses.
* @return bool True if valid, false if not.
*/
public function isValidPost( $post, $allowedPostStatuses = [ 'publish' ] ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return false;
}
if ( ! is_object( $post ) ) {
$post = get_post( $post );
}
// In order to prevent recursion, we are skipping scheduled-action posts.
if (
! is_object( $post ) ||
'scheduled-action' === $post->post_type ||
'revision' === $post->post_type ||
! in_array( $post->post_status, $allowedPostStatuses, true )
) {
return false;
}
return true;
}
/**
* Returns a list of plugins with the active status.
*
* @since 1.0.0
*
* @return array List of plugins with active status.
*/
public function getPluginData() {
static $pluginData = [];
if ( ! empty( $pluginData ) ) {
return $pluginData;
}
$pluginUpgrader = new Utils\PluginUpgraderSilentAjax();
$installedPlugins = array_keys( get_plugins() );
foreach ( $pluginUpgrader->pluginSlugs as $key => $slug ) {
$pluginData[ $key ] = [
'basename' => $slug,
'installed' => in_array( $slug, $installedPlugins, true ),
'activated' => is_plugin_active( $slug ),
'adminUrl' => admin_url( $pluginUpgrader->pluginAdminUrls[ $key ] ),
'canInstall' => $this->canInstall(),
'canActivate' => $this->canActivate(),
'canUpdate' => $this->canUpdate(),
'wpLink' => ! empty( $pluginUpgrader->wpPluginLinks[ $key ] ) ? $pluginUpgrader->wpPluginLinks[ $key ] : null
];
}
return $pluginData;
}
/**
* Installs and activates a given addon or plugin.
*
* @since 1.0.0
*
* @param string $name The addon name/SKU.
* @param bool $network Whether or not we are in a network environment.
* @return bool Whether or not the installation was succesful.
*/
public function installAddon( $name, $network = false ) {
if ( ! $this->canInstall() ) {
return false;
}
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/template.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-screen.php';
require_once ABSPATH . 'wp-admin/includes/screen.php';
// Set the current screen to avoid undefined notices.
set_current_screen( 'toplevel_page_broken-link-checker' );
// Prepare variables.
$url = esc_url_raw(
add_query_arg(
[
'page' => 'broken-link-checker-links'
],
admin_url( 'admin.php' )
)
);
// Do not allow WordPress to search/download translations, as this will break JS output.
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
// Create the plugin upgrader with our custom skin.
$installer = new Utils\PluginUpgraderSilentAjax( new Utils\PluginUpgraderSkin() );
// Activate the plugin silently.
$pluginUrl = ! empty( $installer->pluginSlugs[ $name ] ) ? $installer->pluginSlugs[ $name ] : $name;
$activated = activate_plugin( $pluginUrl, '', $network );
if ( ! is_wp_error( $activated ) ) {
return $name;
}
// Using output buffering to prevent the FTP form from being displayed in the screen.
ob_start();
$creds = request_filesystem_credentials( $url, '', false, false, null );
ob_end_clean();
// Check for file system permissions.
$fs = aioseoBrokenLinkChecker()->core->fs->noConflict();
$fs->init( $creds );
if ( false === $creds || ! $fs->isWpfsValid() ) {
return false;
}
// Error check.
if ( ! method_exists( $installer, 'install' ) ) {
return false;
}
$installLink = ! empty( $installer->pluginLinks[ $name ] ) ? $installer->pluginLinks[ $name ] : null;
// Check if this is an addon and if we have a download link.
if ( empty( $installLink ) ) {
return false;
}
$installer->install( $installLink );
// Flush the cache and return the newly installed plugin basename.
wp_cache_flush();
$pluginBasename = $installer->plugin_info();
if ( ! $pluginBasename ) {
return false;
}
// Activate the plugin silently.
$activated = activate_plugin( $pluginBasename, '', $network );
if ( is_wp_error( $activated ) ) {
return false;
}
return $pluginBasename;
}
/**
* Determine if plugins can be installed.
*
* @since 1.0.0
*
* @return bool Whether the plugin can be installed.
*/
public function canInstall() {
if ( ! current_user_can( 'install_plugins' ) ) {
return false;
}
// Determine whether file modifications are allowed.
if ( ! wp_is_file_mod_allowed( 'aioseo_blc_can_install' ) ) {
return false;
}
return true;
}
/**
* Determine if plugins can be updated.
*
* @since 1.0.0
*
* @return bool Whether the plugin can be updated.
*/
public function canUpdate() {
if ( ! current_user_can( 'update_plugins' ) ) {
return false;
}
// Determine whether file modifications are allowed.
if ( ! wp_is_file_mod_allowed( 'aioseo_blc_can_update' ) ) {
return false;
}
return true;
}
/**
* Determine if plugins can be activated.
*
* @since 1.0.0
*
* @return bool Whether the plugin can be activated.
*/
public function canActivate() {
if ( ! current_user_can( 'activate_plugins' ) ) {
return false;
}
return true;
}
/**
* Returns the charset for the site.
*
* @since 1.0.0
*
* @return string The name of the charset.
*/
public function getCharset() {
static $charset = null;
if ( null !== $charset ) {
return $charset;
}
$charset = get_option( 'blog_charset' );
$charset = $charset ? $charset : 'UTF-8';
return $charset;
}
}