Initial commit: Atomaste website

This commit is contained in:
2025-12-10 12:17:30 -05:00
commit 0b9e5d1605
19260 changed files with 5206382 additions and 0 deletions

View File

@@ -0,0 +1,348 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Access {
/**
* Capabilities for our users.
*
* @since 4.0.0
*
* @var array
*/
protected $capabilities = [
'aioseo_dashboard',
'aioseo_general_settings',
'aioseo_search_appearance_settings',
'aioseo_social_networks_settings',
'aioseo_sitemap_settings',
'aioseo_link_assistant_settings',
'aioseo_redirects_manage',
'aioseo_page_redirects_manage',
'aioseo_redirects_settings',
'aioseo_seo_analysis_settings',
'aioseo_search_statistics_settings',
'aioseo_tools_settings',
'aioseo_feature_manager_settings',
'aioseo_page_analysis',
'aioseo_page_general_settings',
'aioseo_page_advanced_settings',
'aioseo_page_schema_settings',
'aioseo_page_social_settings',
'aioseo_page_link_assistant_settings',
'aioseo_page_redirects_settings',
'aioseo_local_seo_settings',
'aioseo_page_local_seo_settings',
'aioseo_page_writing_assistant_settings',
'aioseo_about_us_page',
'aioseo_setup_wizard',
'aioseo_page_seo_revisions_settings'
];
/**
* Whether we're already updating the roles during this request.
*
* @since 4.2.7
*
* @var bool
*/
protected $isUpdatingRoles = false;
/**
* Roles we check capabilities against.
*
* @since 4.0.0
*
* @var array
*/
protected $roles = [
'superadmin' => 'superadmin',
'administrator' => 'administrator',
'editor' => 'editor',
'author' => 'author',
'contributor' => 'contributor'
];
/**
* Class constructor.
*
* @since 4.0.0
*/
public function __construct() {
// First load the roles so that we can pull the roles from the other plugins.
add_action( 'plugins_loaded', [ $this, 'setRoles' ], 999 );
// Load later again so that we can pull the roles lately registered.
// This needs to run before 1000 so that our update migrations and other hook callbacks can pull the roles.
add_action( 'init', [ $this, 'setRoles' ], 999 );
}
/**
* Sets the roles on the instance.
*
* @since 4.1.5
*
* @return void
*/
public function setRoles() {
$adminRoles = [];
$allRoles = aioseo()->helpers->getUserRoles();
foreach ( $allRoles as $roleName => $wpRole ) {
$role = get_role( $roleName );
if ( $this->isAdmin( $roleName ) || $role->has_cap( 'publish_posts' ) ) {
$adminRoles[ $roleName ] = $roleName;
}
}
$this->roles = array_merge( $this->roles, $adminRoles );
}
/**
* Adds capabilities into WordPress for the current user.
* Only on activation or settings saved.
*
* @since 4.0.0
*
* @return void
*/
public function addCapabilities() {
$this->isUpdatingRoles = true;
foreach ( $this->roles as $wpRole => $role ) {
$roleObject = get_role( $wpRole );
if ( ! is_object( $roleObject ) ) {
continue;
}
if ( $this->isAdmin( $role ) ) {
$roleObject->add_cap( 'aioseo_manage_seo' );
}
if ( $roleObject->has_cap( 'edit_posts' ) ) {
$postCapabilities = [
'aioseo_page_analysis',
'aioseo_page_general_settings',
'aioseo_page_advanced_settings',
'aioseo_page_schema_settings',
'aioseo_page_social_settings',
];
foreach ( $postCapabilities as $capability ) {
$roleObject->add_cap( $capability );
}
}
}
}
/**
* Removes capabilities for any unknown role.
*
* @since 4.0.0
*
* @return void
*/
public function removeCapabilities() {
$this->isUpdatingRoles = true;
// Clear out capabilities for unknown roles.
$wpRoles = wp_roles();
$allRoles = $wpRoles->roles;
foreach ( $allRoles as $key => $wpRole ) {
$checkRole = is_multisite() ? 'superadmin' : 'administrator';
if ( $checkRole === $key ) {
continue;
}
if ( array_key_exists( $key, $this->roles ) ) {
continue;
}
$role = get_role( $key );
if ( ! is_a( $role, 'WP_Role' ) || ! is_array( $role->capabilities ) ) {
continue;
}
// We don't need to remove the capabilities for administrators.
if ( $this->isAdmin( $key ) ) {
continue;
}
foreach ( $this->capabilities as $capability ) {
if ( $role->has_cap( $capability ) ) {
$role->remove_cap( $capability );
}
}
$role->remove_cap( 'aioseo_manage_seo' );
}
}
/**
* Checks if the current user has the capability.
*
* @since 4.0.0
*
* @param string|array $capability The capability to check against.
* @param string|null $checkRole A role to check against.
* @return bool Whether or not the user has this capability.
*/
public function hasCapability( $capability, $checkRole = null ) {
if ( $this->isAdmin( $checkRole ) ) {
return true;
}
$canPublishOrEdit = $this->can( 'publish_posts', $checkRole ) || $this->can( 'edit_posts', $checkRole );
if ( ! $canPublishOrEdit ) {
return false;
}
if ( is_array( $capability ) ) {
foreach ( $capability as $cap ) {
if ( false !== strpos( $cap, 'aioseo_page_' ) ) {
return true;
}
}
return false;
}
return false !== strpos( $capability, 'aioseo_page_' );
}
/**
* Gets all the capabilities for the current user.
*
* @since 4.0.0
*
* @param string|null $role A role to check against.
* @return array An array of capabilities.
*/
public function getAllCapabilities( $role = null ) {
$capabilities = [];
foreach ( $this->getCapabilityList() as $capability ) {
$capabilities[ $capability ] = $this->hasCapability( $capability, $role );
}
$capabilities['aioseo_admin'] = $this->isAdmin( $role );
$capabilities['aioseo_manage_seo'] = $this->isAdmin( $role );
$capabilities['aioseo_about_us_page'] = $this->canManage( $role );
return $capabilities;
}
/**
* Returns the capability list.
*
* @return 4.1.3
*
* @return array An array of capabilities.
*/
public function getCapabilityList() {
return $this->capabilities;
}
/**
* If the current user is an admin, or superadmin, they have access to all caps regardless.
*
* @since 4.0.0
*
* @param string|null $role The role to check admin privileges if we have one.
* @return bool Whether not the user/role is an admin.
*/
public function isAdmin( $role = null ) {
if ( $role ) {
if ( ( is_multisite() && 'superadmin' === $role ) || 'administrator' === $role ) {
return true;
}
return false;
}
if ( ! function_exists( 'wp_get_current_user' ) ) {
return false;
}
if ( ( is_multisite() && current_user_can( 'superadmin' ) ) || current_user_can( 'administrator' ) ) {
return true;
}
return false;
}
/**
* Check if the passed in role can publish posts.
*
* @since 4.0.9
*
* @param string $capability The capability to check against.
* @param string $role The role to check.
* @return boolean True if the role can publish.
*/
protected function can( $capability, $role ) {
if ( empty( $role ) ) {
return current_user_can( $capability );
}
$wpRoles = wp_roles();
$allRoles = $wpRoles->roles;
foreach ( $allRoles as $key => $wpRole ) {
if ( $key === $role ) {
$r = get_role( $key );
if ( $r->has_cap( $capability ) ) {
return true;
}
}
}
return false;
}
/**
* Checks if the current user can manage AIOSEO.
*
* @since 4.0.0
*
* @param string|null $checkRole A role to check against.
* @return bool Whether or not the user can manage AIOSEO.
*/
public function canManage( $checkRole = null ) {
return $this->isAdmin( $checkRole );
}
/**
* Gets all options that the user does not have access to manage.
*
* @since 4.1.3
*
* @return array An array with the option names.
*/
public function getNotAllowedOptions() {
return [];
}
/**
* Gets all page fields that the user does not have access to manage.
*
* @since 4.1.3
*
* @return array An array with the field names.
*/
public function getNotAllowedPageFields() {
return [];
}
/**
* Returns Roles.
*
* @since 4.0.17
*
* @return array An array of role names.
*/
public function getRoles() {
return $this->roles;
}
}

View File

@@ -0,0 +1,305 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles all Action Scheduler related tasks.
*
* @since 4.0.0
*/
class ActionScheduler {
/**
* The Action Scheduler group.
*
* @since 4.1.5
* @version 4.2.7
*
* @var string
*/
private $actionSchedulerGroup = 'aioseo';
/**
* Class constructor.
*
* @since 4.0.0
*/
public function __construct() {
add_action( 'action_scheduler_after_execute', [ $this, 'cleanup' ], 1000, 2 );
// Note: \ActionScheduler is first loaded on `plugins_loaded` action hook.
add_action( 'plugins_loaded', [ $this, 'maybeRecreateTables' ] );
}
/**
* Maybe register the `{$table_prefix}_actionscheduler_{$suffix}` tables with WordPress and create them if needed.
* Hooked into `plugins_loaded` action hook.
*
* @since 4.2.7
*
* @return void
*/
public function maybeRecreateTables() {
if ( ! is_admin() ) {
return;
}
if ( ! apply_filters( 'action_scheduler_enable_recreate_data_store', true ) ) {
return;
}
if (
! class_exists( 'ActionScheduler' ) ||
! class_exists( 'ActionScheduler_HybridStore' ) ||
! class_exists( 'ActionScheduler_StoreSchema' ) ||
! class_exists( 'ActionScheduler_LoggerSchema' )
) {
return;
}
$store = \ActionScheduler::store();
if ( ! is_a( $store, 'ActionScheduler_HybridStore' ) ) {
$store = new \ActionScheduler_HybridStore();
}
$tableList = [
'actionscheduler_actions',
'actionscheduler_logs',
'actionscheduler_groups',
'actionscheduler_claims',
];
foreach ( $tableList as $tableName ) {
if ( ! aioseo()->core->db->tableExists( $tableName ) ) {
add_action( 'action_scheduler/created_table', [ $store, 'set_autoincrement' ], 10, 2 );
$storeSchema = new \ActionScheduler_StoreSchema();
$loggerSchema = new \ActionScheduler_LoggerSchema();
$storeSchema->register_tables( true );
$loggerSchema->register_tables( true );
remove_action( 'action_scheduler/created_table', [ $store, 'set_autoincrement' ] );
break;
}
}
}
/**
* Cleans up the Action Scheduler tables after one of our actions completes.
* Hooked into `action_scheduler_after_execute` action hook.
*
* @since 4.0.10
*
* @param int $actionId The action ID processed.
* @param \ActionScheduler_Action $action Class instance.
* @return void
*/
public function cleanup( $actionId, $action = null ) {
if (
// Bail if this isn't one of our actions or if we're in a dev environment.
'aioseo' !== $action->get_group() ||
( defined( 'WP_ENVIRONMENT_TYPE' ) && 'development' === WP_ENVIRONMENT_TYPE ) ||
// Bail if the tables don't exist.
! aioseo()->core->db->tableExists( 'actionscheduler_actions' ) ||
! aioseo()->core->db->tableExists( 'actionscheduler_groups' ) ||
// Bail if it hasn't been long enough since the last cleanup.
aioseo()->core->cache->get( 'action_scheduler_log_cleanup' )
) {
return;
}
$prefix = aioseo()->core->db->db->prefix;
// Clean up logs associated with entries in the actions table.
aioseo()->core->db->execute(
"DELETE al FROM {$prefix}actionscheduler_logs as al
JOIN {$prefix}actionscheduler_actions as aa on `aa`.`action_id` = `al`.`action_id`
LEFT JOIN {$prefix}actionscheduler_groups as ag on `ag`.`group_id` = `aa`.`group_id`
WHERE (
(`ag`.`slug` = '{$this->actionSchedulerGroup}' AND `aa`.`status` IN ('complete', 'failed', 'canceled'))
OR
(`aa`.`hook` LIKE 'aioseo_%' AND `aa`.`group_id` = 0 AND `aa`.`status` IN ('complete', 'failed', 'canceled'))
);"
);
// Clean up actions.
aioseo()->core->db->execute(
"DELETE aa FROM {$prefix}actionscheduler_actions as aa
LEFT JOIN {$prefix}actionscheduler_groups as ag on `ag`.`group_id` = `aa`.`group_id`
WHERE (
(`ag`.`slug` = '{$this->actionSchedulerGroup}' AND `aa`.`status` IN ('complete', 'failed', 'canceled'))
OR
(`aa`.`hook` LIKE 'aioseo_%' AND `aa`.`group_id` = 0 AND `aa`.`status` IN ('complete', 'failed', 'canceled'))
);"
);
// Set a transient to prevent this from running again for a while.
aioseo()->core->cache->update( 'action_scheduler_log_cleanup', true, DAY_IN_SECONDS );
}
/**
* Schedules a single action at a specific time in the future.
*
* @since 4.0.13
* @version 4.2.7
*
* @param string $actionName The action name.
* @param int $time The time to add to the current time.
* @param array $args Args passed down to the action.
* @param bool $forceSchedule Whether we should schedule a new action regardless of whether one is already set.
* @return boolean Whether the action was scheduled.
*/
public function scheduleSingle( $actionName, $time = 0, $args = [], $forceSchedule = false ) {
try {
if ( $forceSchedule || ! $this->isScheduled( $actionName, $args ) ) {
as_schedule_single_action( time() + $time, $actionName, $args, $this->actionSchedulerGroup );
return true;
}
} catch ( \RuntimeException $e ) {
// Nothing needs to happen.
}
return false;
}
/**
* Checks if a given action is already scheduled.
*
* @since 4.0.13
* @version 4.2.7
*
* @param string $actionName The action name.
* @param array $args Args passed down to the action.
* @return boolean Whether the action is already scheduled.
*/
public function isScheduled( $actionName, $args = [] ) {
$scheduledActions = $this->getScheduledActions();
$hooks = [];
foreach ( $scheduledActions as $action ) {
$hooks[] = $action->hook;
}
$isScheduled = in_array( $actionName, array_filter( $hooks ), true );
if ( empty( $args ) ) {
return $isScheduled;
}
// If there are arguments, we need to check if the action is scheduled with the same arguments.
if ( $isScheduled ) {
foreach ( $scheduledActions as $action ) {
if ( $action->hook === $actionName ) {
foreach ( $args as $k => $v ) {
if ( ! isset( $action->args[ $k ] ) || $action->args[ $k ] !== $v ) {
continue;
}
return true;
}
}
}
}
return false;
}
/**
* Returns all AIOSEO scheduled actions.
*
* @since 4.7.7
*
* @return array The scheduled actions.
*/
private function getScheduledActions() {
static $scheduledActions = null;
if ( null !== $scheduledActions ) {
return $scheduledActions;
}
$scheduledActions = aioseo()->core->db->start( 'actionscheduler_actions as aa' )
->select( 'aa.hook, aa.args' )
->join( 'actionscheduler_groups as ag', 'ag.group_id', 'aa.group_id' )
->where( 'ag.slug', $this->actionSchedulerGroup )
->whereIn( 'status', [ 'pending', 'in-progress' ] )
->run()
->result();
// Decode the args.
foreach ( $scheduledActions as $key => $action ) {
$scheduledActions[ $key ]->args = json_decode( $action->args, true );
}
return $scheduledActions;
}
/**
* Unschedule an action.
*
* @since 4.1.4
* @version 4.2.7
*
* @param string $actionName The action name to unschedule.
* @param array $args Args passed down to the action.
* @return void
*/
public function unschedule( $actionName, $args = [] ) {
try {
if ( as_next_scheduled_action( $actionName, $args ) ) {
as_unschedule_action( $actionName, $args, $this->actionSchedulerGroup );
}
} catch ( \Exception $e ) {
// Do nothing.
}
}
/**
* Schedules a recurring action.
*
* @since 4.1.5
* @version 4.2.7
*
* @param string $actionName The action name.
* @param int $time The seconds to add to the current time.
* @param int $interval The interval in seconds.
* @param array $args Args passed down to the action.
* @return boolean Whether the action was scheduled.
*/
public function scheduleRecurrent( $actionName, $time, $interval = 60, $args = [] ) {
try {
if ( ! $this->isScheduled( $actionName, $args ) ) {
as_schedule_recurring_action( time() + $time, $interval, $actionName, $args, $this->actionSchedulerGroup );
return true;
}
} catch ( \RuntimeException $e ) {
// Nothing needs to happen.
}
return false;
}
/**
* Schedule a single async action.
*
* @since 4.1.6
* @version 4.2.7
*
* @param string $actionName The name of the action.
* @param array $args Any relevant arguments.
* @return void
*/
public function scheduleAsync( $actionName, $args = [] ) {
try {
// Run the task immediately using an async action.
as_enqueue_async_action( $actionName, $args, $this->actionSchedulerGroup );
} catch ( \Exception $e ) {
// Do nothing.
}
}
}

View File

@@ -0,0 +1,91 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Traits;
/**
* Load file assets.
*
* @since 4.1.9
*/
class Assets {
use Traits\Assets;
/**
* Get the script handle to use for asset enqueuing.
*
* @since 4.1.9
*
* @var string
*/
private $scriptHandle = 'aioseo';
/**
* Class constructor.
*
* @since 4.1.9
*
* @param \AIOSEO\Plugin\Common\Core\Core $core The AIOSEO Core class.
*/
public function __construct( $core ) {
$this->core = $core;
$this->version = aioseo()->version;
$this->manifestFile = AIOSEO_DIR . '/dist/' . aioseo()->versionPath . '/manifest.php';
$this->isDev = aioseo()->isDev;
if ( $this->isDev ) {
$this->domain = getenv( 'VITE_AIOSEO_DOMAIN' );
$this->port = getenv( 'VITE_AIOSEO_DEV_PORT' );
}
add_filter( 'script_loader_tag', [ $this, 'scriptLoaderTag' ], 10, 3 );
add_action( 'admin_head', [ $this, 'devRefreshRuntime' ] );
add_action( 'wp_head', [ $this, 'devRefreshRuntime' ] );
}
/**
* Get the public URL base.
*
* @since 4.1.9
*
* @return string The URL base.
*/
private function getPublicUrlBase() {
return $this->shouldLoadDev() ? $this->getDevUrl() . 'dist/' . aioseo()->versionPath . '/assets/' : $this->basePath();
}
/**
* Get the base path URL.
*
* @since 4.1.9
*
* @return string The base path URL.
*/
private function basePath() {
return $this->normalizeAssetsHost( plugins_url( 'dist/' . aioseo()->versionPath . '/assets/', AIOSEO_FILE ) );
}
/**
* Adds the RefreshRuntime.
*
* @since 4.1.9
*
* @return void
*/
public function devRefreshRuntime() {
if ( $this->shouldLoadDev() ) {
echo sprintf( '<script type="module">
import RefreshRuntime from "%1$s@react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () => {}
window.$RefreshSig$ = () => (type) => type
window.__vite_plugin_react_preamble_installed__ = true
</script>', $this->getDevUrl() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
}
}

View File

@@ -0,0 +1,112 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Backup for AIOSEO Settings.
*
* @since 4.0.0
*/
class Backup {
/**
* A the name of the option to save backups with.
*
* @since 4.00
*
* @var string
*/
private $optionsName = 'aioseo_settings_backup';
/**
* Get all backups.
*
* @return array An array of backups.
*/
public function all() {
$backups = json_decode( get_option( $this->optionsName ), true );
if ( empty( $backups ) ) {
$backups = [];
}
return $backups;
}
/**
* Creates a backup of the settings state.
*
* @since 4.0.0
*
* @return void
*/
public function create() {
$backupTime = time();
$options = $this->getOptions();
update_option( $this->optionsName . '_' . $backupTime, wp_json_encode( $options ), 'no' );
$backups = $this->all();
$backups[] = $backupTime;
update_option( $this->optionsName, wp_json_encode( $backups ), 'no' );
}
/**
* Deletes a backup of the settings.
*
* @since 4.0.0
*
* @return void
*/
public function delete( $backupTime ) {
delete_option( $this->optionsName . '_' . $backupTime );
$backups = $this->all();
foreach ( $backups as $key => $backup ) {
if ( $backup === $backupTime ) {
unset( $backups[ $key ] );
}
}
update_option( $this->optionsName, wp_json_encode( array_values( $backups ) ), 'no' );
}
/**
* Restores a backup of the settings.
*
* @since 4.0.0
*
* @return void
*/
public function restore( $backupTime ) {
$backup = json_decode( get_option( $this->optionsName . '_' . $backupTime ), true );
if ( ! empty( $backup['options']['tools']['robots']['rules'] ) ) {
$backup['options']['tools']['robots']['rules'] = array_merge(
aioseo()->robotsTxt->extractSearchAppearanceRules(),
$backup['options']['tools']['robots']['rules']
);
}
aioseo()->options->sanitizeAndSave( $backup['options'] );
aioseo()->internalOptions->sanitizeAndSave( $backup['internalOptions'] );
}
/**
* Get the options to save.
*
* @since 4.0.0
*
* @return array An array of options to save.
*/
private function getOptions() {
return [
'options' => aioseo()->options->all(),
'internalOptions' => aioseo()->internalOptions->all()
];
}
}

View File

@@ -0,0 +1,166 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Block helpers.
*
* @since 4.1.1
*/
class Blocks {
/**
* Class constructor.
*
* @since 4.1.1
*/
public function __construct() {
add_action( 'init', [ $this, 'init' ] );
}
/**
* Initializes our blocks.
*
* @since 4.1.1
*
* @return void
*/
public function init() {
add_action( 'enqueue_block_editor_assets', [ $this, 'registerBlockEditorAssets' ] );
}
/**
* Registers the block type with WordPress.
*
* @since 4.2.1
*
* @param string $slug Block type name including namespace.
* @param array $args Array of block type arguments with additional 'wp_min_version' arg.
* @return \WP_Block_Type|false The registered block type on success, or false on failure.
*/
public function registerBlock( $slug = '', $args = [] ) {
global $wp_version; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( ! strpos( $slug, '/' ) ) {
$slug = 'aioseo/' . $slug;
}
if ( ! $this->isBlockEditorActive() ) {
return false;
}
// Check if the block requires a minimum WP version.
if ( ! empty( $args['wp_min_version'] ) && version_compare( $wp_version, $args['wp_min_version'], '>' ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
return false;
}
// Checking whether block is registered to ensure it isn't registered twice.
if ( $this->isRegistered( $slug ) ) {
return false;
}
$defaults = [
'render_callback' => null,
'editor_script' => aioseo()->core->assets->jsHandle( 'src/vue/standalone/blocks/main.js' ),
'editor_style' => aioseo()->core->assets->cssHandle( 'src/vue/assets/scss/blocks-editor.scss' ),
'attributes' => null,
'supports' => null
];
$args = wp_parse_args( $args, $defaults );
return register_block_type( $slug, $args );
}
/**
* Registers Gutenberg editor assets.
*
* @since 4.2.1
*
* @return void
*/
public function registerBlockEditorAssets() {
$postSettingJsAsset = 'src/vue/standalone/post-settings/main.js';
if (
aioseo()->helpers->isScreenBase( 'widgets' ) ||
aioseo()->helpers->isScreenBase( 'customize' )
) {
/**
* Make sure the post settings JS asset is registered before adding it as a dependency below.
* This is needed because this asset is not loaded on widgets and customizer screens,
* {@see \AIOSEO\Plugin\Common\Admin\PostSettings::enqueuePostSettingsAssets}.
*
* @link https://github.com/awesomemotive/aioseo/issues/3326
*/
aioseo()->core->assets->load( $postSettingJsAsset, [], aioseo()->helpers->getVueData() );
}
aioseo()->core->assets->loadCss( 'src/vue/standalone/blocks/main.js' );
$dependencies = [
'wp-annotations',
'wp-block-editor',
'wp-blocks',
'wp-components',
'wp-element',
'wp-i18n',
'wp-data',
'wp-url',
'wp-polyfill',
aioseo()->core->assets->jsHandle( $postSettingJsAsset )
];
aioseo()->core->assets->enqueueJs( 'src/vue/standalone/blocks/main.js', $dependencies );
aioseo()->core->assets->registerCss( 'src/vue/assets/scss/blocks-editor.scss' );
}
/**
* Check if a block is already registered.
*
* @since 4.2.1
*
* @param string $slug Name of block to check.
*
* @return bool
*/
public function isRegistered( $slug ) {
if ( ! class_exists( 'WP_Block_Type_Registry' ) ) {
return false;
}
return \WP_Block_Type_Registry::get_instance()->is_registered( $slug );
}
/**
* Helper function to determine if we're rendering the block inside Gutenberg.
*
* @since 4.1.1
*
* @return bool In gutenberg.
*/
public function isRenderingBlockInEditor() {
// phpcs:disable HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
return false;
}
$context = isset( $_REQUEST['context'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['context'] ) ) : '';
// phpcs:enable HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
return 'edit' === $context;
}
/**
* Helper function to determine if we can register blocks.
*
* @since 4.1.1
*
* @return bool Can register block.
*/
public function isBlockEditorActive() {
return function_exists( 'register_block_type' );
}
}

View File

@@ -0,0 +1,314 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles our cache.
*
* @since 4.1.5
*/
class Cache {
/**
* Our cache table.
*
* @since 4.1.5
*
* @var string
*/
private $table = 'aioseo_cache';
/**
* Our cached cache.
*
* @since 4.1.5
*
* @var array
*/
private static $cache = [];
/**
* The Cache Prune class.
*
* @since 4.1.5
*
* @var CachePrune
*/
public $prune;
/**
* Prefix for this cache.
*
* @since 4.1.5
*
* @var string
*/
protected $prefix = '';
/**
* Class constructor.
*
* @since 4.7.7.1
*/
public function __construct() {
add_action( 'init', [ $this, 'checkIfTableExists' ] ); // This needs to run on init because the DB
// class gets instantiated along with the cache class.
}
/**
* Checks if the cache table exists and creates it if it doesn't.
*
* @since 4.7.7.1
*
* @return void
*/
public function checkIfTableExists() {
if ( ! aioseo()->core->db->tableExists( $this->table ) ) {
aioseo()->preUpdates->createCacheTable();
}
}
/**
* Returns the cache value for a key if it exists and is not expired.
*
* @since 4.1.5
*
* @param string $key The cache key name. Use a '%' for a like query.
* @param bool|array $allowedClasses Whether to allow objects to be returned.
* @return mixed The value or null if the cache does not exist.
*/
public function get( $key, $allowedClasses = false ) {
$key = $this->prepareKey( $key );
if ( isset( self::$cache[ $key ] ) ) {
return self::$cache[ $key ];
}
// Are we searching for a group of keys?
$isLikeGet = preg_match( '/%/', (string) $key );
$result = aioseo()->core->db
->start( $this->table )
->select( '`key`, `value`' )
->whereRaw( '( `expiration` IS NULL OR `expiration` > \'' . aioseo()->helpers->timeToMysql( time() ) . '\' )' );
$isLikeGet ?
$result->whereRaw( '`key` LIKE \'' . $key . '\'' ) :
$result->where( 'key', $key );
$result->output( ARRAY_A )->run();
// If we have nothing in the cache let's return a hard null.
$values = $result->nullSet() ? null : $result->result();
// If we have something let's normalize it.
if ( $values ) {
foreach ( $values as &$value ) {
$value['value'] = aioseo()->helpers->maybeUnserialize( $value['value'], $allowedClasses );
}
// Return only the single cache value.
if ( ! $isLikeGet ) {
$values = $values[0]['value'];
}
}
// Return values without a static cache.
// This is here because clearing the like cache is not simple.
if ( $isLikeGet ) {
return $values;
}
self::$cache[ $key ] = $values;
return self::$cache[ $key ];
}
/**
* Updates the given cache or creates it if it doesn't exist.
*
* @since 4.1.5
*
* @param string $key The cache key name.
* @param mixed $value The value.
* @param int $expiration The expiration time in seconds. Defaults to 24 hours. 0 to no expiration.
* @return void
*/
public function update( $key, $value, $expiration = DAY_IN_SECONDS ) {
// If the value is null we'll convert it and give it a shorter expiration.
if ( null === $value ) {
$value = false;
$expiration = 10 * MINUTE_IN_SECONDS;
}
$serializedValue = serialize( $value );
$expiration = 0 < $expiration ? aioseo()->helpers->timeToMysql( time() + $expiration ) : null;
aioseo()->core->db->insert( $this->table )
->set( [
'key' => $this->prepareKey( $key ),
'value' => $serializedValue,
'expiration' => $expiration,
'created' => aioseo()->helpers->timeToMysql( time() ),
'updated' => aioseo()->helpers->timeToMysql( time() )
] )
->onDuplicate( [
'value' => $serializedValue,
'expiration' => $expiration,
'updated' => aioseo()->helpers->timeToMysql( time() )
] )
->run();
$this->updateStatic( $key, $value );
}
/**
* Deletes the given cache key.
*
* @since 4.1.5
*
* @param string $key The cache key.
* @return void
*/
public function delete( $key ) {
$key = $this->prepareKey( $key );
aioseo()->core->db->delete( $this->table )
->where( 'key', $key )
->run();
$this->clearStatic( $key );
}
/**
* Prepares the key before using the cache.
*
* @since 4.1.5
*
* @param string $key The key to prepare.
* @return string The prepared key.
*/
private function prepareKey( $key ) {
$key = trim( $key );
$key = $this->prefix && 0 !== strpos( $key, $this->prefix ) ? $this->prefix . $key : $key;
if ( aioseo()->helpers->isDev() && 80 < mb_strlen( $key, 'UTF-8' ) ) {
throw new \Exception( 'You are using a cache key that is too large, shorten your key and try again: [' . esc_html( $key ) . ']' );
}
return $key;
}
/**
* Clears all of our cache.
*
* @since 4.1.5
*
* @return void
*/
public function clear() {
// Bust the tableExists and columnExists cache.
aioseo()->internalOptions->database->installedTables = '';
if ( $this->prefix ) {
$this->clearPrefix( '' );
return;
}
// If we find the activation redirect, we'll need to reset it after clearing.
$activationRedirect = $this->get( 'activation_redirect' );
aioseo()->core->db->truncate( $this->table )->run();
$this->clearStatic();
if ( $activationRedirect ) {
$this->update( 'activation_redirect', $activationRedirect, 30 );
}
}
/**
* Clears all of our cache under a certain prefix.
*
* @since 4.1.5
*
* @param string $prefix A prefix to clear or empty to clear everything.
* @return void
*/
public function clearPrefix( $prefix ) {
$prefix = $this->prepareKey( $prefix );
aioseo()->core->db->delete( $this->table )
->whereRaw( "`key` LIKE '$prefix%'" )
->run();
$this->clearStaticPrefix( $prefix );
}
/**
* Clears all of our static in-memory cache of a prefix.
*
* @since 4.1.5
*
* @param string $prefix A prefix to clear.
* @return void
*/
private function clearStaticPrefix( $prefix ) {
$prefix = $this->prepareKey( $prefix );
foreach ( array_keys( self::$cache ) as $key ) {
if ( 0 === strpos( $key, $prefix ) ) {
unset( self::$cache[ $key ] );
}
}
}
/**
* Clears all of our static in-memory cache.
*
* @since 4.1.5
*
* @param string $key A key to clear.
* @return void
*/
private function clearStatic( $key = null ) {
if ( empty( $key ) ) {
self::$cache = [];
return;
}
unset( self::$cache[ $this->prepareKey( $key ) ] );
}
/**
* Clears all of our static in-memory cache or the cache for a single given key.
*
* @since 4.7.1
*
* @param string $key A key to clear (optional).
* @param string $value A value to update (optional).
* @return void
*/
private function updateStatic( $key = null, $value = null ) {
if ( empty( $key ) ) {
$this->clearStatic( $key );
return;
}
self::$cache[ $this->prepareKey( $key ) ] = $value;
}
/**
* Returns the cache table name.
*
* @since 4.1.5
*
* @return string
*/
public function getTableName() {
return $this->table;
}
}

View File

@@ -0,0 +1,104 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles our cache pruning.
*
* @since 4.1.5
*/
class CachePrune {
/**
* The action for the scheduled cache prune.
*
* @since 4.1.5
*
* @var string
*/
private $pruneAction = 'aioseo_cache_prune';
/**
* The action for the scheduled old cache clean.
*
* @since 4.1.5
*
* @var string
*/
private $optionCacheCleanAction = 'aioseo_old_cache_clean';
/**
* Class constructor.
*
* @since 4.1.5
*/
public function __construct() {
add_action( 'init', [ $this, 'init' ] );
}
/**
* Inits our class.
*
* @since 4.1.5
*
* @return void
*/
public function init() {
add_action( $this->pruneAction, [ $this, 'prune' ] );
add_action( $this->optionCacheCleanAction, [ $this, 'optionCacheClean' ] );
if ( ! is_admin() ) {
return;
}
if ( ! aioseo()->actionScheduler->isScheduled( $this->pruneAction ) ) {
aioseo()->actionScheduler->scheduleRecurrent( $this->pruneAction, 0, DAY_IN_SECONDS );
}
}
/**
* Prunes our expired cache.
*
* @since 4.1.5
*
* @return void
*/
public function prune() {
aioseo()->core->db->delete( aioseo()->core->cache->getTableName() )
->whereRaw( '( `expiration` IS NOT NULL AND expiration <= \'' . aioseo()->helpers->timeToMysql( time() ) . '\' )' )
->run();
}
/**
* Cleans our old options cache.
*
* @since 4.1.5
*
* @return void
*/
public function optionCacheClean() {
$optionCache = aioseo()->core->db->delete( aioseo()->core->db->db->options, true )
->whereRaw( "option_name LIKE '\_aioseo\_cache\_%'" )
->limit( 10000 )
->run();
// Schedule a new run if we're not done cleaning.
if ( 0 !== $optionCache->db->rows_affected ) {
aioseo()->actionScheduler->scheduleSingle( $this->optionCacheCleanAction, MINUTE_IN_SECONDS, [], true );
}
}
/**
* Returns the action name for the old cache clean.
*
* @since 4.1.5
*
* @return string
*/
public function getOptionCacheCleanAction() {
return $this->optionCacheCleanAction;
}
}

View File

@@ -0,0 +1,204 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Contains helper methods specific to the addons.
*
* @since 4.3.0
*/
class Features {
/**
* The features URL.
*
* @since 4.3.0
*
* @var string
*/
protected $featuresUrl = 'https://licensing-cdn.aioseo.com/keys/lite/all-in-one-seo-pack-pro-features.json';
/**
* Returns our features.
*
* @since 4.3.0
*
* @param boolean $flushCache Whether or not to flush the cache.
* @return array An array of addon data.
*/
public function getFeatures( $flushCache = false ) {
$features = aioseo()->core->networkCache->get( 'license_features' );
if ( null === $features || $flushCache ) {
$response = aioseo()->helpers->wpRemoteGet( $this->getFeaturesUrl() );
if ( 200 === wp_remote_retrieve_response_code( $response ) ) {
$features = json_decode( wp_remote_retrieve_body( $response ), true );
}
if ( ! $features || ! empty( $features->error ) ) {
$features = $this->getDefaultFeatures();
}
aioseo()->core->networkCache->update( 'license_features', $features );
}
// Convert the features array to objects using JSON. This is essential because we have lots of features that rely on this to be an object, and changing it to an array would break them.
// See: https://github.com/awesomemotive/aioseo/issues/5966
$features = json_decode( wp_json_encode( $features ) );
return $features;
}
/**
* Get the URL to get features.
*
* @since 4.1.8
*
* @return string The URL.
*/
protected function getFeaturesUrl() {
$url = $this->featuresUrl;
if ( defined( 'AIOSEO_FEATURES_URL' ) ) {
$url = AIOSEO_FEATURES_URL;
}
return $url;
}
/**
* Retrieves a default list of all external saas features available for the current user if the API cannot be reached.
*
* @since 4.3.0
*
* @return array An array of features.
*/
protected function getDefaultFeatures() {
return json_decode( wp_json_encode( [
[
'license_level' => 'pro',
'section' => 'schema',
'feature' => 'event'
],
[
'license_level' => 'elite',
'section' => 'schema',
'feature' => 'event'
],
[
'license_level' => 'elite',
'section' => 'schema',
'feature' => 'job-posting'
],
[
'license_level' => 'elite',
'section' => 'tools',
'feature' => 'network-tools-site-activation'
],
[
'license_level' => 'elite',
'section' => 'tools',
'feature' => 'network-tools-database'
],
[
'license_level' => 'elite',
'section' => 'tools',
'feature' => 'network-tools-import-export'
],
[
'license_level' => 'elite',
'section' => 'tools',
'feature' => 'network-tools-robots'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'seo-statistics'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'keyword-rankings'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'keyword-rankings-pages'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'content-rankings'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail-page-speed'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail-seo-statistics'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail-keywords'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail-focus-keyword-trend'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'keyword-tracking'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'post-detail-keyword-tracking'
],
[
'license_level' => 'elite',
'section' => 'search-statistics',
'feature' => 'index-status'
]
] ), true );
}
/**
* Get the plans for a given feature.
*
* @since 4.3.0
*
* @param string $sectionSlug The section name.
* @param string $feature The feature name.
* @return array The plans for the feature.
*/
public function getPlansForFeature( $sectionSlug, $feature = '' ) {
$plans = [];
// Loop through all the features and find the plans that have access to the feature.
foreach ( $this->getFeatures() as $featureArray ) {
if ( $featureArray->section !== $sectionSlug ) {
continue;
}
if ( ! empty( $feature ) && $featureArray->feature !== $feature ) {
continue;
}
$plans[] = ucfirst( $featureArray->license_level );
}
return array_unique( $plans );
}
}

View File

@@ -0,0 +1,280 @@
<?php
// phpcs:disable WordPress.WP.AlternativeFunctions
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Load our manifest to use throughout the app.
*
* @since 4.1.9
*/
class Filesystem {
/**
* Holds the WordPress filesystem object.
*
* @since 4.1.9
*
* @var \WP_Filesystem_Base
*/
public $fs = null;
/**
* Core class instance.
*
* @since 4.2.7
*
* @var \AIOSEO\Plugin\Common\Core\Core
*/
private $core = null;
/**
* Class constructor.
*
* @since 4.1.9
*
* @param \AIOSEO\Plugin\Common\Core\Core $core The AIOSEO Core class.
* @param array $args Any arguments needed to construct the class with.
*/
public function __construct( $core, $args = [] ) {
$this->core = $core;
$this->init( $args );
}
/**
* Initialize the filesystem.
*
* @since 4.1.9
*
* @param array $args An array of arguments for the WP_Filesystem
* @return void
*/
public function init( $args = [] ) {
require_once ABSPATH . 'wp-admin/includes/file.php';
WP_Filesystem( $args );
global $wp_filesystem; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( is_object( $wp_filesystem ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
$this->fs = $wp_filesystem; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
}
}
/**
* Wrapper method to check if a file exists.
*
* @since 4.1.9
*
* @param string $filename The filename to check if it exists.
* @return bool Returns true if the file or directory specified by filename exists; false otherwise.
*/
public function exists( $filename ) {
if ( ! $this->isWpfsValid() ) {
return @file_exists( $filename );
}
return $this->fs->exists( $filename );
}
/**
* Retrieve the contents of a file.
*
* @since 4.1.9
*
* @param string $filename The filename to get the contents for.
* @return string|bool The function returns the read data or false on failure.
*/
public function getContents( $filename ) {
if ( ! $this->exists( $filename ) ) {
return false;
}
if ( ! $this->isWpfsValid() ) {
return @file_get_contents( $filename );
}
return $this->fs->get_contents( $filename );
}
/**
* Reads entire file into an array.
*
* @since 4.1.9
*
* @param string $file Path to the file.
* @return array|bool File contents in an array on success, false on failure.
*/
public function getContentsArray( $file ) {
if ( ! $this->exists( $file ) ) {
return false;
}
if ( ! $this->isWpfsValid() ) {
return @file( $file );
}
return $this->fs->get_contents_array( $file );
}
/**
* Sets the access and modification times of a file.
* Note: If $file doesn't exist, it will be created.
*
* @since 4.1.9
*
* @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 True on success, false on failure.
*/
public function touch( $file, $time = 0, $atime = 0 ) {
if ( 0 === $time ) {
$time = time();
}
if ( 0 === $atime ) {
$atime = time();
}
if ( ! $this->isWpfsValid() ) {
return @touch( $file, $time, $atime );
}
return $this->fs->touch( $file, $time, $atime );
}
/**
* Writes a string to a file.
*
* @since 4.1.9
*
* @param string $file Remote path to the file where to write the data.
* @param string $contents The data to write.
* @param int|false $mode Optional. The file permissions as octal number, usually 0644. Default false.
* @return int|bool True on success, false on failure.
*/
public function putContents( $file, $contents, $mode = false ) {
if ( ! $this->isWpfsValid() ) {
return @file_put_contents( $file, $contents );
}
return $this->fs->put_contents( $file, $contents, $mode );
}
/**
* Checks if a file or directory is writable.
*
* @since 4.1.9
*
* @param string $file Path to file or directory.
* @return bool Whether $file is writable.
*/
public function isWritable( $file ) {
if ( ! $this->isWpfsValid() ) {
return @is_writable( $file );
}
return $this->fs->is_writable( $file );
}
/**
* Checks if a file is readable.
*
* @since 4.1.9
*
* @param string $file Path to file.
* @return bool Whether $file is readable.
*/
public function isReadable( $file ) {
if ( ! $this->isWpfsValid() ) {
return @is_readable( $file );
}
return $this->fs->is_readable( $file );
}
/**
* Gets the file size (in bytes).
*
* @since 4.1.9
*
* @param string $file Path to file.
* @return int|bool Size of the file in bytes on success, false on failure.
*/
public function size( $file ) {
if ( ! $this->isWpfsValid() ) {
return @filesize( $file );
}
return $this->fs->size( $file );
}
/**
* Checks if resource is a file.
*
* @since 4.1.9
*
* @param string $file File path.
* @return bool Whether $file is a file.
*/
public function isFile( $file ) {
if ( ! $this->isWpfsValid() ) {
return @is_file( $file );
}
return $this->fs->is_file( $file );
}
/**
* Checks if resource is a directory.
*
* @since 4.1.9
*
* @param string $path Directory path.
* @return bool Whether $path is a directory.
*/
public function isDir( $path ) {
if ( ! $this->isWpfsValid() ) {
return @is_dir( $path );
}
return $this->fs->is_dir( $path );
}
/**
* A simple check to ensure that the WP_Filesystem is valid.
*
* @since 4.1.9
*
* @return bool True if valid, false if not.
*/
public function isWpfsValid() {
if (
! is_a( $this->fs, 'WP_Filesystem_Base' ) ||
(
// Errors is a WP_Error object.
! empty( $this->fs->errors ) &&
// We directly check if the errors array is empty for compatibility with WP < 5.1.
! empty( $this->fs->errors->errors )
)
) {
return false;
}
return true;
}
/**
* In order to not have a conflict, we need to return a clone.
*
* @since 4.1.9
*
* @return Filesystem The cloned Filesystem object.
*/
public function noConflict() {
return clone $this;
}
}

View File

@@ -0,0 +1,404 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Traits\Helpers as TraitHelpers;
/**
* Contains helper functions
*
* @since 4.0.0
*/
class Helpers {
use TraitHelpers\Api;
use TraitHelpers\Arrays;
use TraitHelpers\Constants;
use TraitHelpers\Deprecated;
use TraitHelpers\DateTime;
use TraitHelpers\Language;
use TraitHelpers\Numbers;
use TraitHelpers\PostType;
use TraitHelpers\Request;
use TraitHelpers\Shortcodes;
use TraitHelpers\Strings;
use TraitHelpers\Svg;
use TraitHelpers\ThirdParty;
use TraitHelpers\Url;
use TraitHelpers\Vue;
use TraitHelpers\Wp;
use TraitHelpers\WpContext;
use TraitHelpers\WpMultisite;
use TraitHelpers\WpUri;
/**
* Generate a UTM URL from the url and medium/content passed in.
*
* @since 4.0.0
*
* @param string $url The URL to parse.
* @param string $medium The UTM medium parameter.
* @param string|null $content The UTM content parameter or null.
* @param boolean $esc Whether or not to escape the URL.
* @return string The new URL.
*/
public function utmUrl( $url, $medium, $content = null, $esc = true ) {
// First, remove any existing utm parameters on the URL.
$url = remove_query_arg( [
'utm_source',
'utm_medium',
'utm_campaign',
'utm_content'
], $url );
// Generate the new arguments.
$args = [
'utm_source' => 'WordPress',
'utm_campaign' => aioseo()->pro ? 'proplugin' : 'liteplugin',
'utm_medium' => $medium
];
// Content is not used by default.
if ( $content ) {
$args['utm_content'] = $content;
}
// Return the new URL.
$url = add_query_arg( $args, $url );
return $esc ? esc_url( $url ) : $url;
}
/**
* Checks if we are in a dev environment or not.
*
* @since 4.1.0
*
* @return boolean True if we are, false if not.
*/
public function isDev() {
return aioseo()->isDev || isset( $_REQUEST['aioseo-dev'] ); // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
}
/**
* Checks if the server is running on Apache.
*
* @since 4.0.0
*
* @return boolean Whether or not it is on apache.
*/
public function isApache() {
if ( ! isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
return false;
}
return stripos( sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ), 'apache' ) !== false;
}
/**
* Checks if the server is running on nginx.
*
* @since 4.0.0
*
* @return bool Whether or not it is on nginx.
*/
public function isNginx() {
if ( ! isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
return false;
}
$server = sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) );
if (
false !== stripos( $server, 'Flywheel' ) ||
false !== stripos( $server, 'nginx' )
) {
return true;
}
return false;
}
/**
* Checks if the server is running on LiteSpeed.
*
* @since 4.5.3
*
* @return bool Whether it is on LiteSpeed.
*/
public function isLiteSpeed() {
if ( ! isset( $_SERVER['SERVER_SOFTWARE'] ) ) {
return false;
}
$server = strtolower( sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) );
return false !== stripos( $server, 'litespeed' );
}
/**
* Returns the server name: Apache, nginx or LiteSpeed.
*
* @since 4.5.3
*
* @return string The server name. An empty string if it's unknown.
*/
public function getServerName() {
if ( aioseo()->helpers->isApache() ) {
return 'apache';
}
if ( aioseo()->helpers->isNginx() ) {
return 'nginx';
}
if ( aioseo()->helpers->isLiteSpeed() ) {
return 'litespeed';
}
return '';
}
/**
* Validate IP addresses.
*
* @since 4.0.0
*
* @param string $ip The IP address to validate.
* @return boolean If the IP address is valid or not.
*/
public function validateIp( $ip ) {
if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4 ) ) {
return true;
}
if ( filter_var( $ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6 ) ) {
return true;
}
// Doesn't seem to be a valid IP.
return false;
}
/**
* Convert bytes to readable format.
*
* @since 4.0.0
*
* @param integer $bytes The size of the file.
* @return array The original and readable file size.
*/
public function convertFileSize( $bytes ) {
if ( empty( $bytes ) ) {
return [
'original' => 0,
'readable' => '0 B'
];
}
$i = floor( log( $bytes ) / log( 1024 ) );
$sizes = [ 'B', 'KB', 'MB', 'GB', 'TB' ];
return [
'original' => $bytes,
'readable' => sprintf( '%.02F', $bytes / pow( 1024, $i ) ) * 1 . ' ' . $sizes[ $i ]
];
}
/**
* Sanitizes a given option value before we store it in the DB.
*
* Used by the migration and importer classes.
*
* @since 4.0.0
*
* @param mixed $value The value.
* @return mixed $value The sanitized value.
*/
public function sanitizeOption( $value ) {
switch ( gettype( $value ) ) {
case 'boolean':
return (bool) $value;
case 'string':
$value = aioseo()->helpers->decodeHtmlEntities( $value );
return aioseo()->helpers->encodeOutputHtml( wp_strip_all_tags( wp_check_invalid_utf8( trim( $value ) ) ) );
case 'integer':
return intval( $value );
case 'double':
return floatval( $value );
case 'array':
$sanitized = [];
foreach ( (array) $value as $child ) {
$sanitized[] = aioseo()->helpers->sanitizeOption( $child );
}
return $sanitized;
default:
return false;
}
}
/**
* Checks if the given string is serialized, and if so, unserializes it.
* If the serialized string contains an object, we abort to prevent PHP object injection.
*
* @since 4.1.0.2
*
* @param string $string The string.
* @param array|boolean $allowedClasses The allowed classes for unserialize.
* @return string|array The string or unserialized data.
*/
public function maybeUnserialize( $string, $allowedClasses = false ) {
if ( ! is_string( $string ) ) {
return $string;
}
$string = trim( $string );
if ( is_serialized( $string ) ) {
return @unserialize( $string, [ 'allowed_classes' => $allowedClasses ] ); // phpcs:disable PHPCompatibility.FunctionUse.NewFunctionParameters.unserialize_optionsFound
}
return $string;
}
/**
* Returns a deep clone of the given object.
* The built-in PHP clone KW provides a shallow clone. This method returns a deep clone that also clones nested object properties.
* You can use this method to sever the reference to nested objects.
*
* @since 4.4.7
*
* @return object The cloned object.
*/
public function deepClone( $object ) {
return unserialize( serialize( $object ) );
}
/**
* Sanitizes a given variable
*
* @since 4.5.6
*
* @param mixed $variable The variable.
* @param bool $preserveHtml Whether or not to preserve HTML for ALL fields.
* @param array $fieldsToPreserveHtml Specific fields to preserve HTML for.
* @param string $fieldName The name of the current field (when looping over a list).
* @return mixed The sanitized variable.
*/
public function sanitize( $variable, $preserveHtml = false, $fieldsToPreserveHtml = [], $fieldName = '' ) {
$type = gettype( $variable );
switch ( $type ) {
case 'boolean':
return (bool) $variable;
case 'string':
if ( $preserveHtml || in_array( $fieldName, $fieldsToPreserveHtml, true ) ) {
return aioseo()->helpers->decodeHtmlEntities( sanitize_text_field( htmlspecialchars( $variable, ENT_NOQUOTES, 'UTF-8' ) ) );
}
return sanitize_text_field( $variable );
case 'integer':
return intval( $variable );
case 'float':
case 'double':
return floatval( $variable );
case 'array':
$array = [];
foreach ( (array) $variable as $k => $v ) {
$array[ $k ] = $this->sanitize( $v, $preserveHtml, $fieldsToPreserveHtml, $k );
}
return $array;
default:
return false;
}
}
/**
* Return the version number with a filter to enable users to hide the version.
*
* @since 4.3.7
*
* @return string The current version or empty if the filter is active. Using ?aioseo-dev will override the filter.
*/
public function getAioseoVersion() {
$version = aioseo()->version;
if ( ! $this->isDev() && apply_filters( 'aioseo_hide_version_number', false ) ) {
$version = '';
}
return $version;
}
/**
* Retrieves the marketing site articles.
*
* @since 4.7.2
*
* @param bool $fetchImage Whether to fetch the article image.
* @return array The articles or an empty array on failure.
*/
public function fetchAioseoArticles( $fetchImage = false ) {
$items = aioseo()->core->networkCache->get( 'rss_feed' );
if ( null !== $items ) {
return $items;
}
$options = [
'timeout' => 10,
'sslverify' => false,
];
$response = wp_remote_get( 'https://aioseo.com/wp-json/wp/v2/posts?per_page=4', $options );
$body = wp_remote_retrieve_body( $response );
if ( ! $body ) {
return [];
}
$cached = [];
$items = json_decode( $body, true );
foreach ( $items as $k => $item ) {
$cached[ $k ] = [
'url' => $item['link'],
'title' => $item['title']['rendered'],
'date' => date( get_option( 'date_format' ), strtotime( $item['date'] ) ),
'content' => wp_html_excerpt( $item['content']['rendered'], 128, '&hellip;' ),
];
if ( $fetchImage ) {
$response = wp_remote_get( $item['_links']['wp:featuredmedia'][0]['href'] ?? '', $options );
$body = wp_remote_retrieve_body( $response );
if ( ! $body ) {
continue;
}
$image = json_decode( $body, true );
$cached[ $k ]['image'] = [
'url' => $image['source_url'] ?? '',
'alt' => $image['alt_text'] ?? '',
'sizes' => $image['media_details']['sizes'] ?? ''
];
}
}
aioseo()->core->networkCache->update( 'rss_feed', $cached, 24 * HOUR_IN_SECONDS );
return $cached;
}
/**
* Returns if the admin bar is enabled.
*
* @since 4.8.1
*
* @return bool Whether the admin bar is enabled.
*/
public function isAdminBarEnabled() {
$showAdminBarMenu = aioseo()->options->advanced->adminBarMenu;
return is_admin_bar_showing() && ( $showAdminBarMenu ?? true );
}
}

View File

@@ -0,0 +1,116 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles our network cache.
*
* @since 4.2.5
*/
class NetworkCache extends Cache {
/**
* Returns the cache value for a key if it exists and is not expired.
*
* @since 4.2.5
*
* @param string $key The cache key name. Use a '%' for a like query.
* @param bool|array $allowedClasses Whether to allow objects to be returned.
* @return mixed The value or null if the cache does not exist.
*/
public function get( $key, $allowedClasses = false ) {
if ( ! is_multisite() ) {
return parent::get( $key, $allowedClasses );
}
aioseo()->helpers->switchToBlog( aioseo()->helpers->getNetworkId() );
$value = parent::get( $key, $allowedClasses );
aioseo()->helpers->restoreCurrentBlog();
return $value;
}
/**
* Updates the given cache or creates it if it doesn't exist.
*
* @since 4.2.5
*
* @param string $key The cache key name.
* @param mixed $value The value.
* @param int $expiration The expiration time in seconds. Defaults to 24 hours. 0 to no expiration.
* @return void
*/
public function update( $key, $value, $expiration = DAY_IN_SECONDS ) {
if ( ! is_multisite() ) {
parent::update( $key, $value, $expiration );
return;
}
aioseo()->helpers->switchToBlog( aioseo()->helpers->getNetworkId() );
parent::update( $key, $value, $expiration );
aioseo()->helpers->restoreCurrentBlog();
}
/**
* Deletes the given cache key.
*
* @since 4.2.5
*
* @param string $key The cache key.
* @return void
*/
public function delete( $key ) {
if ( ! is_multisite() ) {
parent::delete( $key );
return;
}
aioseo()->helpers->switchToBlog( aioseo()->helpers->getNetworkId() );
parent::delete( $key );
aioseo()->helpers->restoreCurrentBlog();
}
/**
* Clears all of our cache.
*
* @since 4.2.5
*
* @return void
*/
public function clear() {
if ( ! is_multisite() ) {
parent::clear();
return;
}
aioseo()->helpers->switchToBlog( aioseo()->helpers->getNetworkId() );
parent::clear();
aioseo()->helpers->restoreCurrentBlog();
}
/**
* Clears all of our cache under a certain prefix.
*
* @since 4.2.5
*
* @param string $prefix A prefix to clear or empty to clear everything.
* @return void
*/
public function clearPrefix( $prefix ) {
if ( ! is_multisite() ) {
parent::clearPrefix( $prefix );
return;
}
aioseo()->helpers->switchToBlog( aioseo()->helpers->getNetworkId() );
parent::clearPrefix( $prefix );
aioseo()->helpers->restoreCurrentBlog();
}
}

View File

@@ -0,0 +1,197 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use WP_Error;
/** \WP_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
/** \Plugin_Upgrader class */
require_once ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
/**
* In WP 5.3 a PHP 5.6 splat operator (...$args) was added to \WP_Upgrader_Skin::feedback().
* We need to remove all calls to *Skin::feedback() method, as we can't override it in own Skins
* without breaking support for PHP 5.3-5.5.
*
* @internal Please do not use this class outside of core AIOSEO development. May be removed at any time.
*
* @since 1.5.6.1
*/
class PluginUpgraderSilentAjax extends \Plugin_Upgrader {
/**
* An array of links to install the plugins from.
*
* @since 4.0.0
*
* @var array
*/
public $pluginLinks = [
'brokenLinkChecker' => 'https://downloads.wordpress.org/plugin/broken-link-checker-seo.zip',
'optinMonster' => 'https://downloads.wordpress.org/plugin/optinmonster.zip',
'wpForms' => 'https://downloads.wordpress.org/plugin/wpforms-lite.zip',
'miLite' => 'https://downloads.wordpress.org/plugin/google-analytics-for-wordpress.zip',
'emLite' => 'https://downloads.wordpress.org/plugin/google-analytics-dashboard-for-wp.zip',
'wpMail' => 'https://downloads.wordpress.org/plugin/wp-mail-smtp.zip',
'rafflePress' => 'https://downloads.wordpress.org/plugin/rafflepress.zip',
'seedProd' => 'https://downloads.wordpress.org/plugin/coming-soon.zip',
'trustPulse' => 'https://downloads.wordpress.org/plugin/trustpulse-api.zip',
'instagramFeed' => 'https://downloads.wordpress.org/plugin/instagram-feed.zip',
'facebookFeed' => 'https://downloads.wordpress.org/plugin/custom-facebook-feed.zip',
'twitterFeed' => 'https://downloads.wordpress.org/plugin/custom-twitter-feeds.zip',
'youTubeFeed' => 'https://downloads.wordpress.org/plugin/feeds-for-youtube.zip',
'pushEngage' => 'https://downloads.wordpress.org/plugins/pushengage.zip',
'sugarCalendar' => 'https://downloads.wordpress.org/plugins/sugar-calendar-lite.zip',
'wpSimplePay' => 'https://downloads.wordpress.org/plugins/stripe.zip',
'easyDigitalDownloads' => 'https://downloads.wordpress.org/plugins/easy-digital-downloads.zip',
'wpcode' => 'https://downloads.wordpress.org/plugin/insert-headers-and-footers.zip',
'searchWp' => '',
'affiliateWp' => '',
'charitable' => 'https://downloads.wordpress.org/plugin/charitable.zip',
'duplicator' => 'https://downloads.wordpress.org/plugin/duplicator.zip'
];
/**
* An array of links to install the plugins from wordpress.org.
*
* @since 4.0.0
*
* @var array
*/
public $wpPluginLinks = [
'brokenLinkChecker' => 'https://wordpress.org/plugins/broken-link-checker-seo/',
'optinMonster' => 'https://wordpress.org/plugin/optinmonster/',
'wpForms' => 'https://wordpress.org/plugin/wpforms-lite/',
'miLite' => 'https://wordpress.org/plugin/google-analytics-for-wordpress/',
'emLite' => 'https://wordpress.org/plugin/google-analytics-dashboard-for-wp/',
'wpMail' => 'https://wordpress.org/plugin/wp-mail-smtp/',
'rafflePress' => 'https://wordpress.org/plugin/rafflepress/',
'seedProd' => 'https://wordpress.org/plugin/coming-soon/',
'trustPulse' => 'https://wordpress.org/plugin/trustpulse-api/',
'instagramFeed' => 'https://wordpress.org/plugin/instagram-feed/',
'facebookFeed' => 'https://wordpress.org/plugin/custom-facebook-feed/',
'twitterFeed' => 'https://wordpress.org/plugin/custom-twitter-feeds/',
'youTubeFeed' => 'https://wordpress.org/plugin/feeds-for-youtube/',
'pushEngage' => 'https://wordpress.org/plugins/pushengage/',
'sugarCalendar' => 'https://wordpress.org/plugins/sugar-calendar-lite/',
'wpSimplePay' => 'https://wordpress.org/plugins/stripe/',
'searchWp' => 'https://searchwp.com/',
'affiliateWp' => 'https://affiliatewp.com/',
'wpcode' => 'https://wordpress.org/plugins/insert-headers-and-footers/',
'charitable' => 'https://wordpress.org/plugins/charitable/',
'duplicator' => 'https://wordpress.org/plugins/duplicator/'
];
/**
* An array of slugs to check if plugins are activated.
*
* @since 4.0.0
*
* @var array
*/
public $pluginSlugs = [
'brokenLinkChecker' => 'broken-link-checker-seo/aioseo-broken-link-checker.php',
'optinMonster' => 'optinmonster/optin-monster-wp-api.php',
'wpForms' => 'wpforms-lite/wpforms.php',
'wpFormsPro' => 'wpforms/wpforms.php',
'miLite' => 'google-analytics-for-wordpress/googleanalytics.php',
'miPro' => 'google-analytics-premium/googleanalytics-premium.php',
'emLite' => 'google-analytics-dashboard-for-wp/gadwp.php',
'emPro' => 'exactmetrics-premium/exactmetrics-premium.php',
'wpMail' => 'wp-mail-smtp/wp_mail_smtp.php',
'wpMailPro' => 'wp-mail-smtp-pro/wp_mail_smtp.php',
'rafflePress' => 'rafflepress/rafflepress.php',
'rafflePressPro' => 'rafflepress-pro/rafflepress-pro.php',
'seedProd' => 'coming-soon/coming-soon.php',
'seedProdPro' => 'seedprod-coming-soon-pro-5/seedprod-coming-soon-pro-5.php',
'trustPulse' => 'trustpulse-api/trustpulse.php',
'instagramFeed' => 'instagram-feed/instagram-feed.php',
'instagramFeedPro' => 'instagram-feed-pro/instagram-feed.php',
'facebookFeed' => 'custom-facebook-feed/custom-facebook-feed.php',
'facebookFeedPro' => 'custom-facebook-feed-pro/custom-facebook-feed.php',
'twitterFeed' => 'custom-twitter-feeds/custom-twitter-feed.php',
'twitterFeedPro' => 'custom-twitter-feeds-pro/custom-twitter-feed.php',
'youTubeFeed' => 'feeds-for-youtube/youtube-feed.php',
'youTubeFeedPro' => 'youtube-feed-pro/youtube-feed.php',
'pushEngage' => 'pushengage/main.php',
'sugarCalendar' => 'sugar-calendar-lite/sugar-calendar-lite.php',
'sugarCalendarPro' => 'sugar-calendar/sugar-calendar.php',
'wpSimplePay' => 'stripe/stripe-checkout.php',
'wpSimplePayPro' => 'wp-simple-pay-pro-3/simple-pay.php',
'easyDigitalDownloads' => 'easy-digital-downloads/easy-digital-downloads.php',
'easyDigitalDownloadsPro' => 'easy-digital-downloads-pro/easy-digital-downloads.php',
'searchWp' => 'searchwp/index.php',
'affiliateWp' => 'affiliate-wp/affiliate-wp.php',
'wpcode' => 'insert-headers-and-footers/ihaf.php',
'wpcodePro' => 'wpcode-premium/wpcode.php',
'charitable' => 'charitable/charitable.php',
'duplicator' => 'duplicator/duplicator.php'
];
/**
* An array of links for admin settings.
*
* @since 4.0.0
*
* @var array
*/
public $pluginAdminUrls = [
'brokenLinkChecker' => 'admin.php?page=broken-link-checker#/settings',
'optinMonster' => 'admin.php?page=optin-monster-api-settings',
'wpForms' => 'admin.php?page=wpforms-settings',
'wpFormsPro' => 'admin.php?page=wpforms-settings',
'miLite' => 'admin.php?page=monsterinsights_settings#/',
'miPro' => 'admin.php?page=monsterinsights_settings#/',
'emLite' => 'admin.php?page=exactmetrics_settings#/',
'emPro' => 'admin.php?page=exactmetrics_settings#/',
'wpMail' => 'admin.php?page=wp-mail-smtp',
'wpMailPro' => 'admin.php?page=wp-mail-smtp',
'seedProd' => 'admin.php?page=seedprod_lite',
'seedProdPro' => 'admin.php?page=seedprod_pro',
'rafflePress' => 'admin.php?page=rafflepress_lite#/settings',
'rafflePressPro' => 'admin.php?page=rafflepress_pro#/settings',
'trustPulse' => 'admin.php?page=trustpulse',
'instagramFeed' => 'admin.php?page=sb-instagram-feed',
'instagramFeedPro' => 'admin.php?page=sb-instagram-feed',
'facebookFeed' => 'admin.php?page=cff-top',
'facebookFeedPro' => 'admin.php?page=cff-top',
'twitterFeed' => 'admin.php?page=ctf-settings',
'twitterFeedPro' => 'admin.php?page=ctf-settings',
'youTubeFeed' => 'admin.php?page=youtube-feed-settings',
'youTubeFeedPro' => 'admin.php?page=youtube-feed-settings',
'pushEngage' => 'admin.php?page=pushengage',
'sugarCalendar' => 'admin.php?page=sugar-calendar',
'sugarCalendarPro' => 'admin.php?page=sugar-calendar',
'wpSimplePay' => 'edit.php?post_type=simple-pay',
'wpSimplePayPro' => 'edit.php?post_type=simple-pay',
'easyDigitalDownloads' => 'edit.php?post_type=download&page=edd-settings',
'easyDigitalDownloadsPro' => 'edit.php?post_type=download&page=edd-settings',
'searchWp' => 'options-general.php?page=searchwp',
'affiliateWp' => 'admin.php?page=affiliate-wp',
'wpcode' => 'admin.php?page=wpcode',
'wpcodePro' => 'admin.php?page=wpcode',
'charitable' => 'admin.php?page=charitable-settings',
'duplicator' => 'admin.php?page=duplicator-settings'
];
/**
* An array of slugs that work in the network admin.
*
* @since 4.2.8
*
* @var array
*/
public $hasNetworkAdmin = [
'miLite' => 'admin.php?page=monsterinsights_network',
'miPro' => 'admin.php?page=monsterinsights_network',
'emLite' => 'admin.php?page=exactmetrics_network',
'emPro' => 'admin.php?page=exactmetrics_network',
'wpMail' => 'admin.php?page=wp-mail-smtp',
'wpMailPro' => 'admin.php?page=wp-mail-smtp',
];
}

View File

@@ -0,0 +1,67 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require_once ABSPATH . 'wp-admin/includes/plugin.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader-skin.php';
/**
* Class PluginSilentUpgraderSkin.
*
* @internal Please do not use this class outside of core All in One SEO development. May be removed at any time.
*
* @since 4.0.0
*/
class PluginUpgraderSkin extends \WP_Upgrader_Skin {
/**
* Empty out the header of its HTML content and only check to see if it has
* been performed or not.
*
* @since 4.0.0
*/
public function header() {}
/**
* Empty out the footer of its HTML contents.
*
* @since 4.0.0
*/
public function footer() {}
/**
* Instead of outputting HTML for errors, just return them.
* Ajax request will just ignore it.
*
* @since 4.0.0
*
* @param array $errors Array of errors with the install process.
* @return void
*/
public function error( $errors ) {
if ( ! empty( $errors ) ) {
wp_send_json_error( $errors );
}
}
/**
* Empty out JavaScript output that calls function to decrement the update counts.
*
* @since 4.0.0
*
* @param string $type Type of update count to decrement.
*/
public function decrement_update_count( $type ) {} // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable, PSR1.Methods.CamelCapsMethodName.NotCamelCaps
/**
* @since 4.2.5
*
* @param string $feedback Message data.
* @param mixed ...$args Optional text replacements.
* @return void
*/
public function feedback( $feedback, ...$args ) {} // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
}

View File

@@ -0,0 +1,134 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class Templates
*
* @since 4.0.17
*
* @package AIOSEO\Plugin\Common\Utils
*/
class Templates {
/**
* This plugin absolute path.
*
* @since 4.0.17
*
* @var string
*/
protected $pluginPath = AIOSEO_DIR;
/**
* Paths were our template files are located.
*
* @since 4.0.17
*
* @var string Array of paths.
*/
protected $paths = [
'app/Common/Views'
];
/**
*
* The theme folder.
*
* @since 4.0.17
*
* @var string
*/
private $themeTemplatePath = 'aioseo/';
/**
*
* A theme subfolder.
*
* @since 4.0.17
*
* @var string
*/
protected $themeTemplateSubpath = '';
/**
* Locate a template file in the theme or our plugin paths.
*
* @since 4.0.17
*
* @param string $templateName The template name.
* @return string The template absolute path.
*/
public function locateTemplate( $templateName ) {
// Try to find template file in the theme.
$template = locate_template(
[
trailingslashit( $this->getThemeTemplatePath() ) . trailingslashit( $this->getThemeTemplateSubpath() ) . $templateName
]
);
if ( ! $template ) {
// Try paths, in order.
foreach ( $this->paths as $path ) {
$template = trailingslashit( $this->addPluginPath( $path ) ) . $templateName;
if ( aioseo()->core->fs->exists( $template ) ) {
break;
}
}
}
return apply_filters( 'aioseo_locate_template', $template, $templateName );
}
/**
* Includes a template if the file exists.
*
* @param string $templateName The template path/name.php to be included.
* @param null $data Data passed down to the template.
* @return void
*/
public function getTemplate( $templateName, $data = null ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
$template = $this->locateTemplate( $templateName );
if ( ! empty( $template ) and aioseo()->core->fs->exists( $template ) ) {
include $template;
}
}
/**
* Add this plugin path when trying the paths.
*
* @since 4.0.17
*
* @param string $path A path.
* @return string A path with the plugin absolute path.
*/
protected function addPluginPath( $path ) {
return trailingslashit( $this->pluginPath ) . $path;
}
/**
* Returns the theme folder for templates.
*
* @since 4.0.17
*
* @return string The theme folder for templates.
*/
public function getThemeTemplatePath() {
return apply_filters( 'aioseo_template_path', $this->themeTemplatePath );
}
/**
*
* Returns the theme subfolder for templates.
*
* @since 4.0.17
*
* @return string The theme subfolder for templates.
*/
public function getThemeTemplateSubpath() {
return apply_filters( 'aioseo_template_subpath', $this->themeTemplateSubpath );
}
}

View File

@@ -0,0 +1,320 @@
<?php
namespace AIOSEO\Plugin\Common\Utils;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Vue Settings for the user.
*
* @since 4.0.0
*/
class VueSettings {
/**
* The name to lookup the settings with.
*
* @since 4.0.0
*
* @var string
*/
private $settingsName = '';
/**
* The settings array.
*
* @since 4.0.0
*
* @var array
*/
private $settings = [];
/**
* All the default settings.
*
* @since 4.0.0
*
* @var array
*/
private $defaults = [
'showUpgradeBar' => true,
'showSetupWizard' => true,
'toggledCards' => [
'dashboardOverview' => true,
'dashboardSeoSetup' => true,
'dashboardSeoSiteScore' => true,
'dashboardNotifications' => true,
'dashboardSupport' => true,
'license' => true,
'webmasterTools' => true,
'enableBreadcrumbs' => true,
'breadcrumbSettings' => true,
'breadcrumbTemplates' => true,
'advanced' => true,
'accessControl' => true,
'rssContent' => true,
'generalSitemap' => true,
'generalSitemapSettings' => true,
'imageSitemap' => true,
'videoSitemap' => true,
'newsSitemap' => true,
'rssSitemap' => true,
'rssSitemapSettings' => true,
'rssAdditionalPages' => true,
'rssAdvancedSettings' => true,
'additionalPages' => true,
'advancedSettings' => true,
'videoSitemapSettings' => true,
'videoAdditionalPages' => true,
'videoAdvancedSettings' => true,
'videoEmbedSettings' => true,
'newsSitemapSettings' => true,
'newsAdditionalPages' => true,
'newsAdvancedSettings' => true,
'newsEmbedSettings' => true,
'socialProfiles' => true,
'facebook' => true,
'facebookHomePageSettings' => true,
'facebookAdvancedSettings' => true,
'twitter' => true,
'twitterHomePageSettings' => true,
'pinterest' => true,
'searchTitleSeparator' => true,
'searchHomePage' => true,
'searchSchema' => true,
'searchMediaAttachments' => true,
'searchAdvanced' => true,
'searchAdvancedCrawlCleanup' => true,
'searchCleanup' => true,
'authorArchives' => true,
'dateArchives' => true,
'searchArchives' => true,
'imageSeo' => true,
'completeSeoChecklist' => true,
'localBusinessInfo' => true,
'localBusinessOpeningHours' => true,
'locationsSettings' => true,
'advancedLocationsSettings' => true,
'localBusinessMapsApiKey' => true,
'localBusinessMapsSettings' => true,
'robotsEditor' => true,
'badBotBlocker' => true,
'databaseTools' => true,
'htaccessEditor' => true,
'databaseToolsLogs' => true,
'systemStatusInfo' => true,
'addNewRedirection' => true,
'redirectSettings' => true,
'debug' => true,
'fullSiteRedirectsRelocate' => true,
'fullSiteRedirectsAliases' => true,
'fullSiteRedirectsCanonical' => true,
'fullSiteRedirectsHttpHeaders' => true,
'htmlSitemap' => true,
'htmlSitemapSettings' => true,
'htmlSitemapAdvancedSettings' => true,
'linkAssistantSettings' => true,
'domainActivations' => true,
'404Settings' => true,
'userProfiles' => true,
'queryArgLogs' => true,
'writingAssistantSettings' => true,
'writingAssistantCta' => true
],
'toggledRadio' => [
'breadcrumbsShowMoreSeparators' => false,
'searchShowMoreSeparators' => false,
'overviewPostType' => 'post',
],
'dismissedAlerts' => [
'searchStatisticsContentRankings' => false,
'searchConsoleNotConnected' => false,
'searchConsoleSitemapErrors' => false
],
'internalTabs' => [
'authorArchives' => 'title-description',
'dateArchives' => 'title-description',
'searchArchives' => 'title-description',
'seoAuditChecklist' => 'all-items'
],
'tablePagination' => [
'networkDomains' => 20,
'redirects' => 20,
'redirectLogs' => 20,
'redirect404Logs' => 20,
'sitemapAdditionalPages' => 20,
'linkAssistantLinksReport' => 20,
'linkAssistantPostsReport' => 20,
'linkAssistantDomainsReport' => 20,
'searchStatisticsSeoStatistics' => 20,
'searchStatisticsKeywordRankings' => 20,
'searchStatisticsContentRankings' => 20,
'searchStatisticsPostDetailKeywords' => 20,
'searchStatisticsKrtKeywords' => 20,
'searchStatisticsKrtGroups' => 20,
'searchStatisticsKrtGroupsTableKeywords' => 10,
'queryArgs' => 20
],
'semrushCountry' => 'US'
];
/**
* The Construct method.
*
* @since 4.0.0
*
* @param string $settings An array of settings.
*/
public function __construct( $settings = '_aioseo_settings' ) {
$this->addDynamicDefaults();
$this->settingsName = $settings;
$dbSettings = get_user_meta( get_current_user_id(), $settings, true );
$this->settings = $dbSettings
? array_replace_recursive( $this->defaults, $dbSettings )
: $this->defaults;
}
/**
* Adds some defaults that are dynamically generated.
*
* @since 4.0.0
*
* @return void
*/
private function addDynamicDefaults() {
$postTypes = aioseo()->helpers->getPublicPostTypes( false, false, true, [ 'include' => [ 'buddypress' ] ] );
foreach ( $postTypes as $postType ) {
$this->defaults['toggledCards'][ $postType['name'] . 'SA' ] = true;
$this->defaults['internalTabs'][ $postType['name'] . 'SA' ] = 'title-description';
}
$taxonomies = aioseo()->helpers->getPublicTaxonomies( false, true );
foreach ( $taxonomies as $taxonomy ) {
$this->defaults['toggledCards'][ $taxonomy['name'] . 'SA' ] = true;
$this->defaults['internalTabs'][ $taxonomy['name'] . 'SA' ] = 'title-description';
}
$postTypes = aioseo()->helpers->getPublicPostTypes( false, true, true, [ 'include' => [ 'buddypress' ] ] );
foreach ( $postTypes as $postType ) {
$this->defaults['toggledCards'][ $postType['name'] . 'ArchiveArchives' ] = true;
$this->defaults['internalTabs'][ $postType['name'] . 'ArchiveArchives' ] = 'title-description';
}
// Check any addons for defaults.
$addonsDefaults = array_filter( aioseo()->addons->doAddonFunction( 'vueSettings', 'addDynamicDefaults' ) );
foreach ( $addonsDefaults as $addonDefaults ) {
$this->defaults = array_merge_recursive( $this->defaults, $addonDefaults );
}
}
/**
* Retrieves all settings.
*
* @since 4.0.0
*
* @return array An array of settings.
*/
public function all() {
return array_replace_recursive( $this->defaults, $this->settings );
}
/**
* Retrieve a setting or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @param array $arguments The arguments passed into the method.
* @return mixed The value from the settings or default/null.
*/
public function __call( $name, $arguments = [] ) {
$value = isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : ( ! empty( $arguments[0] ) ? $arguments[0] : $this->getDefault( $name ) );
return $value;
}
/**
* Retrieve a setting or null if missing.
*
* @since 4.0.0
*
* @param string $name The name of the property that is missing on the class.
* @return mixed The value from the settings or default/null.
*/
public function __get( $name ) {
$value = isset( $this->settings[ $name ] ) ? $this->settings[ $name ] : $this->getDefault( $name );
return $value;
}
/**
* Sets the settings value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the settings.
* @param mixed $value The value to set.
* @return void
*/
public function __set( $name, $value ) {
$this->settings[ $name ] = $value;
$this->update();
}
/**
* Checks if an settings is set or returns null if not.
*
* @since 4.0.0
*
* @param string $name The name of the settings.
* @return mixed True or null.
*/
public function __isset( $name ) {
return isset( $this->settings[ $name ] ) ? false === empty( $this->settings[ $name ] ) : null;
}
/**
* Unsets the settings value and saves to the database.
*
* @since 4.0.0
*
* @param string $name The name of the settings.
* @return void
*/
public function __unset( $name ) {
if ( ! isset( $this->settings[ $name ] ) ) {
return;
}
unset( $this->settings[ $name ] );
$this->update();
}
/**
* Gets the default value for a setting.
*
* @since 4.0.0
*
* @param string $name The settings name.
* @return mixed The default value.
*/
public function getDefault( $name ) {
return isset( $this->defaults[ $name ] ) ? $this->defaults[ $name ] : null;
}
/**
* Updates the settings in the database.
*
* @since 4.0.0
*
* @return void
*/
public function update() {
update_user_meta( get_current_user_id(), $this->settingsName, $this->settings );
}
}