| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/Api.tar |
Api.php 0000666 00000001351 15113403455 0005773 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Api as CommonApi;
/**
* Api class for the admin.
*
* @since 4.0.0
*/
class Api extends CommonApi\Api {
/**
* The routes we use in the rest API.
*
* @since 4.0.0
*
* @var array
*/
protected $liteRoutes = [
// phpcs:disable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* Get all the routes to register.
*
* @since 4.0.0
*
* @return array An array of routes.
*/
protected function getRoutes() {
return array_merge_recursive( $this->routes, $this->liteRoutes );
}
} Wizard.php 0000666 00000002124 15113403455 0006521 0 ustar 00 <?php
namespace AIOSEO\Plugin\Lite\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Api as CommonApi;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Wizard extends CommonApi\Wizard {
/**
* Save the wizard information.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveWizard( $request ) {
$response = parent::saveWizard( $request );
$body = $request->get_json_params();
$section = ! empty( $body['section'] ) ? sanitize_text_field( $body['section'] ) : null;
$wizard = ! empty( $body['wizard'] ) ? $body['wizard'] : null;
// Save the smart recommendations section.
if ( 'smartRecommendations' === $section && ! empty( $wizard['smartRecommendations'] ) ) {
$smartRecommendations = $wizard['smartRecommendations'];
if ( isset( $smartRecommendations['usageTracking'] ) ) {
aioseo()->options->advanced->usageTracking = $smartRecommendations['usageTracking'];
}
}
return $response;
}
} Listener.php 0000666 00000016145 15114613222 0007052 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\SearchStatistics\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// phpcs:disable HM.Security.NonceVerification.Recommended
/**
* Class that holds our listeners for the microservice.
*
* @since 4.3.0
* @version 4.6.2 Moved from Pro to Common.
*/
class Listener {
/**
* Class constructor.
*
* @since 4.3.0
*/
public function __construct() {
add_action( 'admin_init', [ $this, 'listenForAuthentication' ] );
add_action( 'admin_init', [ $this, 'listenForReauthentication' ] );
add_action( 'admin_init', [ $this, 'listenForReturningBack' ] );
add_action( 'wp_ajax_nopriv_aioseo_is_installed', [ $this, 'isInstalled' ] );
add_action( 'wp_ajax_nopriv_aioseo_rauthenticate', [ $this, 'reauthenticate' ] );
}
/**
* Listens to the response from the microservice server.
*
* @since 4.3.0
*
* @return void
*/
public function listenForAuthentication() {
if ( empty( $_REQUEST['aioseo-oauth-action'] ) || 'auth' !== $_REQUEST['aioseo-oauth-action'] ) {
return;
}
if (
! aioseo()->access->hasCapability( 'aioseo_search_statistics_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_general_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_setup_wizard' )
) {
return;
}
if ( empty( $_REQUEST['tt'] ) || empty( $_REQUEST['key'] ) || empty( $_REQUEST['token'] ) || empty( $_REQUEST['authedsite'] ) ) {
return;
}
if ( ! aioseo()->searchStatistics->api->trustToken->validate( sanitize_text_field( wp_unslash( $_REQUEST['tt'] ) ) ) ) {
return;
}
$profile = [
'key' => sanitize_text_field( wp_unslash( $_REQUEST['key'] ) ),
'token' => sanitize_text_field( wp_unslash( $_REQUEST['token'] ) ),
'siteurl' => site_url(),
'authedsite' => esc_url_raw( wp_unslash( $this->getAuthenticatedDomain() ) )
];
$success = aioseo()->searchStatistics->api->auth->verify( $profile );
if ( ! $success ) {
return;
}
$this->saveAndRedirect( $profile );
}
/**
* Listens to for the reauthentication response from the microservice.
*
* @since 4.3.0
*
* @return void
*/
public function listenForReauthentication() {
if ( empty( $_REQUEST['aioseo-oauth-action'] ) || 'reauth' !== $_REQUEST['aioseo-oauth-action'] ) {
return;
}
if (
! aioseo()->access->hasCapability( 'aioseo_search_statistics_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_general_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_setup_wizard' )
) {
return;
}
if ( empty( $_REQUEST['tt'] ) || empty( $_REQUEST['authedsite'] ) ) {
return;
}
if ( ! aioseo()->searchStatistics->api->trustToken->validate( sanitize_text_field( wp_unslash( $_REQUEST['tt'] ) ) ) ) {
return;
}
$existingProfile = aioseo()->searchStatistics->api->auth->getProfile( true );
if ( empty( $existingProfile['key'] ) || empty( $existingProfile['token'] ) ) {
return;
}
$profile = [
'key' => $existingProfile['key'],
'token' => $existingProfile['token'],
'siteurl' => site_url(),
'authedsite' => esc_url_raw( wp_unslash( $this->getAuthenticatedDomain() ) )
];
$this->saveAndRedirect( $profile );
}
/**
* Listens for the response from the microservice when the user returns back.
*
* @since 4.6.2
*
* @return void
*/
public function listenForReturningBack() {
if ( empty( $_REQUEST['aioseo-oauth-action'] ) || 'back' !== $_REQUEST['aioseo-oauth-action'] ) {
return;
}
if (
! aioseo()->access->hasCapability( 'aioseo_search_statistics_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_general_settings' ) ||
! aioseo()->access->hasCapability( 'aioseo_setup_wizard' )
) {
return;
}
wp_safe_redirect( $this->getRedirectUrl() );
exit;
}
/**
* Return a success status code indicating that the plugin is installed.
*
* @since 4.3.0
*
* @return void
*/
public function isInstalled() {
wp_send_json_success( [
'version' => aioseo()->version,
'pro' => aioseo()->pro
] );
}
/**
* Validate the trust token and tells the microservice that we can reauthenticate.
*
* @since 4.3.0
*
* @return void
*/
public function reauthenticate() {
foreach ( [ 'key', 'token', 'tt' ] as $arg ) {
if ( empty( $_REQUEST[ $arg ] ) ) {
wp_send_json_error( [
'error' => 'authenticate_missing_arg',
'message' => 'Authentication request missing parameter: ' . $arg,
'version' => aioseo()->version,
'pro' => aioseo()->pro
] );
}
}
$trustToken = ! empty( $_REQUEST['tt'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['tt'] ) ) : '';
if ( ! aioseo()->searchStatistics->api->trustToken->validate( $trustToken ) ) {
wp_send_json_error( [
'error' => 'authenticate_invalid_tt',
'message' => 'Invalid TT sent',
'version' => aioseo()->version,
'pro' => aioseo()->pro
] );
}
// If the trust token is validated, send a success response to trigger the regular auth process.
wp_send_json_success();
}
/**
* Saves the authenticated account, clear the existing data and redirect back to the settings page.
*
* @since 4.3.0
*
* @return void
*/
private function saveAndRedirect( $profile ) {
// Reset the search statistics data.
aioseo()->searchStatistics->reset();
// Save the authenticated profile.
aioseo()->searchStatistics->api->auth->setProfile( $profile );
// Reset dismissed alerts.
$dismissedAlerts = aioseo()->settings->dismissedAlerts;
foreach ( $dismissedAlerts as $key => $alert ) {
if ( in_array( $key, [ 'searchConsoleNotConnected', 'searchConsoleSitemapErrors' ], true ) ) {
$dismissedAlerts[ $key ] = false;
}
}
aioseo()->settings->dismissedAlerts = $dismissedAlerts;
// Maybe verifies the site.
aioseo()->searchStatistics->site->maybeVerify();
// Redirects to the original page.
wp_safe_redirect( $this->getRedirectUrl() );
exit;
}
/**
* Returns the authenticated domain.
*
* @since 4.3.0
*
* @return string The authenticated domain.
*/
private function getAuthenticatedDomain() {
if ( empty( $_REQUEST['authedsite'] ) ) {
return '';
}
$authedSite = sanitize_text_field( wp_unslash( $_REQUEST['authedsite'] ) );
if ( false !== aioseo()->helpers->stringIndex( $authedSite, 'sc-domain:' ) ) {
$authedSite = str_replace( 'sc-domain:', '', $authedSite );
}
return $authedSite;
}
/**
* Gets the redirect URL.
*
* @since 4.6.2
*
* @return string The redirect URL.
*/
private function getRedirectUrl() {
$returnTo = ! empty( $_REQUEST['return-to'] ) ? sanitize_key( $_REQUEST['return-to'] ) : '';
$redirectUrl = 'admin.php?page=aioseo';
switch ( $returnTo ) {
case 'webmaster-tools':
$redirectUrl = 'admin.php?page=aioseo-settings#/webmaster-tools?activetool=googleSearchConsole';
break;
case 'setup-wizard':
$redirectUrl = 'index.php?page=aioseo-setup-wizard#/' . aioseo()->standalone->setupWizard->getNextStage();
break;
case 'search-statistics':
$redirectUrl = 'admin.php?page=aioseo-search-statistics/#search-statistics';
break;
}
return admin_url( $redirectUrl );
}
} TrustToken.php 0000666 00000003001 15114613222 0007372 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\SearchStatistics\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the trust token.
*
* @since 4.3.0
* @version 4.6.2 Moved from Pro to Common.
*/
class TrustToken {
/**
* Returns the trust token from the database or creates a new one & stores it.
*
* @since 4.3.0
*
* @return string The trust token.
*/
public function get() {
$trustToken = aioseo()->internalOptions->internal->searchStatistics->trustToken;
if ( empty( $trustToken ) ) {
$trustToken = $this->generate();
aioseo()->internalOptions->internal->searchStatistics->trustToken = $trustToken;
}
return $trustToken;
}
/**
* Rotates the trust token.
*
* @since 4.3.0
*
* @return void
*/
public function rotate() {
$trustToken = $this->generate();
aioseo()->internalOptions->internal->searchStatistics->trustToken = $trustToken;
}
/**
* Generates a new trust token.
*
* @since 4.3.0
*
* @return string The trust token.
*/
public function generate() {
return hash( 'sha512', wp_generate_password( 128, true, true ) . uniqid( '', true ) );
}
/**
* Verifies whether the passed trust token is valid or not.
*
* @since 4.3.0
*
* @param string $passedTrustToken The trust token to validate.
* @return bool Whether the trust token is valid or not.
*/
public function validate( $passedTrustToken = '' ) {
$trustToken = $this->get();
return hash_equals( $trustToken, $passedTrustToken );
}
} Request.php 0000666 00000022526 15114613222 0006715 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\SearchStatistics\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Constructs requests to our microservice.
*
* @since 4.3.0
* @version 4.6.2 Moved from Pro to Common.
*/
class Request {
/**
* The base API route.
*
* @since 4.3.0
*
* @var string
*/
private $base = '';
/**
* The URL scheme.
*
* @since 4.3.0
*
* @var string
*/
private $scheme = 'https://';
/**
* The current API route.
*
* @since 4.3.0
*
* @var string
*/
private $route = '';
/**
* The full API URL endpoint.
*
* @since 4.3.0
*
* @var string
*/
private $url = '';
/**
* The current API method.
*
* @since 4.3.0
*
* @var string
*/
private $method = '';
/**
* The API token.
*
* @since 4.3.0
*
* @var string
*/
private $token = '';
/**
* The API key.
*
* @since 4.3.0
*
* @var string
*/
private $key = '';
/**
* The API trust token.
*
* @since 4.3.0
*
* @var string
*/
private $tt = '';
/**
* Plugin slug.
*
* @since 4.3.0
*
* @var bool|string
*/
private $plugin = false;
/**
* URL to test connection with.
*
* @since 4.3.0
*
* @var string
*/
private $testurl = '';
/**
* The site URL.
*
* @since 4.3.0
*
* @var string
*/
private $siteurl = '';
/**
* The plugin version.
*
* @since 4.3.0
*
* @var string
*/
private $version = '';
/**
* The site identifier.
*
* @since 4.3.0
*
* @var string
*/
private $sitei = '';
/**
* The request args.
*
* @since 4.3.0
*
* @var array
*/
private $args = [];
/**
* Additional data to append to request body.
*
* @since 4.3.0
*
* @var array
*/
protected $additionalData = [];
/**
* Class constructor.
*
* @since 4.3.0
*
* @param string $route The API route.
* @param array $args List of arguments.
* @param string $method The API method.
*/
public function __construct( $route, $args = [], $method = 'POST' ) {
$this->base = trailingslashit( aioseo()->searchStatistics->api->getApiUrl() ) . trailingslashit( aioseo()->searchStatistics->api->getApiVersion() );
$this->route = trailingslashit( $route );
$this->url = trailingslashit( $this->scheme . $this->base . $this->route );
$this->method = $method;
$this->token = ! empty( $args['token'] ) ? $args['token'] : aioseo()->searchStatistics->api->auth->getToken();
$this->key = ! empty( $args['key'] ) ? $args['key'] : aioseo()->searchStatistics->api->auth->getKey();
$this->tt = ! empty( $args['tt'] ) ? $args['tt'] : '';
$this->args = ! empty( $args ) ? $args : [];
$this->siteurl = site_url();
$this->plugin = 'aioseo-' . strtolower( aioseo()->versionPath );
$this->version = aioseo()->version;
$this->sitei = ! empty( $args['sitei'] ) ? $args['sitei'] : '';
$this->testurl = ! empty( $args['testurl'] ) ? $args['testurl'] : '';
}
/**
* Sends and processes the API request.
*
* @since 4.3.0
*
* @return mixed The response.
*/
public function request() {
// Make sure we're not blocked.
$blocked = $this->isBlocked( $this->url );
if ( is_wp_error( $blocked ) ) {
return new \WP_Error(
'api-error',
sprintf(
'The firewall of the server is blocking outbound calls. Please contact your hosting provider to fix this issue. %s',
$blocked->get_error_message()
)
);
}
// 1. BUILD BODY
$body = [];
if ( ! empty( $this->args ) ) {
foreach ( $this->args as $name => $value ) {
$body[ $name ] = $value;
}
}
foreach ( [ 'sitei', 'siteurl', 'version', 'key', 'token', 'tt' ] as $key ) {
if ( ! empty( $this->{$key} ) ) {
$body[ $key ] = $this->{$key};
}
}
// If this is a plugin API request, add the data.
if ( 'info' === $this->route || 'update' === $this->route ) {
$body['aioseoapi-plugin'] = $this->plugin;
}
// Add in additional data if needed.
if ( ! empty( $this->additionalData ) ) {
$body['aioseoapi-data'] = maybe_serialize( $this->additionalData );
}
if ( 'GET' === $this->method ) {
$body['time'] = time(); // Add a timestamp to avoid caching.
}
$body['timezone'] = gmdate( 'e' );
$body['ip'] = ! empty( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '';
// 2. SET HEADERS
$headers = array_merge( [
'Content-Type' => 'application/json',
'Cache-Control' => 'no-store, no-cache, must-revalidate, max-age=0, post-check=0, pre-check=0',
'Pragma' => 'no-cache',
'Expires' => 0,
'AIOSEOAPI-Referer' => site_url(),
'AIOSEOAPI-Sender' => 'WordPress',
'X-AIOSEO-Key' => aioseo()->internalOptions->internal->siteAnalysis->connectToken,
], aioseo()->helpers->getApiHeaders() );
// 3. COMPILE REQUEST DATA
$data = [
'headers' => $headers,
'body' => wp_json_encode( $body ),
'timeout' => 3000,
'user-agent' => aioseo()->helpers->getApiUserAgent()
];
// 4. EXECUTE REQUEST
if ( 'GET' === $this->method ) {
$queryString = http_build_query( $body, '', '&' );
unset( $data['body'] );
$response = wp_remote_get( esc_url_raw( $this->url ) . '?' . $queryString, $data );
} else {
$response = wp_remote_post( esc_url_raw( $this->url ), $data );
}
// 5. VALIDATE RESPONSE
if ( is_wp_error( $response ) ) {
return $response;
}
$responseCode = wp_remote_retrieve_response_code( $response );
$responseBody = json_decode( wp_remote_retrieve_body( $response ), true );
if ( is_wp_error( $responseBody ) ) {
return false;
}
if ( 200 !== $responseCode ) {
$type = ! empty( $responseBody['type'] ) ? $responseBody['type'] : 'api-error';
if ( empty( $responseCode ) ) {
return new \WP_Error(
$type,
'The API was unreachable.'
);
}
if ( empty( $responseBody ) || ( empty( $responseBody['message'] ) && empty( $responseBody['error'] ) ) ) {
return new \WP_Error(
$type,
sprintf(
'The API returned a <strong>%s</strong> response',
$responseCode
)
);
}
if ( ! empty( $responseBody['message'] ) ) {
return new \WP_Error(
$type,
sprintf(
'The API returned a <strong>%1$d</strong> response with this message: <strong>%2$s</strong>',
$responseCode, stripslashes( $responseBody['message'] )
)
);
}
if ( ! empty( $responseBody['error'] ) ) {
return new \WP_Error(
$type,
sprintf(
'The API returned a <strong>%1$d</strong> response with this message: <strong>%2$s</strong>', $responseCode,
stripslashes( $responseBody['error'] )
)
);
}
}
// Check if the trust token is required.
if (
! empty( $this->tt ) &&
( empty( $responseBody['tt'] ) || ! hash_equals( $this->tt, $responseBody['tt'] ) )
) {
return new \WP_Error( 'validation-error', 'Invalid API request.' );
}
return $responseBody;
}
/**
* Sets additional data for the request.
*
* @since 4.3.0
*
* @param array $data The additional data.
* @return void
*/
public function setAdditionalData( array $data ) {
$this->additionalData = array_merge( $this->additionalData, $data );
}
/**
* Checks if the given URL is blocked for a request.
*
* @since 4.3.0
*
* @param string $url The URL to test against.
* @return bool|\WP_Error False or WP_Error if it is blocked.
*/
private function isBlocked( $url = '' ) {
// The below page is a test HTML page used for firewall/router login detection
// and for image linking purposes in Google Images. We use it to test outbound connections
// It's on Google's main CDN so it loads in most countries in 0.07 seconds or less. Perfect for our
// use case of testing outbound connections.
$testurl = ! empty( $this->testurl ) ? $this->testurl : 'https://www.google.com/blank.html';
if ( defined( 'WP_HTTP_BLOCK_EXTERNAL' ) && WP_HTTP_BLOCK_EXTERNAL ) {
if ( defined( 'WP_ACCESSIBLE_HOSTS' ) ) {
$wpHttp = new \WP_Http();
$onBlacklist = $wpHttp->block_request( $url );
if ( $onBlacklist ) {
return new \WP_Error( 'api-error', 'The API was unreachable because the API url is on the WP HTTP blocklist.' );
} else {
$params = [
'sslverify' => false,
'timeout' => 2,
'user-agent' => aioseo()->helpers->getApiUserAgent(),
'body' => ''
];
$response = wp_remote_get( $testurl, $params );
if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 ) {
return false;
} else {
if ( is_wp_error( $response ) ) {
return $response;
} else {
return new \WP_Error( 'api-error', 'The API was unreachable because the call to Google failed.' );
}
}
}
} else {
return new \WP_Error( 'api-error', 'The API was unreachable because no external hosts are allowed on this site.' );
}
} else {
$params = [
'sslverify' => false,
'timeout' => 2,
'user-agent' => aioseo()->helpers->getApiUserAgent(),
'body' => ''
];
$response = wp_remote_get( $testurl, $params );
if ( ! is_wp_error( $response ) && $response['response']['code'] >= 200 && $response['response']['code'] < 300 ) {
return false;
} else {
if ( is_wp_error( $response ) ) {
return $response;
} else {
return new \WP_Error( 'api-error', 'The API was unreachable because the call to Google failed.' );
}
}
}
}
} Auth.php 0000666 00000010064 15114613222 0006160 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\SearchStatistics\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles the authentication/connection to our microservice.
*
* @since 4.3.0
* @version 4.6.2 Moved from Pro to Common.
*/
class Auth {
/**
* The authenticated profile data.
*
* @since 4.3.0
*
* @var array
*/
private $profile = [];
/**
* The type of authentication.
*
* @since 4.6.2
*
* @var string
*/
public $type = 'lite';
/**
* Class constructor.
*
* @since 4.3.0
*/
public function __construct() {
$this->profile = $this->getProfile();
if ( aioseo()->pro ) {
$this->type = 'pro';
}
}
/**
* Returns the authenticated profile.
*
* @since 4.3.0
*
* @param bool $force Busts the cache and forces an update of the profile data.
* @return array The authenticated profile data.
*/
public function getProfile( $force = false ) {
if ( ! empty( $this->profile ) && ! $force ) {
return $this->profile;
}
$this->profile = aioseo()->internalOptions->internal->searchStatistics->profile;
return $this->profile;
}
/**
* Returns the profile key.
*
* @since 4.3.0
*
* @return string The profile key.
*/
public function getKey() {
return ! empty( $this->profile['key'] ) ? $this->profile['key'] : '';
}
/**
* Returns the profile token.
*
* @since 4.3.0
*
* @return string The profile token.
*/
public function getToken() {
return ! empty( $this->profile['token'] ) ? $this->profile['token'] : '';
}
/**
* Returns the authenticated site.
*
* @since 4.3.0
*
* @return string The authenticated site.
*/
public function getAuthedSite() {
return ! empty( $this->profile['authedsite'] ) ? $this->profile['authedsite'] : '';
}
/**
* Sets the profile data.
*
* @since 4.3.0
*
* @return void
*/
public function setProfile( $data = [] ) {
$this->profile = $data;
aioseo()->internalOptions->internal->searchStatistics->profile = $this->profile;
}
/**
* Deletes the profile data.
*
* @since 4.3.0
*
* @return void
*/
public function deleteProfile() {
$this->setProfile( [] );
}
/**
* Check whether we are connected.
*
* @since 4.3.0
*
* @return bool Whether we are connected or not.
*/
public function isConnected() {
return ! empty( $this->profile['key'] );
}
/**
* Verifies whether the authentication details are valid.
*
* @since 4.3.0
*
* @return bool Whether the data is valid or not.
*/
public function verify( $credentials = [] ) {
$creds = ! empty( $credentials ) ? $credentials : aioseo()->internalOptions->internal->searchStatistics->profile;
if ( empty( $creds['key'] ) ) {
return new \WP_Error( 'validation-error', 'Authentication key is missing.' );
}
$request = new Request( "auth/verify/{$this->type}/", [
'tt' => aioseo()->searchStatistics->api->trustToken->get(),
'key' => $creds['key'],
'token' => $creds['token'],
'testurl' => 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/test/',
] );
$response = $request->request();
aioseo()->searchStatistics->api->trustToken->rotate();
return ! is_wp_error( $response );
}
/**
* Removes all authentication data.
*
* @since 4.3.0
*
* @return bool Whether the authentication data was deleted or not.
*/
public function delete() {
if ( ! $this->isConnected() ) {
return false;
}
$creds = aioseo()->searchStatistics->api->auth->getProfile( true );
if ( empty( $creds['key'] ) ) {
return false;
}
( new Request( "auth/delete/{$this->type}/", [
'tt' => aioseo()->searchStatistics->api->trustToken->get(),
'key' => $creds['key'],
'token' => $creds['token'],
'testurl' => 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/test/',
] ) )->request();
aioseo()->searchStatistics->api->trustToken->rotate();
aioseo()->searchStatistics->api->auth->deleteProfile();
aioseo()->searchStatistics->reset();
// Resets the results for the Google meta tag.
aioseo()->options->webmasterTools->google = '';
return true;
}
} Sitemaps.php 0000666 00000011452 15114625233 0007053 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Sitemaps {
/**
* Delete all static sitemap files.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function deleteStaticFiles() {
require_once ABSPATH . 'wp-admin/includes/file.php';
$files = list_files( get_home_path(), 1 );
if ( ! count( $files ) ) {
return;
}
$isGeneralSitemapStatic = aioseo()->options->sitemap->general->advancedSettings->enable &&
in_array( 'staticSitemap', aioseo()->internalOptions->internal->deprecatedOptions, true ) &&
! aioseo()->options->deprecated->sitemap->general->advancedSettings->dynamic;
$detectedFiles = [];
if ( ! $isGeneralSitemapStatic ) {
foreach ( $files as $filename ) {
if ( preg_match( '#.*sitemap.*#', (string) $filename ) ) {
// We don't want to delete the video sitemap here at all.
$isVideoSitemap = preg_match( '#.*video.*#', (string) $filename ) ? true : false;
if ( ! $isVideoSitemap ) {
$detectedFiles[] = $filename;
}
}
}
}
if ( ! count( $detectedFiles ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No sitemap files found.'
], 400 );
}
$fs = aioseo()->core->fs;
if ( ! $fs->isWpfsValid() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No access to filesystem.'
], 400 );
}
foreach ( $detectedFiles as $file ) {
$fs->fs->delete( $file, false, 'f' );
}
Models\Notification::deleteNotificationByName( 'sitemap-static-files' );
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
/**
* Deactivates conflicting plugins.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function deactivateConflictingPlugins() {
$error = esc_html__( 'Deactivation failed. Please check permissions and try again.', 'all-in-one-seo-pack' );
if ( ! current_user_can( 'install_plugins' ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
aioseo()->conflictingPlugins->deactivateConflictingPlugins( [ 'seo', 'sitemap' ] );
Models\Notification::deleteNotificationByName( 'conflicting-plugins' );
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
/**
* Check whether the slug for the HTML sitemap is not in use.
*
* @since 4.1.3
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function validateHtmlSitemapSlug( $request ) {
$body = $request->get_json_params();
$pageUrl = ! empty( $body['pageUrl'] ) ? sanitize_text_field( $body['pageUrl'] ) : '';
if ( empty( $pageUrl ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No path was provided.'
], 400 );
}
$parsedPageUrl = wp_parse_url( $pageUrl );
if ( empty( $parsedPageUrl['path'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'The given path is invalid.'
], 400 );
}
$isUrl = aioseo()->helpers->isUrl( $pageUrl );
$isInternalUrl = aioseo()->helpers->isInternalUrl( $pageUrl );
if ( $isUrl && ! $isInternalUrl ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'The given URL is not a valid internal URL.'
], 400 );
}
$pathExists = self::pathExists( $parsedPageUrl['path'], false );
return new \WP_REST_Response( [
'exists' => $pathExists
], 200 );
}
/**
* Checks whether the given path is unique or not.
*
* @since 4.1.4
* @version 4.2.6
*
* @param string $path The path.
* @param bool $path Whether the given path is a URL.
* @return boolean Whether the path exists.
*/
private static function pathExists( $path, $isUrl ) {
$path = trim( aioseo()->helpers->excludeHomePath( $path ), '/' );
$url = $isUrl ? $path : trailingslashit( home_url() ) . $path;
$url = user_trailingslashit( $url );
// Let's do another check here, just to be sure that the domain matches.
if ( ! aioseo()->helpers->isInternalUrl( $url ) ) {
return false;
}
$response = wp_safe_remote_head( $url );
$status = wp_remote_retrieve_response_code( $response );
if ( ! $status ) {
// If there is no status code, we might be in a local environment with CURL misconfigured.
// In that case we can still check if a post exists for the path by quering the DB.
$post = aioseo()->helpers->getPostbyPath(
$path,
OBJECT,
aioseo()->helpers->getPublicPostTypes( true )
);
return is_object( $post );
}
return 200 === $status;
}
} Migration.php 0000666 00000003575 15114625233 0007226 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Migration as CommonMigration;
use AIOSEO\Plugin\Common\Models;
/**
* Route class for the API.
*
* @since 4.0.6
*/
class Migration {
/**
* Resets blank title formats and retriggers the post/term meta migration.
*
* @since 4.0.6
*
* @return \WP_REST_Response The response.
*/
public static function fixBlankFormats() {
$oldOptions = ( new CommonMigration\OldOptions() )->oldOptions;
if ( ! $oldOptions ) {
return new \WP_REST_Response( [
'success' => true,
'message' => 'Could not load v3 options.'
], 400 );
}
$postTypes = aioseo()->helpers->getPublicPostTypes( true );
$taxonomies = aioseo()->helpers->getPublicTaxonomies( true );
foreach ( $oldOptions as $k => $v ) {
if ( ! preg_match( '/^aiosp_([a-zA-Z]*)_title_format$/', (string) $k, $match ) || ! empty( $v ) ) {
continue;
}
$objectName = $match[1];
if ( in_array( $objectName, $postTypes, true ) && aioseo()->dynamicOptions->searchAppearance->postTypes->has( $objectName ) ) {
aioseo()->dynamicOptions->searchAppearance->postTypes->$objectName->title = '#post_title #separator_sa #site_title';
continue;
}
if ( in_array( $objectName, $taxonomies, true ) && aioseo()->dynamicOptions->searchAppearance->taxonomies->has( $objectName ) ) {
aioseo()->dynamicOptions->searchAppearance->taxonomies->$objectName->title = '#taxonomy_title #separator_sa #site_title';
}
}
aioseo()->migration->redoMetaMigration();
Models\Notification::deleteNotificationByName( 'v3-migration-title-formats-blank' );
return new \WP_REST_Response( [
'success' => true,
'message' => 'Title formats have been reset; post/term migration has been scheduled.',
'notifications' => Models\Notification::getNotifications()
], 200 );
}
} Tags.php 0000666 00000000604 15114625233 0006161 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Tags {
/**
* Get all Tags.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function getTags() {
return new \WP_REST_Response( aioseo()->tags->all( true ), 200 );
}
} Tools.php 0000666 00000015430 15114625233 0006366 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Tools as CommonTools;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Tools {
/**
* Import contents from a robots.txt url, static file or pasted text.
*
* @since 4.0.0
* @version 4.4.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function importRobotsTxt( $request ) {
$body = $request->get_json_params();
$blogId = ! empty( $body['blogId'] ) ? $body['blogId'] : 0;
$source = ! empty( $body['source'] ) ? $body['source'] : '';
$text = ! empty( $body['text'] ) ? sanitize_textarea_field( $body['text'] ) : '';
$url = ! empty( $body['url'] ) ? sanitize_url( $body['url'], [ 'http', 'https' ] ) : '';
try {
if ( is_multisite() && 'network' !== $blogId ) {
aioseo()->helpers->switchToBlog( $blogId );
}
switch ( $source ) {
case 'url':
aioseo()->robotsTxt->importRobotsTxtFromUrl( $url, $blogId );
break;
case 'text':
aioseo()->robotsTxt->importRobotsTxtFromText( $text, $blogId );
break;
case 'static':
default:
aioseo()->robotsTxt->importPhysicalRobotsTxt( $blogId );
aioseo()->robotsTxt->deletePhysicalRobotsTxt();
$options = aioseo()->options;
if ( 'network' === $blogId ) {
$options = aioseo()->networkOptions;
}
$options->tools->robots->enable = true;
break;
}
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
} catch ( \Exception $e ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $e->getMessage()
], 400 );
}
}
/**
* Delete the static robots.txt file.
*
* @since 4.0.0
* @version 4.4.5
*
* @return \WP_REST_Response The response.
*/
public static function deleteRobotsTxt() {
try {
aioseo()->robotsTxt->deletePhysicalRobotsTxt();
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
} catch ( \Exception $e ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $e->getMessage()
], 400 );
}
}
/**
* Email debug info.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function emailDebugInfo( $request ) {
$body = $request->get_json_params();
$email = ! empty( $body['email'] ) ? $body['email'] : null;
if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'invalid-email-address'
], 400 );
}
require_once ABSPATH . 'wp-admin/includes/update.php';
// Translators: 1 - The plugin name ("All in One SEO"), 2 - The Site URL.
$html = sprintf( __( '%1$s Debug Info from %2$s', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_NAME, aioseo()->helpers->getSiteDomain() ) . "\r\n------------------\r\n\r\n";
$info = CommonTools\SystemStatus::getSystemStatusInfo();
foreach ( $info as $group ) {
if ( empty( $group['results'] ) ) {
continue;
}
$html .= "\r\n\r\n{$group['label']}\r\n";
foreach ( $group['results'] as $data ) {
$html .= "{$data['header']}: {$data['value']}\r\n";
}
}
if ( ! wp_mail(
$email,
// Translators: 1 - The plugin name ("All in One SEO).
sprintf( __( '%1$s Debug Info', 'all-in-one-seo-pack' ), AIOSEO_PLUGIN_NAME ),
$html
) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Unable to send debug email, please check your email send settings and try again.'
], 400 );
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Create a settings backup.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function createBackup( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
aioseo()->backup->create();
return new \WP_REST_Response( [
'success' => true,
'backups' => array_reverse( aioseo()->backup->all() )
], 200 );
}
/**
* Restore a settings backup.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function restoreBackup( $request ) {
$body = $request->get_json_params();
$backup = ! empty( $body['backup'] ) ? (int) $body['backup'] : null;
if ( empty( $backup ) ) {
return new \WP_REST_Response( [
'success' => false,
'backups' => array_reverse( aioseo()->backup->all() )
], 400 );
}
aioseo()->backup->restore( $backup );
return new \WP_REST_Response( [
'success' => true,
'backups' => array_reverse( aioseo()->backup->all() ),
'options' => aioseo()->options->all(),
'internalOptions' => aioseo()->internalOptions->all()
], 200 );
}
/**
* Delete a settings backup.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function deleteBackup( $request ) {
$body = $request->get_json_params();
$backup = ! empty( $body['backup'] ) ? (int) $body['backup'] : null;
if ( empty( $backup ) ) {
return new \WP_REST_Response( [
'success' => false,
'backups' => array_reverse( aioseo()->backup->all() )
], 400 );
}
aioseo()->backup->delete( $backup );
return new \WP_REST_Response( [
'success' => true,
'backups' => array_reverse( aioseo()->backup->all() )
], 200 );
}
/**
* Save the .htaccess file.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveHtaccess( $request ) {
$body = $request->get_json_params();
$htaccess = ! empty( $body['htaccess'] ) ? sanitize_textarea_field( $body['htaccess'] ) : '';
if ( empty( $htaccess ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => __( '.htaccess file is empty.', 'all-in-one-seo-pack' )
], 400 );
}
$htaccess = aioseo()->helpers->decodeHtmlEntities( $htaccess );
$saveHtaccess = (object) aioseo()->htaccess->saveContents( $htaccess );
if ( ! $saveHtaccess->success ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $saveHtaccess->message ? $saveHtaccess->message : __( 'An error occurred while trying to write to the .htaccess file. Please try again later.', 'all-in-one-seo-pack' ),
'reason' => $saveHtaccess->reason
], 400 );
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
} Connect.php 0000666 00000004650 15114625233 0006661 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Connect {
/**
* Get the connect URL.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getConnectUrl( $request ) {
$body = $request->get_json_params();
$key = ! empty( $body['licenseKey'] ) ? sanitize_text_field( $body['licenseKey'] ) : null;
$wizard = ! empty( $body['wizard'] ) ? (bool) $body['wizard'] : false;
$success = true;
$urlData = aioseo()->admin->connect->generateConnectUrl( $key, $wizard ? admin_url( 'index.php?page=aioseo-setup-wizard#/success' ) : null );
$url = '';
$message = '';
if ( ! empty( $urlData['error'] ) ) {
$success = false;
$message = $urlData['error'];
}
$url = $urlData['url'];
return new \WP_REST_Response( [
'success' => $success,
'url' => $url,
'message' => $message,
'popup' => ! isset( $urlData['popup'] ) ? true : $urlData['popup']
], 200 );
}
/**
* Process the connection.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function processConnect( $request ) {
$body = $request->get_json_params();
$wizard = ! empty( $body['wizard'] ) ? sanitize_text_field( $body['wizard'] ) : null;
$success = true;
if ( $wizard ) {
aioseo()->internalOptions->internal->wizard = $wizard;
}
$response = aioseo()->admin->connect->process();
if ( ! empty( $response['error'] ) ) {
$message = $response['error'];
} else {
$message = $response['success'];
}
return new \WP_REST_Response( [
'success' => $success,
'message' => $message
], 200 );
}
/**
* Saves the connect token.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveConnectToken( $request ) {
$body = $request->get_json_params();
$token = ! empty( $body['token'] ) ? sanitize_text_field( $body['token'] ) : null;
$success = true;
$message = 'token-saved';
aioseo()->internalOptions->internal->siteAnalysis->connectToken = $token;
return new \WP_REST_Response( [
'success' => $success,
'message' => $message
], 200 );
}
} Network.php 0000666 00000002547 15114625233 0006724 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Route class for the API.
*
* @since 4.2.5
*/
class Network {
/**
* Save network robots rules.
*
* @since 4.2.5
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveNetworkRobots( $request ) {
$isNetwork = 'network' === $request->get_param( 'siteId' );
$siteId = $isNetwork ? aioseo()->helpers->getNetworkId() : (int) $request->get_param( 'siteId' );
$body = $request->get_json_params();
$rules = ! empty( $body['rules'] ) ? array_map( 'sanitize_text_field', $body['rules'] ) : [];
$enabled = isset( $body['enabled'] ) ? boolval( $body['enabled'] ) : null;
$searchAppearance = ! empty( $body['searchAppearance'] ) ? $body['searchAppearance'] : [];
aioseo()->helpers->switchToBlog( $siteId );
$options = $isNetwork ? aioseo()->networkOptions : aioseo()->options;
$enabled = null === $enabled ? $options->tools->robots->enable : $enabled;
$options->sanitizeAndSave( [
'tools' => [
'robots' => [
'enable' => $enabled,
'rules' => $rules
]
],
'searchAppearance' => $searchAppearance
] );
return new \WP_REST_Response( [
'success' => true
], 200 );
}
} Integrations/WpCode.php 0000666 00000001656 15114625233 0011122 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api\Integrations;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\WpCode as WpCodeIntegration;
/**
* Route class for the API.
*
* @since 4.3.8
*/
class WpCode {
/**
* Load the WPCode Snippets from the library, if available.
*
* @since 4.3.8
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getSnippets( $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
return new \WP_REST_Response( [
'success' => true,
'snippets' => WpCodeIntegration::loadWpCodeSnippets(),
'pluginInstalled' => WpCodeIntegration::isPluginInstalled(),
'pluginActive' => WpCodeIntegration::isPluginActive(),
'pluginNeedsUpdate' => WpCodeIntegration::pluginNeedsUpdate()
], 200 );
}
} Integrations/Semrush.php 0000666 00000004331 15114625233 0011360 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api\Integrations;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Integrations\Semrush as SemrushIntegration;
/**
* Route class for the API.
*
* @since 4.0.16
*/
class Semrush {
/**
* Fetches the additional keyphrases.
*
* @since 4.0.16
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function semrushGetKeyphrases( $request ) {
$body = $request->get_json_params();
$keyphrases = SemrushIntegration::getKeyphrases( $body['keyphrase'], $body['database'] );
if ( false === $keyphrases ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'You may have sent too many requests to Semrush. Please wait a few minutes and try again.'
], 400 );
}
return new \WP_REST_Response( [
'success' => true,
'keyphrases' => $keyphrases
], 200 );
}
/**
* Authenticates with Semrush.
*
* @since 4.0.16
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function semrushAuthenticate( $request ) {
$body = $request->get_json_params();
if ( empty( $body['code'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Missing authorization code.'
], 400 );
}
$success = SemrushIntegration::authenticate( $body['code'] );
if ( ! $success ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Authentication failed.'
], 400 );
}
return new \WP_REST_Response( [
'success' => true,
'semrush' => aioseo()->internalOptions->integrations->semrush->all()
], 200 );
}
/**
* Refreshes the API tokens.
*
* @since 4.0.16
*
* @return \WP_REST_Response The response.
*/
public static function semrushRefresh() {
$success = SemrushIntegration::refreshTokens();
if ( ! $success ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'API tokens could not be refreshed.'
], 400 );
}
return new \WP_REST_Response( [
'success' => true,
'semrush' => aioseo()->internalOptions->integrations->semrush->all()
], 200 );
}
} Plugins.php 0000666 00000010533 15114625233 0006706 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Plugins {
/**
* Installs plugins from vue.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function installPlugins( $request ) {
$error = esc_html__( 'Installation failed. Please check permissions and try again.', 'all-in-one-seo-pack' );
$body = $request->get_json_params();
$plugins = ! empty( $body['plugins'] ) ? $body['plugins'] : [];
$network = ! empty( $body['network'] ) ? $body['network'] : false;
if ( ! is_array( $plugins ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
if ( ! aioseo()->addons->canInstall() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
$failed = [];
$completed = [];
foreach ( $plugins as $plugin ) {
if ( empty( $plugin['plugin'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
$result = aioseo()->addons->installAddon( $plugin['plugin'], $network );
if ( ! $result ) {
$failed[] = $plugin['plugin'];
} else {
$completed[ $plugin['plugin'] ] = $result;
}
}
return new \WP_REST_Response( [
'success' => true,
'completed' => $completed,
'failed' => $failed
], 200 );
}
/**
* Upgrade plugins from vue.
*
* @since 4.1.6
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function upgradePlugins( $request ) {
$error = esc_html__( 'Plugin update failed. Please check permissions and try again.', 'all-in-one-seo-pack' );
$body = $request->get_json_params();
$plugins = ! empty( $body['plugins'] ) ? $body['plugins'] : [];
$network = ! empty( $body['network'] ) ? $body['network'] : false;
if ( ! is_array( $plugins ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
if ( ! aioseo()->addons->canUpdate() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
$failed = [];
$completed = [];
foreach ( $plugins as $plugin ) {
if ( empty( $plugin['plugin'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
$result = aioseo()->addons->upgradeAddon( $plugin['plugin'], $network );
if ( ! $result ) {
$failed[] = $plugin['plugin'];
} else {
$completed[ $plugin['plugin'] ] = aioseo()->addons->getAddon( $plugin['plugin'], true );
}
}
return new \WP_REST_Response( [
'success' => true,
'completed' => $completed,
'failed' => $failed
], 200 );
}
/**
* Deactivates plugins from vue.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function deactivatePlugins( $request ) {
$error = esc_html__( 'Deactivation failed. Please check permissions and try again.', 'all-in-one-seo-pack' );
$body = $request->get_json_params();
$plugins = ! empty( $body['plugins'] ) ? $body['plugins'] : [];
$network = ! empty( $body['network'] ) ? $body['network'] : false;
if ( ! is_array( $plugins ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
if ( ! current_user_can( 'install_plugins' ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
require_once ABSPATH . 'wp-admin/includes/plugin.php';
$failed = [];
$completed = [];
foreach ( $plugins as $plugin ) {
if ( empty( $plugin['plugin'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $error
], 400 );
}
deactivate_plugins( $plugin['plugin'], false, $network );
$stillActive = $network ? is_plugin_active_for_network( $plugin['plugin'] ) : is_plugin_active( $plugin['plugin'] );
if ( $stillActive ) {
$failed[] = $plugin['plugin'];
}
$completed[] = $plugin['plugin'];
}
return new \WP_REST_Response( [
'success' => true,
'completed' => $completed,
'failed' => $failed
], 200 );
}
} User.php 0000666 00000001402 15114625233 0006176 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Handles user related API routes.
*
* @since 4.2.8
*/
class User {
/**
* Get the user image.
*
* @since 4.2.8
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getUserImage( $request ) {
$args = $request->get_params();
if ( empty( $args['userId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No user ID was provided.'
], 400 );
}
$url = get_avatar_url( $args['userId'] );
return new \WP_REST_Response( [
'success' => true,
'url' => is_array( $url ) ? $url[0] : $url,
], 200 );
}
} EmailSummary.php 0000666 00000003027 15114625233 0007672 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Email Summary related REST API endpoint callbacks.
*
* @since 4.7.2
*/
class EmailSummary {
/**
* Sends a summary.
*
* @since 4.7.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function send( $request ) {
try {
$body = $request->get_json_params();
$to = $body['to'] ?? '';
$frequency = $body['frequency'] ?? '';
if ( $to && $frequency ) {
aioseo()->emailReports->summary->run( [
'recipient' => $to,
'frequency' => $frequency,
] );
}
return new \WP_REST_Response( [
'success' => true,
], 200 );
} catch ( \Exception $e ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $e->getMessage()
], 200 );
}
}
/**
* Enable email reports from notification.
*
* @since 4.7.7
*
* @return \WP_REST_Response The response.
*/
public static function enableEmailReports() {
// Update option.
aioseo()->options->advanced->emailSummary->enable = true;
// Remove notification.
$notification = Models\Notification::getNotificationByName( 'email-reports-enable-reminder' );
if ( $notification->exists() ) {
$notification->delete();
}
// Send a success response.
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
} SearchStatistics.php 0000666 00000013703 15114625233 0010547 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\SearchStatistics\Api;
/**
* Route class for the API.
*
* @since 4.3.0
* @version 4.6.2 Moved from Pro to Common.
*/
class SearchStatistics {
/**
* Get the authorize URL.
*
* @since 4.3.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getAuthUrl( $request ) {
$body = $request->get_params();
if ( aioseo()->searchStatistics->api->auth->isConnected() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Cannot authenticate. Please re-authenticate.'
], 200 );
}
$returnTo = ! empty( $body['returnTo'] ) ? sanitize_key( $body['returnTo'] ) : '';
$url = add_query_arg( [
'tt' => aioseo()->searchStatistics->api->trustToken->get(),
'sitei' => aioseo()->searchStatistics->api->getSiteIdentifier(),
'version' => aioseo()->version,
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'siteurl' => site_url(),
'return' => urlencode( admin_url( 'admin.php?page=aioseo&return-to=' . $returnTo ) ),
'testurl' => 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/test/'
], 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/auth/new/' . aioseo()->searchStatistics->api->auth->type . '/' );
$url = apply_filters( 'aioseo_search_statistics_auth_url', $url );
return new \WP_REST_Response( [
'success' => true,
'url' => $url,
], 200 );
}
/**
* Get the reauthorize URL.
*
* @since 4.3.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getReauthUrl( $request ) {
$body = $request->get_params();
if ( ! aioseo()->searchStatistics->api->auth->isConnected() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Cannot re-authenticate. Please authenticate.',
], 200 );
}
$returnTo = ! empty( $body['returnTo'] ) ? sanitize_key( $body['returnTo'] ) : '';
$url = add_query_arg( [
'tt' => aioseo()->searchStatistics->api->trustToken->get(),
'sitei' => aioseo()->searchStatistics->api->getSiteIdentifier(),
'version' => aioseo()->version,
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'siteurl' => site_url(),
'key' => aioseo()->searchStatistics->api->auth->getKey(),
'token' => aioseo()->searchStatistics->api->auth->getToken(),
'return' => urlencode( admin_url( 'admin.php?page=aioseo&return-to=' . $returnTo ) ),
'testurl' => 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/test/'
], 'https://' . aioseo()->searchStatistics->api->getApiUrl() . '/v1/auth/reauth/' . aioseo()->searchStatistics->api->auth->type . '/' );
$url = apply_filters( 'aioseo_search_statistics_reauth_url', $url );
return new \WP_REST_Response( [
'success' => true,
'url' => $url,
], 200 );
}
/**
* Delete the authorization.
*
* @since 4.3.0
*
* @return \WP_REST_Response The response.
*/
public static function deleteAuth() {
if ( ! aioseo()->searchStatistics->api->auth->isConnected() ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Cannot deauthenticate. You are not currently authenticated.'
], 200 );
}
aioseo()->searchStatistics->api->auth->delete();
aioseo()->searchStatistics->cancelActions();
return new \WP_REST_Response( [
'success' => true,
'message' => 'Successfully deauthenticated.'
], 200 );
}
/**
* Deletes a sitemap.
*
* @since 4.6.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function deleteSitemap( $request ) {
$body = $request->get_json_params();
$sitemap = ! empty( $body['sitemap'] ) ? $body['sitemap'] : '';
if ( empty( $sitemap ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No sitemap provided.'
], 200 );
}
$args = [
'sitemap' => $sitemap
];
$api = new Api\Request( 'google-search-console/sitemap/delete/', $args, 'POST' );
$response = $api->request();
if ( is_wp_error( $response ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $response['message']
], 200 );
}
aioseo()->internalOptions->searchStatistics->sitemap->list = $response['data'];
aioseo()->internalOptions->searchStatistics->sitemap->lastFetch = time();
return new \WP_REST_Response( [
'success' => true,
'data' => [
'internalOptions' => aioseo()->internalOptions->searchStatistics->sitemap->all(),
'sitemapsWithErrors' => aioseo()->searchStatistics->sitemap->getSitemapsWithErrors()
]
], 200 );
}
/**
* Ignores a sitemap.
*
* @since 4.6.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function ignoreSitemap( $request ) {
$body = $request->get_json_params();
$sitemap = ! empty( $body['sitemap'] ) ? $body['sitemap'] : '';
if ( empty( $sitemap ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No sitemap provided.'
], 200 );
}
$ignoredSitemaps = aioseo()->internalOptions->searchStatistics->sitemap->ignored;
if ( is_array( $sitemap ) ) {
$ignoredSitemaps = array_merge( $ignoredSitemaps, $sitemap );
} else {
$ignoredSitemaps[] = $sitemap;
}
$ignoredSitemaps = array_unique( $ignoredSitemaps ); // Remove duplicates.
$ignoredSitemaps = array_filter( $ignoredSitemaps ); // Remove empty values.
aioseo()->internalOptions->searchStatistics->sitemap->ignored = $ignoredSitemaps;
return new \WP_REST_Response( [
'success' => true,
'data' => [
'internalOptions' => aioseo()->internalOptions->searchStatistics->sitemap->all(),
'sitemapsWithErrors' => aioseo()->searchStatistics->sitemap->getSitemapsWithErrors()
]
], 200 );
}
} WritingAssistant.php 0000666 00000021163 15114625233 0010603 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* WritingAssistant class for the API.
*
* @since 4.7.4
*/
class WritingAssistant {
/**
* Process the keyword.
*
* @since 4.7.4
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function processKeyword( $request ) {
$body = $request->get_json_params();
$postId = absint( $body['postId'] );
$keywordText = sanitize_text_field( $body['keyword'] );
$country = sanitize_text_field( $body['country'] );
$language = sanitize_text_field( strtolower( $body['language'] ) );
if ( empty( $keywordText ) || empty( $country ) || empty( $language ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => __( 'Missing data to generate a report', 'all-in-one-seo-pack' )
] );
}
$keyword = Models\WritingAssistantKeyword::getKeyword( $keywordText, $country, $language );
$writingAssistantPost = Models\WritingAssistantPost::getPost( $postId );
if ( $keyword->exists() ) {
$writingAssistantPost->attachKeyword( $keyword->id );
// Returning early will let the UI code start polling the keyword.
return new \WP_REST_Response( [
'success' => true,
'progress' => $keyword->progress
], 200 );
}
// Start a new keyword process.
$processResult = aioseo()->writingAssistant->seoBoost->service->processKeyword( $keywordText, $country, $language );
if ( is_wp_error( $processResult ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $processResult->get_error_message()
] );
}
// Store the new keyword.
$keyword->uuid = $processResult['slug'];
$keyword->progress = 0;
$keyword->save();
// Update the writing assistant post with the current keyword.
$writingAssistantPost->attachKeyword( $keyword->id );
return new \WP_REST_Response( [ 'success' => true ], 200 );
}
/**
* Get current keyword for a Post.
*
* @since 4.7.4
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getPostKeyword( $request ) {
$postId = $request->get_param( 'postId' );
if ( empty( $postId ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => __( 'Empty Post ID', 'all-in-one-seo-pack' )
], 404 );
}
$keyword = Models\WritingAssistantPost::getKeyword( $postId );
if ( $keyword && 100 !== $keyword->progress ) {
// Update progress.
$newProgress = aioseo()->writingAssistant->seoBoost->service->getProgressAndResult( $keyword->uuid );
if ( is_wp_error( $newProgress ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $newProgress->get_error_message()
], 200 );
}
if ( 'success' !== $newProgress['status'] ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $newProgress['msg']
], 200 );
}
$keyword->progress = ! empty( $newProgress['report']['progress'] ) ? $newProgress['report']['progress'] : $keyword->progress;
if ( ! empty( $newProgress['report']['keywords'] ) ) {
$keyword->keywords = $newProgress['report']['keywords'];
}
if ( ! empty( $newProgress['report']['competitors'] ) ) {
$keyword->competitors = [
'competitors' => $newProgress['report']['competitors'],
'summary' => $newProgress['report']['competitors_summary']
];
}
$keyword->save();
}
// Return a refreshed keyword here because we need some parsed data.
$keyword = Models\WritingAssistantPost::getKeyword( $postId );
return new \WP_REST_Response( $keyword, 200 );
}
/**
* Get the content analysis for a post.
*
* @since 4.7.4
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getContentAnalysis( $request ) {
$title = $request->get_param( 'title' );
$description = $request->get_param( 'description' );
$content = apply_filters( 'the_content', $request->get_param( 'content' ) );
$postId = $request->get_param( 'postId' );
if ( empty( $content ) || empty( $postId ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => __( 'Empty Content or Post ID', 'all-in-one-seo-pack' )
], 200 );
}
$keyword = Models\WritingAssistantPost::getKeyword( $postId );
if (
! $keyword ||
! $keyword->exists() ||
100 !== $keyword->progress
) {
return new \WP_REST_Response( [
'success' => false,
'error' => __( 'Keyword not found or not ready', 'all-in-one-seo-pack' )
], 200 );
}
$writingAssistantPost = Models\WritingAssistantPost::getPost( $postId );
// Make sure we're not analysing the same content again.
$contentHash = sha1( $content );
if (
! empty( $writingAssistantPost->content_analysis ) &&
$writingAssistantPost->content_analysis_hash === $contentHash
) {
return new \WP_REST_Response( $writingAssistantPost->content_analysis, 200 );
}
// Call SEOBoost service to get the content analysis.
$contentAnalysis = aioseo()->writingAssistant->seoBoost->service->getContentAnalysis( $title, $description, $content, $keyword->uuid );
if ( is_wp_error( $contentAnalysis ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $contentAnalysis->get_error_message()
], 200 );
}
if ( empty( $contentAnalysis['result'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => __( 'Empty response from service', 'all-in-one-seo-pack' )
], 200 );
}
// Update the post with the content analysis.
$writingAssistantPost->content_analysis = $contentAnalysis['result'];
$writingAssistantPost->content_analysis_hash = $contentHash;
$writingAssistantPost->save();
return new \WP_REST_Response( $contentAnalysis['result'], 200 );
}
/**
* Get the user info.
*
* @since 4.7.4
*
* @return \WP_REST_Response The response.
*/
public static function getUserInfo() {
$userInfo = aioseo()->writingAssistant->seoBoost->service->getUserInfo();
if ( is_wp_error( $userInfo ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $userInfo->get_error_message()
], 200 );
}
if ( empty( $userInfo['status'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => __( 'Empty response from service', 'all-in-one-seo-pack' )
], 200 );
}
if ( 'success' !== $userInfo['status'] ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $userInfo['msg']
], 200 );
}
return new \WP_REST_Response( $userInfo, 200 );
}
/**
* Get the user info.
*
* @since 4.7.4
*
* @return \WP_REST_Response The response.
*/
public static function getUserOptions() {
$userOptions = aioseo()->writingAssistant->seoBoost->getUserOptions();
return new \WP_REST_Response( $userOptions, 200 );
}
/**
* Get the report history.
*
* @since 4.7.4
*
* @return \WP_REST_Response The response.
*/
public static function getReportHistory() {
$reportHistory = aioseo()->writingAssistant->seoBoost->getReportHistory();
if ( is_wp_error( $reportHistory ) ) {
return new \WP_REST_Response( [
'success' => false,
'error' => $reportHistory->get_error_message()
], 200 );
}
return new \WP_REST_Response( $reportHistory, 200 );
}
/**
* Disconnect the user.
*
* @since 4.7.4
*
* @return \WP_REST_Response The response.
*/
public static function disconnect() {
aioseo()->writingAssistant->seoBoost->setAccessToken( '' );
return new \WP_REST_Response( [ 'success' => true ], 200 );
}
/**
* Save user options.
*
* @since 4.7.4
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveUserOptions( $request ) {
$body = $request->get_json_params();
$userOptions = [
'country' => $body['country'],
'language' => $body['language'],
];
aioseo()->writingAssistant->seoBoost->setUserOptions( $userOptions );
return new \WP_REST_Response( [ 'success' => true ], 200 );
}
/**
* Set the report progress.
*
* @since 4.7.4
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function setReportProgress( $request ) {
$body = $request->get_json_params();
$keyword = Models\WritingAssistantPost::getKeyword( (int) $body['postId'] );
$keyword->progress = (int) $body['progress'];
$keyword->save();
return new \WP_REST_Response( [ 'success' => true ], 200 );
}
} Settings.php 0000666 00000057350 15114625233 0007075 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
use AIOSEO\Plugin\Common\Migration;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Settings {
/**
* Contents to import.
*
* @since 4.7.2
*
* @var array
*/
public static $importFile = [];
/**
* Update the settings.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function getOptions() {
return new \WP_REST_Response( [
'options' => aioseo()->options->all(),
'settings' => aioseo()->settings->all()
], 200 );
}
/**
* Toggles a card in the settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function toggleCard( $request ) {
$body = $request->get_json_params();
$card = ! empty( $body['card'] ) ? sanitize_text_field( $body['card'] ) : null;
$cards = aioseo()->settings->toggledCards;
if ( array_key_exists( $card, $cards ) ) {
$cards[ $card ] = ! $cards[ $card ];
aioseo()->settings->toggledCards = $cards;
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Toggles a radio in the settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function toggleRadio( $request ) {
$body = $request->get_json_params();
$radio = ! empty( $body['radio'] ) ? sanitize_text_field( $body['radio'] ) : null;
$value = ! empty( $body['value'] ) ? sanitize_text_field( $body['value'] ) : null;
$radios = aioseo()->settings->toggledRadio;
if ( array_key_exists( $radio, $radios ) ) {
$radios[ $radio ] = $value;
aioseo()->settings->toggledRadio = $radios;
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Dismisses an alert.
*
* @since 4.3.6
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function dismissAlert( $request ) {
$body = $request->get_json_params();
$alert = ! empty( $body['alert'] ) ? sanitize_text_field( $body['alert'] ) : null;
$alerts = aioseo()->settings->dismissedAlerts;
if ( array_key_exists( $alert, $alerts ) ) {
$alerts[ $alert ] = true;
aioseo()->settings->dismissedAlerts = $alerts;
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Toggles a table's items per page setting.
*
* @since 4.2.5
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function changeItemsPerPage( $request ) {
$body = $request->get_json_params();
$table = ! empty( $body['table'] ) ? sanitize_text_field( $body['table'] ) : null;
$value = ! empty( $body['value'] ) ? intval( $body['value'] ) : null;
$tables = aioseo()->settings->tablePagination;
if ( array_key_exists( $table, $tables ) ) {
$tables[ $table ] = $value;
aioseo()->settings->tablePagination = $tables;
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Dismisses the upgrade bar.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function hideUpgradeBar() {
aioseo()->settings->showUpgradeBar = false;
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Hides the Setup Wizard CTA.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function hideSetupWizard() {
aioseo()->settings->showSetupWizard = false;
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Save options from the front end.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function saveChanges( $request ) {
$body = $request->get_json_params();
$options = ! empty( $body['options'] ) ? $body['options'] : [];
$dynamicOptions = ! empty( $body['dynamicOptions'] ) ? $body['dynamicOptions'] : [];
$network = ! empty( $body['network'] ) ? (bool) $body['network'] : false;
$networkOptions = ! empty( $body['networkOptions'] ) ? $body['networkOptions'] : [];
// If this is the network admin, reset the options.
if ( $network ) {
aioseo()->networkOptions->sanitizeAndSave( $networkOptions );
} else {
aioseo()->options->sanitizeAndSave( $options );
aioseo()->dynamicOptions->sanitizeAndSave( $dynamicOptions );
}
// Re-initialize notices.
aioseo()->notices->init();
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
/**
* Reset settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function resetSettings( $request ) {
$body = $request->get_json_params();
$settings = ! empty( $body['settings'] ) ? $body['settings'] : [];
$notAllowedOptions = aioseo()->access->getNotAllowedOptions();
foreach ( $settings as $setting ) {
$optionAccess = in_array( $setting, [ 'robots', 'blocker' ], true ) ? 'tools' : $setting;
if ( in_array( $optionAccess, $notAllowedOptions, true ) ) {
continue;
}
switch ( $setting ) {
case 'robots':
aioseo()->options->tools->robots->reset();
aioseo()->options->searchAppearance->advanced->unwantedBots->reset();
aioseo()->options->searchAppearance->advanced->searchCleanup->settings->preventCrawling = false;
break;
default:
if ( 'searchAppearance' === $setting ) {
aioseo()->robotsTxt->resetSearchAppearanceRules();
}
if ( aioseo()->options->has( $setting ) ) {
aioseo()->options->$setting->reset();
}
if ( aioseo()->dynamicOptions->has( $setting ) ) {
aioseo()->dynamicOptions->$setting->reset();
}
}
if ( 'access-control' === $setting ) {
aioseo()->access->addCapabilities();
}
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Import settings from external file.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request.
* @return \WP_REST_Response The response.
*/
public static function importSettings( $request ) {
$file = $request->get_file_params()['file'];
$isJSONFile = 'application/json' === $file['type'];
$isCSVFile = 'text/csv' === $file['type'];
$isOctetFile = 'application/octet-stream' === $file['type'];
if (
empty( $file['tmp_name'] ) ||
empty( $file['type'] ) ||
(
! $isJSONFile &&
! $isCSVFile &&
! $isOctetFile
)
) {
return new \WP_REST_Response( [
'success' => false
], 400 );
}
$contents = aioseo()->core->fs->getContents( $file['tmp_name'] );
if ( empty( $contents ) ) {
return new \WP_REST_Response( [
'success' => false
], 400 );
}
if ( $isJSONFile ) {
self::$importFile = json_decode( $contents, true );
}
if ( $isCSVFile ) {
// Transform the CSV content into the original JSON array.
self::$importFile = self::prepareCsvImport( $contents );
}
// If the file is invalid just return.
if ( empty( self::$importFile ) ) {
return new \WP_REST_Response( [
'success' => false
], 400 );
}
// Import settings.
if ( ! empty( self::$importFile['settings'] ) ) {
self::importSettingsFromFile( self::$importFile['settings'] );
}
// Import posts.
if ( ! empty( self::$importFile['postOptions'] ) ) {
self::importPostsFromFile( self::$importFile['postOptions'] );
}
// Import INI.
if ( $isOctetFile ) {
$response = aioseo()->importExport->importIniData( self::$importFile );
if ( ! $response ) {
return new \WP_REST_Response( [
'success' => false
], 400 );
}
}
return new \WP_REST_Response( [
'success' => true,
'options' => aioseo()->options->all()
], 200 );
}
/**
* Import settings from a file.
*
* @since 4.7.2
*
* @param array $settings The data to import.
*/
private static function importSettingsFromFile( $settings ) {
// Clean up the array removing options the user should not manage.
$notAllowedOptions = aioseo()->access->getNotAllowedOptions();
$settings = array_diff_key( $settings, $notAllowedOptions );
if ( ! empty( $settings['deprecated'] ) ) {
$settings['deprecated'] = array_diff_key( $settings['deprecated'], $notAllowedOptions );
}
// Remove any dynamic options and save them separately since this has been refactored.
$commonDynamic = [
'sitemap',
'searchAppearance',
'breadcrumbs',
'accessControl'
];
foreach ( $commonDynamic as $cd ) {
if ( ! empty( $settings[ $cd ]['dynamic'] ) ) {
$settings['dynamic'][ $cd ] = $settings[ $cd ]['dynamic'];
unset( $settings[ $cd ]['dynamic'] );
}
}
// These options have a very different structure so we'll do them separately.
if ( ! empty( $settings['social']['facebook']['general']['dynamic'] ) ) {
$settings['dynamic']['social']['facebook']['general'] = $settings['social']['facebook']['general']['dynamic'];
unset( $settings['social']['facebook']['general']['dynamic'] );
}
if ( ! empty( $settings['dynamic'] ) ) {
aioseo()->dynamicOptions->sanitizeAndSave( $settings['dynamic'] );
unset( $settings['dynamic'] );
}
if ( ! empty( $settings['tools']['robots']['rules'] ) ) {
$settings['tools']['robots']['rules'] = array_merge( aioseo()->robotsTxt->extractSearchAppearanceRules(), $settings['tools']['robots']['rules'] );
}
aioseo()->options->sanitizeAndSave( $settings );
}
/**
* Import posts from a file.
*
* @since 4.7.2
*
* @param array $postOptions The data to import.
*/
private static function importPostsFromFile( $postOptions ) {
$notAllowedFields = aioseo()->access->getNotAllowedPageFields();
foreach ( $postOptions as $postData ) {
if ( ! empty( $postData['posts'] ) ) {
foreach ( $postData['posts'] as $post ) {
unset( $post['id'] );
// Clean up the array removing fields the user should not manage.
$post = array_diff_key( $post, $notAllowedFields );
$thePost = Models\Post::getPost( $post['post_id'] );
// Remove primary term if the term is not attached to the post anymore.
if ( ! empty( $post['primary_term'] ) && aioseo()->helpers->isJsonString( $post['primary_term'] ) ) {
$primaryTerms = json_decode( $post['primary_term'], true );
foreach ( $primaryTerms as $tax => $termId ) {
$terms = wp_get_post_terms( $post['post_id'], $tax, [
'fields' => 'ids'
] );
if ( is_array( $terms ) && ! in_array( $termId, $terms, true ) ) {
unset( $primaryTerms[ $tax ] );
}
}
$post['primary_term'] = empty( $primaryTerms ) ? null : wp_json_encode( $primaryTerms );
}
// Remove FAQ Block schema if the block is not present in the post anymore.
if ( ! empty( $post['schema'] ) && aioseo()->helpers->isJsonString( $post['schema'] ) ) {
$schemas = json_decode( $post['schema'], true );
foreach ( $schemas['blockGraphs'] as $index => $block ) {
if ( 'aioseo/faq' !== $block['type'] ) {
continue;
}
$postBlocks = parse_blocks( get_the_content( null, false, $post['post_id'] ) );
$postFaqBlock = array_filter( $postBlocks, function( $block ) {
return 'aioseo/faq' === $block['blockName'];
} );
if ( empty( $postFaqBlock ) ) {
unset( $schemas['blockGraphs'][ $index ] );
}
}
$post['schema'] = wp_json_encode( $schemas );
}
$thePost->set( $post );
$thePost->save();
}
}
}
}
/**
* Prepare the content from CSV to the original JSON array to import.
*
* @since 4.7.2
*
* @param string $fileContent The Data to import.
* @return array The content.
*/
public static function prepareCSVImport( $fileContent ) {
$content = [];
$newContent = [
'postOptions' => null
];
$rows = str_getcsv( $fileContent, "\n" );
// Get the first row to check if the file has post_id or term_id.
$header = str_getcsv( $rows[0], ',' );
$header = aioseo()->helpers->sanitizeOption( $header );
// Check if the file has post_id or term_id.
$type = in_array( 'post_id', $header, true ) ? 'posts' : null;
$type = in_array( 'term_id', $header, true ) ? 'terms' : $type;
if ( ! $type ) {
return false;
}
// Remove header row.
unset( $rows[0] );
$jsonFields = [
'keywords',
'keyphrases',
'page_analysis',
'primary_term',
'og_article_tags',
'schema',
'options',
'open_ai',
'videos'
];
foreach ( $rows as $row ) {
$row = str_replace( '\\""', '\\"', $row );
$row = str_getcsv( $row, ',' );
foreach ( $row as $key => $value ) {
$key = aioseo()->helpers->sanitizeOption( $key );
if ( ! empty( $value ) && in_array( $header[ $key ], $jsonFields, true ) && ! aioseo()->helpers->isJsonString( $value ) ) {
continue;
} elseif ( '' === trim( $value ) ) {
$value = null;
}
$content[ $header [ $key ] ] = $value;
}
$newContent['postOptions']['content'][ $type ][] = $content;
}
return $newContent;
}
/**
* Export settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function exportSettings( $request ) {
$body = $request->get_json_params();
$settings = ! empty( $body['settings'] ) ? $body['settings'] : [];
$allSettings = [
'settings' => []
];
if ( empty( $settings ) ) {
return new \WP_REST_Response( [
'success' => false
], 400 );
}
$options = aioseo()->options->noConflict();
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
$notAllowedOptions = aioseo()->access->getNotAllowedOptions();
foreach ( $settings as $setting ) {
$optionAccess = in_array( $setting, [ 'robots', 'blocker' ], true ) ? 'tools' : $setting;
if ( in_array( $optionAccess, $notAllowedOptions, true ) ) {
continue;
}
switch ( $setting ) {
case 'robots':
$allSettings['settings']['tools']['robots'] = $options->tools->robots->all();
// Search Appearance settings that are also found in the robots settings.
if ( empty( $allSettings['settings']['searchAppearance']['advanced'] ) ) {
$allSettings['settings']['searchAppearance']['advanced'] = [
'unwantedBots' => $options->searchAppearance->advanced->unwantedBots->all(),
'searchCleanup' => [
'settings' => [
'preventCrawling' => $options->searchAppearance->advanced->searchCleanup->settings->preventCrawling
]
]
];
}
break;
default:
if ( $options->has( $setting ) ) {
$allSettings['settings'][ $setting ] = $options->$setting->all();
}
// If there are related dynamic settings, let's include them.
if ( $dynamicOptions->has( $setting ) ) {
$allSettings['settings']['dynamic'][ $setting ] = $dynamicOptions->$setting->all();
}
// It there is a related deprecated $setting, include it.
if ( $options->deprecated->has( $setting ) ) {
$allSettings['settings']['deprecated'][ $setting ] = $options->deprecated->$setting->all();
}
break;
}
}
return new \WP_REST_Response( [
'success' => true,
'settings' => $allSettings
], 200 );
}
/**
* Export post data.
*
* @since 4.7.2
*
* @param \WP_REST_Request $request The REST Request.
* @return \WP_REST_Response The response.
*/
public static function exportContent( $request ) {
$body = $request->get_json_params();
$postOptions = $body['postOptions'] ?? [];
$typeFile = $body['typeFile'] ?? false;
$siteId = (int) ( $body['siteId'] ?? get_current_blog_id() );
$contentPostType = null;
$return = true;
try {
aioseo()->helpers->switchToBlog( $siteId );
// Get settings from post types selected.
if ( ! empty( $postOptions ) ) {
$fieldsToExclude = [
'seo_score' => '',
'schema_type' => '',
'schema_type_options' => '',
'images' => '',
'image_scan_date' => '',
'videos' => '',
'video_thumbnail' => '',
'video_scan_date' => '',
'link_scan_date' => '',
'link_suggestions_scan_date' => '',
'local_seo' => '',
'options' => '',
'open_ai' => ''
];
$notAllowed = array_merge( aioseo()->access->getNotAllowedPageFields(), $fieldsToExclude );
$posts = self::getPostTypesData( $postOptions, $notAllowed );
// Generate content to CSV or JSON.
if ( ! empty( $posts ) ) {
// Change the order of keys so the post_title shows up at the beginning.
$data = [];
foreach ( $posts as $p ) {
$item = [
'id' => '',
'post_id' => '',
'post_title' => '',
'title' => ''
];
$p['title'] = aioseo()->helpers->decodeHtmlEntities( $p['title'] );
$p['post_title'] = aioseo()->helpers->decodeHtmlEntities( $p['post_title'] );
$data[] = array_merge( $item, $p );
}
if ( 'csv' === $typeFile ) {
$contentPostType = self::dataToCsv( $data );
}
if ( 'json' === $typeFile ) {
$contentPostType['postOptions']['content']['posts'] = $data;
}
}
}
} catch ( \Throwable $th ) {
$return = false;
}
return new \WP_REST_Response( [
'success' => $return,
'postTypeData' => $contentPostType
], 200 );
}
/**
* Returns the posts of specific post types.
*
* @since 4.7.2
*
* @param array $postOptions The post types to get data from.
* @param array $notAllowedFields An array of fields not allowed to be returned.
* @return array The posts.
*/
private static function getPostTypesData( $postOptions, $notAllowedFields = [] ) {
$posts = aioseo()->core->db->start( 'aioseo_posts as ap' )
->select( 'ap.*, p.post_title' )
->join( 'posts as p', 'ap.post_id = p.ID' )
->whereIn( 'p.post_type', $postOptions )
->orderBy( 'ap.id' )
->run()
->result();
if ( ! empty( $notAllowedFields ) ) {
foreach ( $posts as $key => &$p ) {
$p = array_diff_key( (array) $p, $notAllowedFields );
if ( count( $p ) <= 2 ) {
unset( $posts[ $key ] );
}
}
}
return $posts;
}
/**
* Returns a CSV string.
*
* @since 4.7.2
*
* @param array $data An array of data to transform into a CSV.
* @return string The CSV string.
*/
public static function dataToCsv( $data ) {
// Get the header row.
$csvString = implode( ',', array_keys( (array) $data[0] ) ) . "\r\n";
// Get the content rows.
foreach ( $data as $row ) {
$row = (array) $row;
foreach ( $row as &$value ) {
if ( aioseo()->helpers->isJsonString( $value ) ) {
$value = '"' . str_replace( '"', '""', $value ) . '"';
} elseif ( false !== strpos( (string) $value, ',' ) ) {
$value = '"' . $value . '"';
}
}
$csvString .= implode( ',', $row ) . "\r\n";
}
return $csvString;
}
/**
* Import other plugin settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function importPlugins( $request ) {
$body = $request->get_json_params();
$plugins = ! empty( $body['plugins'] ) ? $body['plugins'] : [];
foreach ( $plugins as $plugin ) {
aioseo()->importExport->startImport( $plugin['plugin'], $plugin['settings'] );
}
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Executes a given administrative task.
*
* @since 4.1.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function doTask( $request ) {
$body = $request->get_json_params();
$action = ! empty( $body['action'] ) ? $body['action'] : '';
$data = ! empty( $body['data'] ) ? $body['data'] : [];
$network = ! empty( $body['network'] ) ? boolval( $body['network'] ) : false;
$siteId = ! empty( $body['siteId'] ) ? intval( $body['siteId'] ) : false;
$siteOrNetwork = empty( $siteId ) ? aioseo()->helpers->getNetworkId() : $siteId; // If we don't have a siteId, we will use the networkId.
// When on network admin page and no siteId, it is supposed to perform on network level.
if ( $network && 'clear-cache' === $action && empty( $siteId ) ) {
aioseo()->core->networkCache->clear();
return new \WP_REST_Response( [
'success' => true
], 200 );
}
// Switch to the right blog before processing any task.
aioseo()->helpers->switchToBlog( $siteOrNetwork );
switch ( $action ) {
// General
case 'clear-cache':
aioseo()->core->cache->clear();
break;
case 'clear-plugin-updates-transient':
delete_site_transient( 'update_plugins' );
break;
case 'readd-capabilities':
aioseo()->access->addCapabilities();
break;
case 'reset-data':
aioseo()->uninstall->dropData( true );
aioseo()->internalOptions->database->installedTables = '';
aioseo()->internalOptions->internal->lastActiveVersion = '4.0.0';
aioseo()->internalOptions->save( true );
aioseo()->updates->addInitialCustomTablesForV4();
break;
// Sitemap
case 'clear-image-data':
aioseo()->sitemap->query->resetImages();
break;
// Migrations
case 'rerun-migrations':
aioseo()->internalOptions->database->installedTables = '';
aioseo()->internalOptions->internal->lastActiveVersion = '4.0.0';
aioseo()->internalOptions->save( true );
break;
case 'rerun-addon-migrations':
aioseo()->internalOptions->database->installedTables = '';
foreach ( $data as $sku ) {
$convertedSku = aioseo()->helpers->dashesToCamelCase( $sku );
if (
function_exists( $convertedSku ) &&
isset( $convertedSku()->internalOptions )
) {
$convertedSku()->internalOptions->internal->lastActiveVersion = '0.0';
}
}
break;
case 'restart-v3-migration':
Migration\Helpers::redoMigration();
break;
// Old Issues
case 'remove-duplicates':
aioseo()->updates->removeDuplicateRecords();
break;
case 'unescape-data':
aioseo()->admin->scheduleUnescapeData();
break;
// Deprecated Options
case 'deprecated-options':
// Check if the user is forcefully wanting to add a deprecated option.
$allDeprecatedOptions = aioseo()->internalOptions->getAllDeprecatedOptions() ?: [];
$enableOptions = array_keys( array_filter( $data ) );
$enabledDeprecated = array_intersect( $allDeprecatedOptions, $enableOptions );
aioseo()->internalOptions->internal->deprecatedOptions = array_values( $enabledDeprecated );
aioseo()->internalOptions->save( true );
break;
case 'aioseo-reset-seoboost-logins':
aioseo()->writingAssistant->seoBoost->resetLogins();
break;
default:
aioseo()->helpers->restoreCurrentBlog();
return new \WP_REST_Response( [
'success' => true,
'error' => 'The given action isn\'t defined.'
], 400 );
}
// Revert back to the current blog after processing to avoid conflict with other actions.
aioseo()->helpers->restoreCurrentBlog();
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Change Sem Rush Focus Keyphrase default country.
*
* @since 4.7.5
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function changeSemrushCountry( $request ) {
$body = $request->get_json_params();
$country = ! empty( $body['value'] ) ? sanitize_text_field( $body['value'] ) : 'US';
aioseo()->settings->semrushCountry = $country;
return new \WP_REST_Response( [
'success' => true
], 200 );
}
} Notifications.php 0000666 00000010563 15114625233 0010101 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Notifications {
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function blogVisibilityReminder() {
return self::reminder( 'blog-visibility' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.5
*
* @return \WP_REST_Response The response.
*/
public static function descriptionFormatReminder() {
return self::reminder( 'description-format' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installMiReminder() {
return self::reminder( 'install-mi' );
}
/**
* Extend the start date of a notice.
*
* @since 4.2.1
*
* @return \WP_REST_Response The response.
*/
public static function installOmReminder() {
return self::reminder( 'install-om' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installAddonsReminder() {
return self::reminder( 'install-addons' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installImageSeoReminder() {
return self::reminder( 'install-aioseo-image-seo' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installLocalBusinessReminder() {
return self::reminder( 'install-aioseo-local-business' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installNewsSitemapReminder() {
return self::reminder( 'install-aioseo-news-sitemap' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function installVideoSitemapReminder() {
return self::reminder( 'install-aioseo-video-sitemap' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function conflictingPluginsReminder() {
return self::reminder( 'conflicting-plugins' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function migrationCustomFieldReminder() {
return self::reminder( 'v3-migration-custom-field' );
}
/**
* Extend the start date of a notice.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function migrationSchemaNumberReminder() {
return self::reminder( 'v3-migration-schema-number' );
}
/**
* This allows us to not repeat code over and over.
*
* @since 4.0.0
*
* @param string $slug The slug of the reminder.
* @return \WP_REST_Response The response.
*/
protected static function reminder( $slug ) {
aioseo()->notices->remindMeLater( $slug );
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
/**
* Dismiss notifications.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function dismissNotifications( $request ) {
$slugs = $request->get_json_params();
$notifications = aioseo()->core->db
->start( 'aioseo_notifications' )
->whereIn( 'slug', $slugs )
->run()
->models( 'AIOSEO\\Plugin\\Common\\Models\\Notification' );
foreach ( $notifications as $notification ) {
$notification->dismissed = 1;
$notification->save();
}
// Dismiss static notifications.
if ( in_array( 'notification-review', $slugs, true ) ) {
update_user_meta( get_current_user_id(), '_aioseo_notification_plugin_review_dismissed', '3' );
}
if ( in_array( 'notification-review-delay', $slugs, true ) ) {
update_user_meta( get_current_user_id(), '_aioseo_notification_plugin_review_dismissed', strtotime( '+1 week' ) );
}
return new \WP_REST_Response( [
'success' => true,
'notifications' => Models\Notification::getNotifications()
], 200 );
}
} Analyze.php 0000666 00000015146 15114625233 0006675 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models\SeoAnalyzerResult;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Analyze {
/**
* Analyzes the site for SEO.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function analyzeSite( $request ) {
$body = $request->get_json_params();
$analyzeUrl = ! empty( $body['url'] ) ? esc_url_raw( urldecode( $body['url'] ) ) : null;
$refreshResults = ! empty( $body['refresh'] ) ? (bool) $body['refresh'] : false;
$analyzeOrHomeUrl = ! empty( $analyzeUrl ) ? $analyzeUrl : home_url();
$responseCode = null === aioseo()->core->cache->get( 'analyze_site_code' ) ? [] : aioseo()->core->cache->get( 'analyze_site_code' );
$responseBody = null === aioseo()->core->cache->get( 'analyze_site_body' ) ? [] : aioseo()->core->cache->get( 'analyze_site_body' );
if (
empty( $responseCode ) ||
empty( $responseCode[ $analyzeOrHomeUrl ] ) ||
empty( $responseBody ) ||
empty( $responseBody[ $analyzeOrHomeUrl ] ) ||
$refreshResults
) {
$token = aioseo()->internalOptions->internal->siteAnalysis->connectToken;
$url = defined( 'AIOSEO_ANALYZE_URL' ) ? AIOSEO_ANALYZE_URL : 'https://analyze.aioseo.com';
$response = aioseo()->helpers->wpRemotePost( $url . '/v3/analyze/', [
'timeout' => 60,
'headers' => [
'X-AIOSEO-Key' => $token,
'Content-Type' => 'application/json'
],
'body' => wp_json_encode( [
'url' => $analyzeOrHomeUrl
] ),
] );
$responseCode[ $analyzeOrHomeUrl ] = wp_remote_retrieve_response_code( $response );
$responseBody[ $analyzeOrHomeUrl ] = json_decode( wp_remote_retrieve_body( $response ), true );
aioseo()->core->cache->update( 'analyze_site_code', $responseCode, 10 * MINUTE_IN_SECONDS );
aioseo()->core->cache->update( 'analyze_site_body', $responseBody, 10 * MINUTE_IN_SECONDS );
}
if ( 200 !== $responseCode[ $analyzeOrHomeUrl ] || empty( $responseBody[ $analyzeOrHomeUrl ]['success'] ) || ! empty( $responseBody[ $analyzeOrHomeUrl ]['error'] ) ) {
if ( ! empty( $responseBody[ $analyzeOrHomeUrl ]['error'] ) && 'invalid-token' === $responseBody[ $analyzeOrHomeUrl ]['error'] ) {
aioseo()->internalOptions->internal->siteAnalysis->reset();
}
return new \WP_REST_Response( [
'success' => false,
'response' => $responseBody[ $analyzeOrHomeUrl ]
], 400 );
}
if ( $analyzeUrl ) {
$results = $responseBody[ $analyzeOrHomeUrl ]['results'];
SeoAnalyzerResult::addResults( [
'results' => $results,
'score' => $responseBody[ $analyzeOrHomeUrl ]['score']
], $analyzeUrl );
$result = SeoAnalyzerResult::getCompetitorsResults();
return new \WP_REST_Response( $result, 200 );
}
$results = $responseBody[ $analyzeOrHomeUrl ]['results'];
SeoAnalyzerResult::addResults( [
'results' => $results,
'score' => $responseBody[ $analyzeOrHomeUrl ]['score']
] );
return new \WP_REST_Response( $responseBody[ $analyzeOrHomeUrl ], 200 );
}
/**
* Deletes the analyzed site for SEO.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function deleteSite( $request ) {
$body = $request->get_json_params();
$analyzeUrl = ! empty( $body['url'] ) ? esc_url_raw( urldecode( $body['url'] ) ) : null;
SeoAnalyzerResult::deleteByUrl( $analyzeUrl );
$competitors = aioseo()->internalOptions->internal->siteAnalysis->competitors;
unset( $competitors[ $analyzeUrl ] );
// Reset the competitors.
aioseo()->internalOptions->internal->siteAnalysis->competitors = $competitors;
return new \WP_REST_Response( $competitors, 200 );
}
/**
* Analyzes the title for SEO.
*
* @since 4.1.2
*
* @param \WP_REST_Request $request The REST Request.
* @return \WP_REST_Response The response.
*/
public static function analyzeHeadline( $request ) {
$body = $request->get_json_params();
$headline = ! empty( $body['headline'] ) ? sanitize_text_field( $body['headline'] ) : '';
$shouldStoreHeadline = ! empty( $body['shouldStoreHeadline'] ) ? rest_sanitize_boolean( $body['shouldStoreHeadline'] ) : false;
if ( empty( $headline ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => __( 'Please enter a valid headline.', 'all-in-one-seo-pack' )
], 400 );
}
$result = aioseo()->standalone->headlineAnalyzer->getResult( $headline );
if ( ! $result['analysed'] ) {
return new \WP_REST_Response( [
'success' => false,
'message' => $result['result']->msg
], 400 );
}
$headlines = aioseo()->internalOptions->internal->headlineAnalysis->headlines;
$headlines = array_reverse( $headlines, true );
// Remove a headline from the list if it already exists.
// This will ensure the new analysis is the first and open/highlighted.
if ( array_key_exists( $headline, $headlines ) ) {
unset( $headlines[ $headline ] );
}
$headlines[ $headline ] = wp_json_encode( $result );
$headlines = array_reverse( $headlines, true );
// Store the headlines with the latest one.
if ( $shouldStoreHeadline ) {
aioseo()->internalOptions->internal->headlineAnalysis->headlines = $headlines;
}
return new \WP_REST_Response( $headlines, 200 );
}
/**
* Deletes the analyzed Headline for SEO.
*
* @since 4.1.6
*
* @param \WP_REST_Request $request The REST Request.
* @return \WP_REST_Response The response.
*/
public static function deleteHeadline( $request ) {
$body = $request->get_json_params();
$headline = sanitize_text_field( $body['headline'] );
$headlines = aioseo()->internalOptions->internal->headlineAnalysis->headlines;
unset( $headlines[ $headline ] );
// Reset the headlines.
aioseo()->internalOptions->internal->headlineAnalysis->headlines = $headlines;
return new \WP_REST_Response( $headlines, 200 );
}
/**
* Get Homepage results.
*
* @since 4.8.3
*
* @return \WP_REST_Response The response.
*/
public static function getHomeResults() {
$results = SeoAnalyzerResult::getResults();
return new \WP_REST_Response( [
'success' => true,
'result' => $results,
], 200 );
}
/**
* Get competitors results.
*
* @since 4.8.3
*
* @return \WP_REST_Response The response.
*/
public static function getCompetitorsResults() {
$results = SeoAnalyzerResult::getCompetitorsResults();
return new \WP_REST_Response( [
'success' => true,
'result' => $results,
], 200 );
}
} Ping.php 0000666 00000000631 15114625233 0006160 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Route class for the API.
*
* @since 4.0.0
*/
class Ping {
/**
* Returns a success if the API is alive.
*
* @since 4.0.0
*
* @return \WP_REST_Response The response.
*/
public static function ping() {
return new \WP_REST_Response( [
'success' => true
], 200 );
}
} PostsTerms.php 0000666 00000034521 15114625233 0007413 0 ustar 00 <?php
namespace AIOSEO\Plugin\Common\Api;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
use AIOSEO\Plugin\Common\Models;
/**
* Route class for the API.
*
* @since 4.0.0
*/
class PostsTerms {
/**
* Searches for posts or terms by ID/name.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function searchForObjects( $request ) {
$body = $request->get_json_params();
if ( empty( $body['query'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No search term was provided.'
], 400 );
}
if ( empty( $body['type'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No type was provided.'
], 400 );
}
$searchQuery = esc_sql( aioseo()->core->db->db->esc_like( $body['query'] ) );
$objects = [];
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( 'posts' === $body['type'] ) {
$postTypes = aioseo()->helpers->getPublicPostTypes( true );
foreach ( $postTypes as $postType ) {
// Check if post type isn't noindexed.
if ( $dynamicOptions->searchAppearance->postTypes->has( $postType ) && ! $dynamicOptions->searchAppearance->postTypes->$postType->show ) {
$postTypes = aioseo()->helpers->unsetValue( $postTypes, $postType );
}
}
$objects = aioseo()->core->db
->start( 'posts' )
->select( 'ID, post_type, post_title, post_name' )
->whereRaw( "( post_title LIKE '%{$searchQuery}%' OR post_name LIKE '%{$searchQuery}%' OR ID = '{$searchQuery}' )" )
->whereIn( 'post_type', $postTypes )
->whereIn( 'post_status', [ 'publish', 'draft', 'future', 'pending' ] )
->orderBy( 'post_title' )
->limit( 10 )
->run()
->result();
} elseif ( 'terms' === $body['type'] ) {
$taxonomies = aioseo()->helpers->getPublicTaxonomies( true );
foreach ( $taxonomies as $taxonomy ) {
// Check if taxonomy isn't noindexed.
if ( $dynamicOptions->searchAppearance->taxonomies->has( $taxonomy ) && ! $dynamicOptions->searchAppearance->taxonomies->$taxonomy->show ) {
$taxonomies = aioseo()->helpers->unsetValue( $taxonomies, $taxonomy );
}
}
$objects = aioseo()->core->db
->start( 'terms as t' )
->select( 't.term_id as term_id, t.slug as slug, t.name as name, tt.taxonomy as taxonomy' )
->join( 'term_taxonomy as tt', 't.term_id = tt.term_id', 'INNER' )
->whereRaw( "( t.name LIKE '%{$searchQuery}%' OR t.slug LIKE '%{$searchQuery}%' OR t.term_id = '{$searchQuery}' )" )
->whereIn( 'tt.taxonomy', $taxonomies )
->orderBy( 't.name' )
->limit( 10 )
->run()
->result();
}
if ( empty( $objects ) ) {
return new \WP_REST_Response( [
'success' => true,
'objects' => []
], 200 );
}
$parsed = [];
foreach ( $objects as $object ) {
if ( 'posts' === $body['type'] ) {
$parsed[] = [
'type' => $object->post_type,
'value' => (int) $object->ID,
'slug' => $object->post_name,
'label' => $object->post_title,
'link' => get_permalink( $object->ID )
];
} elseif ( 'terms' === $body['type'] ) {
$parsed[] = [
'type' => $object->taxonomy,
'value' => (int) $object->term_id,
'slug' => $object->slug,
'label' => $object->name,
'link' => get_term_link( $object->term_id )
];
}
}
return new \WP_REST_Response( [
'success' => true,
'objects' => $parsed
], 200 );
}
/**
* Get post data for fetch requests
*
* @since 4.0.0
* @version 4.8.3 Changes the return value to include only the Vue data.
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getPostData( $request ) {
$args = $request->get_query_params();
if ( empty( $args['postId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID was provided.'
], 400 );
}
return new \WP_REST_Response( [
'success' => true,
'data' => aioseo()->helpers->getVueData( 'post', $args['postId'], $args['integrationSlug'] ?? null )
], 200 );
}
/**
* Get the first attached image for a post.
*
* @since 4.1.8
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function getFirstAttachedImage( $request ) {
$args = $request->get_params();
if ( empty( $args['postId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID was provided.'
], 400 );
}
// Disable the cache.
aioseo()->social->image->useCache = false;
$post = aioseo()->helpers->getPost( $args['postId'] );
$url = aioseo()->social->image->getImage( 'facebook', 'attach', $post );
// Reset the cache property.
aioseo()->social->image->useCache = true;
return new \WP_REST_Response( [
'success' => true,
'url' => is_array( $url ) ? $url[0] : $url,
], 200 );
}
/**
* Returns the posts custom fields.
*
* @since 4.0.6
*
* @param \WP_Post|int $post The post.
* @return string The custom field content.
*/
private static function getAnalysisContent( $post = null ) {
$analysisContent = apply_filters( 'aioseo_analysis_content', aioseo()->helpers->getPostContent( $post ) );
return sanitize_post_field( 'post_content', $analysisContent, $post->ID, 'display' );
}
/**
* Update post settings.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function updatePosts( $request ) {
$body = $request->get_json_params();
$postId = ! empty( $body['id'] ) ? intval( $body['id'] ) : null;
if ( ! $postId ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Post ID is missing.'
], 400 );
}
$body['id'] = $postId;
$body['title'] = ! empty( $body['title'] ) ? sanitize_text_field( $body['title'] ) : null;
$body['description'] = ! empty( $body['description'] ) ? sanitize_text_field( $body['description'] ) : null;
$body['keywords'] = ! empty( $body['keywords'] ) ? aioseo()->helpers->sanitize( $body['keywords'] ) : null;
$body['og_title'] = ! empty( $body['og_title'] ) ? sanitize_text_field( $body['og_title'] ) : null;
$body['og_description'] = ! empty( $body['og_description'] ) ? sanitize_text_field( $body['og_description'] ) : null;
$body['og_article_section'] = ! empty( $body['og_article_section'] ) ? sanitize_text_field( $body['og_article_section'] ) : null;
$body['og_article_tags'] = ! empty( $body['og_article_tags'] ) ? aioseo()->helpers->sanitize( $body['og_article_tags'] ) : null;
$body['twitter_title'] = ! empty( $body['twitter_title'] ) ? sanitize_text_field( $body['twitter_title'] ) : null;
$body['twitter_description'] = ! empty( $body['twitter_description'] ) ? sanitize_text_field( $body['twitter_description'] ) : null;
$error = Models\Post::savePost( $postId, $body );
if ( ! empty( $error ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Failed update query: ' . $error
], 401 );
}
return new \WP_REST_Response( [
'success' => true,
'posts' => $postId
], 200 );
}
/**
* Load post settings from Post screen.
*
* @since 4.5.5
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function loadPostDetailsColumn( $request ) {
$body = $request->get_json_params();
$ids = ! empty( $body['ids'] ) ? (array) $body['ids'] : [];
if ( ! $ids ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Post IDs are missing.'
], 400 );
}
$posts = [];
foreach ( $ids as $postId ) {
$postTitle = get_the_title( $postId );
$headline = ! empty( $postTitle ) ? sanitize_text_field( $postTitle ) : ''; // We need this to achieve consistency for the score when using special characters in titles
$headlineResult = aioseo()->standalone->headlineAnalyzer->getResult( $headline );
$posts[] = [
'id' => $postId,
'titleParsed' => aioseo()->meta->title->getPostTitle( $postId ),
'descriptionParsed' => aioseo()->meta->description->getPostDescription( $postId ),
'headlineScore' => ! empty( $headlineResult['score'] ) ? (int) $headlineResult['score'] : 0,
];
}
return new \WP_REST_Response( [
'success' => true,
'posts' => $posts
], 200 );
}
/**
* Update post settings from Post screen.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function updatePostDetailsColumn( $request ) {
$body = $request->get_json_params();
$postId = ! empty( $body['postId'] ) ? intval( $body['postId'] ) : null;
$isMedia = isset( $body['isMedia'] ) ? true : false;
if ( ! $postId ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Post ID is missing.'
], 400 );
}
$aioseoPost = Models\Post::getPost( $postId );
$aioseoData = json_decode( wp_json_encode( $aioseoPost ), true );
if ( $isMedia ) {
wp_update_post(
[
'ID' => $postId,
'post_title' => sanitize_text_field( $body['imageTitle'] ),
]
);
update_post_meta( $postId, '_wp_attachment_image_alt', sanitize_text_field( $body['imageAltTag'] ) );
}
Models\Post::savePost( $postId, array_replace( $aioseoData, $body ) );
$lastError = aioseo()->core->db->lastError();
if ( ! empty( $lastError ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Failed update query: ' . $lastError
], 401 );
}
return new \WP_REST_Response( [
'success' => true,
'posts' => $postId,
'title' => aioseo()->meta->title->getPostTitle( $postId ),
'description' => aioseo()->meta->description->getPostDescription( $postId )
], 200 );
}
/**
* Update post keyphrases.
*
* @since 4.0.0
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function updatePostKeyphrases( $request ) {
$body = $request->get_json_params();
$postId = ! empty( $body['postId'] ) ? intval( $body['postId'] ) : null;
if ( ! $postId ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Post ID is missing.'
], 400 );
}
$thePost = Models\Post::getPost( $postId );
$thePost->post_id = $postId;
if ( ! empty( $body['keyphrases'] ) ) {
$thePost->keyphrases = wp_json_encode( $body['keyphrases'] );
}
if ( ! empty( $body['page_analysis'] ) ) {
$thePost->page_analysis = wp_json_encode( $body['page_analysis'] );
}
if ( ! empty( $body['seo_score'] ) ) {
$thePost->seo_score = sanitize_text_field( $body['seo_score'] );
}
$thePost->updated = gmdate( 'Y-m-d H:i:s' );
$thePost->save();
$lastError = aioseo()->core->db->lastError();
if ( ! empty( $lastError ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'Failed update query: ' . $lastError
], 401 );
}
return new \WP_REST_Response( [
'success' => true,
'post' => $postId
], 200 );
}
/**
* Disable the Primary Term education.
*
* @since 4.3.6
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function disablePrimaryTermEducation( $request ) {
$args = $request->get_params();
if ( empty( $args['postId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID was provided.'
], 400 );
}
$thePost = Models\Post::getPost( $args['postId'] );
$thePost->options->primaryTerm->productEducationDismissed = true;
$thePost->save();
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Disable the link format education.
*
* @since 4.2.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function disableLinkFormatEducation( $request ) {
$args = $request->get_params();
if ( empty( $args['postId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID was provided.'
], 400 );
}
$thePost = Models\Post::getPost( $args['postId'] );
$thePost->options->linkFormat->linkAssistantDismissed = true;
$thePost->save();
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Increment the internal link count.
*
* @since 4.2.2
*
* @param \WP_REST_Request $request The REST Request
* @return \WP_REST_Response The response.
*/
public static function updateInternalLinkCount( $request ) {
$args = $request->get_params();
$body = $request->get_json_params();
$count = ! empty( $body['count'] ) ? intval( $body['count'] ) : null;
if ( empty( $args['postId'] ) || null === $count ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID or count was provided.'
], 400 );
}
$thePost = Models\Post::getPost( $args['postId'] );
$thePost->options->linkFormat->internalLinkCount = $count;
$thePost->save();
return new \WP_REST_Response( [
'success' => true
], 200 );
}
/**
* Get the processed content by the given raw content.
*
* @since 4.5.2
*
* @param \WP_REST_Request $request The REST Request.
* @return \WP_REST_Response The response.
*/
public static function processContent( $request ) {
$args = $request->get_params();
$body = $request->get_json_params();
if ( empty( $args['postId'] ) ) {
return new \WP_REST_Response( [
'success' => false,
'message' => 'No post ID was provided.'
], 400 );
}
// Check if we can process it using a page builder integration.
$pageBuilder = aioseo()->helpers->getPostPageBuilderName( $args['postId'] );
if ( ! empty( $pageBuilder ) ) {
return new \WP_REST_Response( [
'success' => true,
'content' => aioseo()->standalone->pageBuilderIntegrations[ $pageBuilder ]->processContent( $args['postId'], $body['content'] ),
], 200 );
}
// Check if the content was passed, otherwise get it from the post.
$content = $body['content'] ?? aioseo()->helpers->getPostContent( $args['postId'] );
return new \WP_REST_Response( [
'success' => true,
'content' => apply_filters( 'the_content', $content ),
], 200 );
}
}