| Current Path : /home/x/b/o/xbodynamge/namtation/wp-content/ |
| Current File : /home/x/b/o/xbodynamge/namtation/wp-content/config.tar |
wincher-pkce-provider.php 0000666 00000016002 15112002527 0011462 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use UnexpectedValueException;
use YoastSEO_Vendor\GuzzleHttp\Exception\BadResponseException;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\GenericProvider;
use YoastSEO_Vendor\League\OAuth2\Client\Token\AccessToken;
use YoastSEO_Vendor\League\OAuth2\Client\Token\AccessTokenInterface;
use YoastSEO_Vendor\League\OAuth2\Client\Tool\BearerAuthorizationTrait;
use YoastSEO_Vendor\Psr\Http\Message\RequestInterface;
use YoastSEO_Vendor\Psr\Log\InvalidArgumentException;
/**
* Class Wincher_PKCE_Provider
*
* @codeCoverageIgnore Ignoring as this class is purely a temporary wrapper until https://github.com/thephpleague/oauth2-client/pull/901 is merged.
*
* @phpcs:disable WordPress.NamingConventions.ValidVariableName.PropertyNotSnakeCase -- This class extends an external class.
* @phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- This class extends an external class.
*/
class Wincher_PKCE_Provider extends GenericProvider {
use BearerAuthorizationTrait;
/**
* The method to use.
*
* @var string
*/
protected $pkceMethod = null;
/**
* The PKCE code.
*
* @var string
*/
protected $pkceCode;
/**
* Set the value of the pkceCode parameter.
*
* When using PKCE this should be set before requesting an access token.
*
* @param string $pkce_code The value for the pkceCode.
* @return self
*/
public function setPkceCode( $pkce_code ) {
$this->pkceCode = $pkce_code;
return $this;
}
/**
* Returns the current value of the pkceCode parameter.
*
* This can be accessed by the redirect handler during authorization.
*
* @return string
*/
public function getPkceCode() {
return $this->pkceCode;
}
/**
* Returns a new random string to use as PKCE code_verifier and
* hashed as code_challenge parameters in an authorization flow.
* Must be between 43 and 128 characters long.
*
* @param int $length Length of the random string to be generated.
*
* @return string
*
* @throws \Exception Throws exception if an invalid value is passed to random_bytes.
*/
protected function getRandomPkceCode( $length = 64 ) {
return \substr(
\strtr(
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
\base64_encode( \random_bytes( $length ) ),
'+/',
'-_'
),
0,
$length
);
}
/**
* Returns the current value of the pkceMethod parameter.
*
* @return string|null
*/
protected function getPkceMethod() {
return $this->pkceMethod;
}
/**
* Returns authorization parameters based on provided options.
*
* @param array $options The options to use in the authorization parameters.
*
* @return array The authorization parameters
*
* @throws InvalidArgumentException Throws exception if an invalid PCKE method is passed in the options.
* @throws \Exception When something goes wrong with generating the PKCE code.
*/
protected function getAuthorizationParameters( array $options ) {
if ( empty( $options['state'] ) ) {
$options['state'] = $this->getRandomState();
}
if ( empty( $options['scope'] ) ) {
$options['scope'] = $this->getDefaultScopes();
}
$options += [
'response_type' => 'code',
];
if ( \is_array( $options['scope'] ) ) {
$separator = $this->getScopeSeparator();
$options['scope'] = \implode( $separator, $options['scope'] );
}
// Store the state as it may need to be accessed later on.
$this->state = $options['state'];
$pkce_method = $this->getPkceMethod();
if ( ! empty( $pkce_method ) ) {
$this->pkceCode = $this->getRandomPkceCode();
if ( $pkce_method === 'S256' ) {
$options['code_challenge'] = \trim(
\strtr(
// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
\base64_encode( \hash( 'sha256', $this->pkceCode, true ) ),
'+/',
'-_'
),
'='
);
}
elseif ( $pkce_method === 'plain' ) {
$options['code_challenge'] = $this->pkceCode;
}
else {
throw new InvalidArgumentException( 'Unknown PKCE method "' . $pkce_method . '".' );
}
$options['code_challenge_method'] = $pkce_method;
}
// Business code layer might set a different redirect_uri parameter.
// Depending on the context, leave it as-is.
if ( ! isset( $options['redirect_uri'] ) ) {
$options['redirect_uri'] = $this->redirectUri;
}
$options['client_id'] = $this->clientId;
return $options;
}
/**
* Requests an access token using a specified grant and option set.
*
* @param mixed $grant The grant to request access for.
* @param array $options The options to use with the current request.
*
* @return AccessToken|AccessTokenInterface The access token.
*
* @throws UnexpectedValueException Exception thrown if the provider response contains errors.
*/
public function getAccessToken( $grant, array $options = [] ) {
$grant = $this->verifyGrant( $grant );
$params = [
'client_id' => $this->clientId,
'client_secret' => $this->clientSecret,
'redirect_uri' => $this->redirectUri,
];
if ( ! empty( $this->pkceCode ) ) {
$params['code_verifier'] = $this->pkceCode;
}
$params = $grant->prepareRequestParameters( $params, $options );
$request = $this->getAccessTokenRequest( $params );
$response = $this->getParsedResponse( $request );
if ( \is_array( $response ) === false ) {
throw new UnexpectedValueException(
'Invalid response received from Authorization Server. Expected JSON.'
);
}
$prepared = $this->prepareAccessTokenResponse( $response );
$token = $this->createAccessToken( $prepared, $grant );
return $token;
}
/**
* Returns all options that can be configured.
*
* @return array The configurable options.
*/
protected function getConfigurableOptions() {
return \array_merge(
$this->getRequiredOptions(),
[
'accessTokenMethod',
'accessTokenResourceOwnerId',
'scopeSeparator',
'responseError',
'responseCode',
'responseResourceOwnerId',
'scopes',
'pkceMethod',
]
);
}
/**
* Parses the request response.
*
* @param RequestInterface $request The request interface.
*
* @return array The parsed response.
*
* @throws IdentityProviderException Exception thrown if there is no proper identity provider.
*/
public function getParsedResponse( RequestInterface $request ) {
try {
$response = $this->getResponse( $request );
} catch ( BadResponseException $e ) {
$response = $e->getResponse();
}
$parsed = $this->parseResponse( $response );
$this->checkResponse( $response, $parsed );
// We always expect an array from the API except for on DELETE requests.
// We convert to an array here to prevent problems with array_key_exists on PHP8.
if ( ! \is_array( $parsed ) ) {
$parsed = [ 'data' => [] ];
}
// Add the response code as this is omitted from Winchers API.
if ( ! \array_key_exists( 'status', $parsed ) ) {
$parsed['status'] = $response->getStatusCode();
}
return $parsed;
}
}
semrush-client.php 0000666 00000005163 15112002527 0010223 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use Yoast\WP\SEO\Exceptions\OAuth\Authentication_Failed_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Property_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Token_Exception;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Wrappers\WP_Remote_Handler;
use YoastSEO_Vendor\GuzzleHttp\Client;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\GenericProvider;
/**
* Class SEMrush_Client
*/
class SEMrush_Client extends OAuth_Client {
/**
* The option's key.
*/
const TOKEN_OPTION = 'semrush_tokens';
/**
* SEMrush_Client constructor.
*
* @param Options_Helper $options_helper The Options_Helper instance.
* @param WP_Remote_Handler $wp_remote_handler The request handler.
*
* @throws Empty_Property_Exception Throws when one of the required properties is empty.
*/
public function __construct(
Options_Helper $options_helper,
WP_Remote_Handler $wp_remote_handler
) {
$provider = new GenericProvider(
[
'clientId' => 'yoast',
'clientSecret' => 'YdqNsWwnP4vE54WO1ugThKEjGMxMAHJt',
'redirectUri' => 'https://oauth.semrush.com/oauth2/yoast/success',
'urlAuthorize' => 'https://oauth.semrush.com/oauth2/authorize',
'urlAccessToken' => 'https://oauth.semrush.com/oauth2/access_token',
'urlResourceOwnerDetails' => 'https://oauth.semrush.com/oauth2/resource',
],
[
'httpClient' => new Client( [ 'handler' => $wp_remote_handler ] ),
]
);
parent::__construct(
self::TOKEN_OPTION,
$provider,
$options_helper
);
}
/**
* Performs the specified request.
*
* @codeCoverageIgnore
*
* @param string $method The HTTP method to use.
* @param string $url The URL to send the request to.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
public function do_request( $method, $url, array $options ) {
// Add the access token to the GET parameters as well since this is what
// the SEMRush API expects.
$options = \array_merge_recursive(
$options,
[
'params' => [
'access_token' => $this->get_tokens()->access_token,
],
]
);
return parent::do_request( $method, $url, $options );
}
}
oauth-client.php 0000666 00000021654 15112002527 0007660 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Authentication_Failed_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Property_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Token_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Failed_Storage_Exception;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Values\OAuth\OAuth_Token;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\GenericProvider;
/**
* Class OAuth_Client
*/
abstract class OAuth_Client {
/**
* The option's key.
*
* @var string
*/
protected $token_option = null;
/**
* The provider.
*
* @var Wincher_PKCE_Provider|GenericProvider
*/
protected $provider;
/**
* The options helper.
*
* @var Options_Helper
*/
protected $options_helper;
/**
* The token.
*
* @var OAuth_Token|null
*/
protected $token = null;
/**
* OAuth_Client constructor.
*
* @param string $token_option The option's name to save the token as.
* @param Wincher_PKCE_Provider|GenericProvider $provider The provider.
* @param Options_Helper $options_helper The Options_Helper instance.
*
* @throws Empty_Property_Exception Exception thrown if a token property is empty.
*/
public function __construct(
$token_option,
$provider,
Options_Helper $options_helper
) {
$this->provider = $provider;
$this->token_option = $token_option;
$this->options_helper = $options_helper;
$tokens = $this->options_helper->get( $this->token_option );
if ( ! empty( $tokens ) ) {
$this->token = new OAuth_Token(
$tokens['access_token'],
$tokens['refresh_token'],
$tokens['expires'],
$tokens['has_expired'],
$tokens['created_at'],
isset( $tokens['error_count'] ) ? $tokens['error_count'] : 0
);
}
}
/**
* Requests the access token and refresh token based on the passed code.
*
* @param string $code The code to send.
*
* @return OAuth_Token The requested tokens.
*
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
*/
public function request_tokens( $code ) {
try {
$response = $this->provider
->getAccessToken(
'authorization_code',
[
'code' => $code,
]
);
$token = OAuth_Token::from_response( $response );
return $this->store_token( $token );
} catch ( Exception $exception ) {
throw new Authentication_Failed_Exception( $exception );
}
}
/**
* Performs an authenticated GET request to the desired URL.
*
* @param string $url The URL to send the request to.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
public function get( $url, $options = [] ) {
return $this->do_request( 'GET', $url, $options );
}
/**
* Performs an authenticated POST request to the desired URL.
*
* @param string $url The URL to send the request to.
* @param mixed $body The data to send along in the request's body.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
public function post( $url, $body, $options = [] ) {
$options['body'] = $body;
return $this->do_request( 'POST', $url, $options );
}
/**
* Performs an authenticated DELETE request to the desired URL.
*
* @param string $url The URL to send the request to.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
public function delete( $url, $options = [] ) {
return $this->do_request( 'DELETE', $url, $options );
}
/**
* Determines whether there are valid tokens available.
*
* @return bool Whether there are valid tokens.
*/
public function has_valid_tokens() {
return ! empty( $this->token ) && $this->token->has_expired() === false;
}
/**
* Gets the stored tokens and refreshes them if they've expired.
*
* @return OAuth_Token The stored tokens.
*
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
public function get_tokens() {
if ( empty( $this->token ) ) {
throw new Empty_Token_Exception();
}
if ( $this->token->has_expired() ) {
$this->token = $this->refresh_tokens( $this->token );
}
return $this->token;
}
/**
* Stores the passed token.
*
* @param OAuth_Token $token The token to store.
*
* @return OAuth_Token The stored token.
*
* @throws Failed_Storage_Exception Exception thrown if storing of the token fails.
*/
public function store_token( OAuth_Token $token ) {
$saved = $this->options_helper->set( $this->token_option, $token->to_array() );
if ( $saved === false ) {
throw new Failed_Storage_Exception();
}
return $token;
}
/**
* Clears the stored token from storage.
*
* @return bool The stored token.
*
* @throws Failed_Storage_Exception Exception thrown if clearing of the token fails.
*/
public function clear_token() {
$saved = $this->options_helper->set( $this->token_option, [] );
if ( $saved === false ) {
throw new Failed_Storage_Exception();
}
return true;
}
/**
* Performs the specified request.
*
* @param string $method The HTTP method to use.
* @param string $url The URL to send the request to.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
protected function do_request( $method, $url, array $options ) {
$defaults = [
'headers' => $this->provider->getHeaders( $this->get_tokens()->access_token ),
];
$options = \array_merge_recursive( $defaults, $options );
if ( \array_key_exists( 'params', $options ) ) {
$url .= '?' . \http_build_query( $options['params'] );
unset( $options['params'] );
}
$request = $this->provider
->getAuthenticatedRequest( $method, $url, null, $options );
return $this->provider->getParsedResponse( $request );
}
/**
* Refreshes the outdated tokens.
*
* @param OAuth_Token $tokens The outdated tokens.
*
* @return OAuth_Token The refreshed tokens.
*
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
*/
protected function refresh_tokens( OAuth_Token $tokens ) {
// We do this dance with transients since we need to make sure we don't
// delete valid tokens because of a race condition when two calls are
// made simultaneously to this function and refresh token rotation is
// turned on in the OAuth server. This is not 100% safe, but should at
// least be much better than not having any lock at all.
$lock_name = \sprintf( 'lock:%s', $this->token_option );
$can_lock = \get_transient( $lock_name ) === false;
$has_lock = $can_lock && \set_transient( $lock_name, true, 30 );
try {
$new_tokens = $this->provider->getAccessToken(
'refresh_token',
[
'refresh_token' => $tokens->refresh_token,
]
);
$token_obj = OAuth_Token::from_response( $new_tokens );
return $this->store_token( $token_obj );
} catch ( Exception $exception ) {
// If we tried to refresh but the refresh token is invalid, delete
// the tokens so that we don't try again. Only do this if we got the
// lock at the beginning of the call.
if ( $has_lock && $exception->getMessage() === 'invalid_grant' ) {
try {
// To protect from race conditions, only do this if we've
// seen an error before with the same token.
if ( $tokens->error_count >= 1 ) {
$this->clear_token();
}
else {
$tokens->error_count += 1;
$this->store_token( $tokens );
}
} catch ( Exception $e ) { // phpcs:ignore Generic.CodeAnalysis.EmptyStatement.DetectedCatch
// Pass through.
}
}
throw new Authentication_Failed_Exception( $exception );
} finally {
\delete_transient( $lock_name );
}
}
}
wordproof-app-config.php 0000666 00000001015 15112002527 0011313 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use YoastSEO_Vendor\WordProof\SDK\Config\DefaultAppConfig;
/**
* Class WordProof_App_Config.
*
* @package Yoast\WP\SEO\Config
*/
class Wordproof_App_Config extends DefaultAppConfig {
/**
* Returns the partner.
*
* @return string The partner.
*/
public function getPartner() {
return 'yoast';
}
/**
* Returns if the WordProof Uikit should be loaded from a cdn.
*
* @return bool True or false.
*/
public function getLoadUikitFromCdn() {
return false;
}
}
indexing-reasons.php 0000666 00000002121 15112002527 0010525 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Class Indexing_Reasons. Contains constants that aren't context specific.
*/
class Indexing_Reasons {
/**
* Represents the reason that the indexing process failed and should be tried again.
*/
const REASON_INDEXING_FAILED = 'indexing_failed';
/**
* Represents the reason that the permalink settings are changed.
*/
const REASON_PERMALINK_SETTINGS = 'permalink_settings_changed';
/**
* Represents the reason that the category base is changed.
*/
const REASON_CATEGORY_BASE_PREFIX = 'category_base_changed';
/**
* Represents the reason that the tag base is changed.
*/
const REASON_TAG_BASE_PREFIX = 'tag_base_changed';
/**
* Represents the reason that the home url option is changed.
*/
const REASON_HOME_URL_OPTION = 'home_url_option_changed';
/**
* Represents the reason that a post type has been made public.
*/
const REASON_POST_TYPE_MADE_PUBLIC = 'post_type_made_public';
/**
* Represents the reason that a post type has been made viewable.
*/
const REASON_TAXONOMY_MADE_PUBLIC = 'taxonomy_made_public';
}
wordproof-translations.php 0000666 00000005003 15112002527 0012012 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use YoastSEO_Vendor\WordProof\SDK\Translations\TranslationsInterface;
/**
* Class WordProof_Translations
*
* @package Yoast\WP\SEO\Config
*/
class Wordproof_Translations implements TranslationsInterface {
/**
* Returns no balance notice translation.
*
* @return string The translation.
*/
public function getNoBalanceNotice() {
/* translators: %s expands to WordProof. */
return \sprintf( \__( 'You are out of timestamps. Please upgrade your account by opening the %s settings.', 'wordpress-seo' ), 'WordProof' );
}
/**
* Returns no balance notice translation.
*
* @return string The translation.
*/
public function getTimestampSuccessNotice() {
/* translators: %s expands to WordProof. */
return \sprintf( \__( '%s has successfully timestamped this page.', 'wordpress-seo' ), 'WordProof' );
}
/**
* Returns timestamp failed notice translation.
*
* @return string The translation.
*/
public function getTimestampFailedNotice() {
/* translators: %s expands to WordProof. */
return \sprintf( \__( '%1$s failed to timestamp this page. Please check if you\'re correctly authenticated with %1$s and try to save this page again.', 'wordpress-seo' ), 'WordProof' );
}
/**
* Returns webhook failed notice translation.
*
* @return string The translation.
*/
public function getWebhookFailedNotice() {
/* translators: %s expands to WordProof. */
return \sprintf( \__( 'The timestamp is not retrieved by your site. Please try again or contact %1$s support.', 'wordpress-seo' ), 'WordProof' );
}
/**
* Returns no authentication notice translation.
*
* @return string The translation.
*/
public function getNotAuthenticatedNotice() {
/* translators: %s expands to WordProof. */
return \sprintf( \__( 'The timestamp is not created because you need to authenticate with %s first.', 'wordpress-seo' ), 'WordProof' );
}
/**
* Returns authenticate button text.
*
* @return string The translation.
*/
public function getOpenAuthenticationButtonText() {
return \__( 'Open authentication', 'wordpress-seo' );
}
/**
* Returns open settings button translation.
*
* @return string The translation.
*/
public function getOpenSettingsButtonText() {
return \__( 'Open settings', 'wordpress-seo' );
}
/**
* Returns get contact WordProof Support button translation.
*
* @return string The translation.
*/
public function getContactWordProofSupportButtonText() {
return \__( 'Contact WordProof support', 'wordpress-seo' );
}
}
conflicting-plugins.php 0000666 00000012407 15112002527 0011236 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Conflicting_Plugins class that holds all known conflicting plugins.
*/
class Conflicting_Plugins {
const OPEN_GRAPH_PLUGINS = [
'2-click-socialmedia-buttons/2-click-socialmedia-buttons.php',
// 2 Click Social Media Buttons.
'add-link-to-facebook/add-link-to-facebook.php', // Add Link to Facebook.
'add-meta-tags/add-meta-tags.php', // Add Meta Tags.
'easy-facebook-share-thumbnails/esft.php', // Easy Facebook Share Thumbnail.
'facebook/facebook.php', // Facebook (official plugin).
'facebook-awd/AWD_facebook.php', // Facebook AWD All in one.
'facebook-featured-image-and-open-graph-meta-tags/fb-featured-image.php',
// Facebook Featured Image & OG Meta Tags.
'facebook-meta-tags/facebook-metatags.php', // Facebook Meta Tags.
'wonderm00ns-simple-facebook-open-graph-tags/wonderm00n-open-graph.php',
// Facebook Open Graph Meta Tags for WordPress.
'facebook-revised-open-graph-meta-tag/index.php', // Facebook Revised Open Graph Meta Tag.
'facebook-thumb-fixer/_facebook-thumb-fixer.php', // Facebook Thumb Fixer.
'facebook-and-digg-thumbnail-generator/facebook-and-digg-thumbnail-generator.php',
// Fedmich's Facebook Open Graph Meta.
'network-publisher/networkpub.php', // Network Publisher.
'nextgen-facebook/nextgen-facebook.php', // NextGEN Facebook OG.
'opengraph/opengraph.php', // Open Graph.
'open-graph-protocol-framework/open-graph-protocol-framework.php',
// Open Graph Protocol Framework.
'seo-facebook-comments/seofacebook.php', // SEO Facebook Comments.
'sexybookmarks/sexy-bookmarks.php', // Shareaholic.
'shareaholic/sexy-bookmarks.php', // Shareaholic.
'sharepress/sharepress.php', // SharePress.
'simple-facebook-connect/sfc.php', // Simple Facebook Connect.
'social-discussions/social-discussions.php', // Social Discussions.
'social-sharing-toolkit/social_sharing_toolkit.php', // Social Sharing Toolkit.
'socialize/socialize.php', // Socialize.
'only-tweet-like-share-and-google-1/tweet-like-plusone.php',
// Tweet, Like, Google +1 and Share.
'wordbooker/wordbooker.php', // Wordbooker.
'wpsso/wpsso.php', // WordPress Social Sharing Optimization.
'wp-caregiver/wp-caregiver.php', // WP Caregiver.
'wp-facebook-like-send-open-graph-meta/wp-facebook-like-send-open-graph-meta.php',
// WP Facebook Like Send & Open Graph Meta.
'wp-facebook-open-graph-protocol/wp-facebook-ogp.php', // WP Facebook Open Graph protocol.
'wp-ogp/wp-ogp.php', // WP-OGP.
'zoltonorg-social-plugin/zosp.php', // Zolton.org Social Plugin.
];
const XML_SITEMAPS_PLUGINS = [
'google-sitemap-plugin/google-sitemap-plugin.php',
// Google Sitemap (BestWebSoft).
'xml-sitemaps/xml-sitemaps.php',
// XML Sitemaps (Denis de Bernardy and Mike Koepke).
'bwp-google-xml-sitemaps/bwp-simple-gxs.php',
// Better WordPress Google XML Sitemaps (Khang Minh).
'google-sitemap-generator/sitemap.php',
// Google XML Sitemaps (Arne Brachhold).
'xml-sitemap-feed/xml-sitemap.php',
// XML Sitemap & Google News feeds (RavanH).
'google-monthly-xml-sitemap/monthly-xml-sitemap.php',
// Google Monthly XML Sitemap (Andrea Pernici).
'simple-google-sitemap-xml/simple-google-sitemap-xml.php',
// Simple Google Sitemap XML (iTx Technologies).
'another-simple-xml-sitemap/another-simple-xml-sitemap.php',
// Another Simple XML Sitemap.
'xml-maps/google-sitemap.php',
// Xml Sitemap (Jason Martens).
'google-xml-sitemap-generator-by-anton-dachauer/adachauer-google-xml-sitemap.php',
// Google XML Sitemap Generator by Anton Dachauer (Anton Dachauer).
'wp-xml-sitemap/wp-xml-sitemap.php',
// WP XML Sitemap (Team Vivacity).
'sitemap-generator-for-webmasters/sitemap.php',
// Sitemap Generator for Webmasters (iwebslogtech).
'xml-sitemap-xml-sitemapcouk/xmls.php',
// XML Sitemap - XML-Sitemap.co.uk (Simon Hancox).
'sewn-in-xml-sitemap/sewn-xml-sitemap.php',
// Sewn In XML Sitemap (jcow).
'rps-sitemap-generator/rps-sitemap-generator.php',
// RPS Sitemap Generator (redpixelstudios).
];
const CLOAKING_PLUGINS = [
'rs-head-cleaner/rs-head-cleaner.php',
// RS Head Cleaner Plus https://wordpress.org/plugins/rs-head-cleaner/.
'rs-head-cleaner-lite/rs-head-cleaner-lite.php',
// RS Head Cleaner Lite https://wordpress.org/plugins/rs-head-cleaner-lite/.
];
const SEO_PLUGINS = [
'all-in-one-seo-pack/all_in_one_seo_pack.php', // All in One SEO Pack.
'seo-ultimate/seo-ultimate.php', // SEO Ultimate.
'seo-by-rank-math/rank-math.php', // Rank Math.
];
/**
* Returns the list of all conflicting plugins.
*
* @return array The list of all conflicting plugins.
*/
public static function all_plugins() {
return \array_merge(
self::OPEN_GRAPH_PLUGINS,
self::XML_SITEMAPS_PLUGINS,
self::CLOAKING_PLUGINS,
self::SEO_PLUGINS
);
}
}
migration-status.php 0000666 00000012220 15112002527 0010563 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Migration_Status class.
*
* Used to validate whether or not migrations have been run and whether or not they should be run again.
*/
class Migration_Status {
/**
* The migration option key.
*
* @var string
*/
const MIGRATION_OPTION_KEY = 'yoast_migrations_';
/**
* The migration options.
*
* @var array
*/
protected $migration_options = [];
/**
* Checks if a given migration should be run.
*
* @param string $name The name of the migration.
* @param string $version The current version.
*
* @return bool Whether or not the migration should be run.
*/
public function should_run_migration( $name, $version = \WPSEO_VERSION ) {
$migration_status = $this->get_migration_status( $name );
// Check if we've attempted to run this migration in the past 10 minutes. If so, it may still be running.
if ( \array_key_exists( 'lock', $migration_status ) ) {
$timestamp = \strtotime( '-10 minutes' );
return $timestamp > $migration_status['lock'];
}
// Is the migration version less than the current version.
return \version_compare( $migration_status['version'], $version, '<' );
}
/**
* Checks whether or not the given migration is at least the given version, defaults to checking for the latest version.
*
* @param string $name The name of the migration.
* @param string $version The version to check, defaults to the latest version.
*
* @return bool Whether or not the requested migration is at least the requested version.
*/
public function is_version( $name, $version = \WPSEO_VERSION ) {
$migration_status = $this->get_migration_status( $name );
return \version_compare( $version, $migration_status['version'], '<=' );
}
/**
* Gets the error of a given migration if it exists.
*
* @param string $name The name of the migration.
*
* @return bool|array False if there is no error, otherwise the error.
*/
public function get_error( $name ) {
$migration_status = $this->get_migration_status( $name );
if ( ! isset( $migration_status['error'] ) ) {
return false;
}
return $migration_status['error'];
}
/**
* Sets an error for the migration.
*
* @param string $name The name of the migration.
* @param string $message Message explaining the reason for the error.
* @param string $version The current version.
*
* @return void
*/
public function set_error( $name, $message, $version = \WPSEO_VERSION ) {
$migration_status = $this->get_migration_status( $name );
$migration_status['error'] = [
'time' => \strtotime( 'now' ),
'version' => $version,
'message' => $message,
];
$this->set_migration_status( $name, $migration_status );
}
/**
* Updates the migration version to the latest version.
*
* @param string $name The name of the migration.
* @param string $version The current version.
*
* @return void
*/
public function set_success( $name, $version = \WPSEO_VERSION ) {
$migration_status = $this->get_migration_status( $name );
unset( $migration_status['lock'] );
unset( $migration_status['error'] );
$migration_status['version'] = $version;
$this->set_migration_status( $name, $migration_status );
}
/**
* Locks the migration status.
*
* @param string $name The name of the migration.
*
* @return bool Whether or not the migration was succesfully locked.
*/
public function lock_migration( $name ) {
$migration_status = $this->get_migration_status( $name );
$migration_status['lock'] = \strtotime( 'now' );
return $this->set_migration_status( $name, $migration_status );
}
/**
* Retrieves the migration option.
*
* @param string $name The name of the migration.
*
* @return bool|array The status of the migration, false if no status exists.
*/
protected function get_migration_status( $name ) {
$current_blog_id = \get_current_blog_id();
if ( ! isset( $this->migration_options[ $current_blog_id ][ $name ] ) ) {
$migration_status = \get_option( self::MIGRATION_OPTION_KEY . $name );
if ( ! \is_array( $migration_status ) || ! isset( $migration_status['version'] ) ) {
$migration_status = [ 'version' => '0.0' ];
}
if ( ! isset( $this->migration_options[ $current_blog_id ] ) ) {
$this->migration_options[ $current_blog_id ] = [];
}
$this->migration_options[ $current_blog_id ][ $name ] = $migration_status;
}
return $this->migration_options[ $current_blog_id ][ $name ];
}
/**
* Retrieves the migration option.
*
* @param string $name The name of the migration.
* @param array $migration_status The migration status.
*
* @return bool True if the status was succesfully updated, false otherwise.
*/
protected function set_migration_status( $name, $migration_status ) {
if ( ! \is_array( $migration_status ) || ! isset( $migration_status['version'] ) ) {
return false;
}
$current_blog_id = \get_current_blog_id();
if ( ! isset( $this->migration_options[ $current_blog_id ] ) ) {
$this->migration_options[ $current_blog_id ] = [];
}
$this->migration_options[ $current_blog_id ][ $name ] = $migration_status;
return \update_option( self::MIGRATION_OPTION_KEY . $name, $migration_status );
}
}
badge-group-names.php 0000666 00000002753 15112002527 0010560 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Class Badge_Group_Names.
*
* This class defines groups for "new" badges, with the version in which those groups are no longer considered
* to be "new".
*/
class Badge_Group_Names {
const GROUP_GLOBAL_TEMPLATES = 'global-templates';
/**
* Constant describing when certain groups of new badges will no longer be shown.
*/
const GROUP_NAMES = [
self::GROUP_GLOBAL_TEMPLATES => '16.7-beta0',
];
/**
* The current plugin version.
*
* @var string
*/
protected $version;
/**
* Badge_Group_Names constructor.
*
* @param string|null $version Optional: the current plugin version.
*/
public function __construct( $version = null ) {
if ( ! $version ) {
$version = \WPSEO_VERSION;
}
$this->version = $version;
}
/**
* Check whether a group of badges is still eligible for a "new" badge.
*
* @param string $group One of the GROUP_* constants.
* @param string|null $current_version The current version of the plugin that's being checked.
*
* @return bool Whether a group of badges is still eligible for a "new" badge.
*/
public function is_still_eligible_for_new_badge( $group, $current_version = null ) {
if ( ! \array_key_exists( $group, $this::GROUP_NAMES ) ) {
return false;
}
$group_version = $this::GROUP_NAMES[ $group ];
if ( \is_null( $current_version ) ) {
$current_version = $this->version;
}
return (bool) \version_compare( $group_version, $current_version, '>' );
}
}
researcher-languages.php 0000666 00000000514 15112002527 0011343 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Holds all languages supported with specific researches for our readability analysis.
*/
class Researcher_Languages {
const SUPPORTED_LANGUAGES = [ 'ar', 'ca', 'de', 'en', 'es', 'fa', 'fr', 'he', 'hu', 'id', 'it', 'nb', 'nl', 'pl', 'pt', 'ru', 'sv', 'tr', 'cs', 'sk', 'el', 'ja' ];
}
wincher-client.php 0000666 00000007513 15112002527 0010175 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
use WPSEO_Utils;
use Yoast\WP\SEO\Exceptions\OAuth\Authentication_Failed_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Property_Exception;
use Yoast\WP\SEO\Exceptions\OAuth\Tokens\Empty_Token_Exception;
use Yoast\WP\SEO\Helpers\Options_Helper;
use Yoast\WP\SEO\Values\OAuth\OAuth_Token;
use Yoast\WP\SEO\Wrappers\WP_Remote_Handler;
use YoastSEO_Vendor\GuzzleHttp\Client;
use YoastSEO_Vendor\League\OAuth2\Client\Provider\Exception\IdentityProviderException;
/**
* Class Wincher_Client
*/
class Wincher_Client extends OAuth_Client {
/**
* The option's key.
*/
const TOKEN_OPTION = 'wincher_tokens';
/**
* Name of the temporary PKCE cookie.
*/
const PKCE_TRANSIENT_NAME = 'yoast_wincher_pkce';
/**
* The WP_Remote_Handler instance.
*
* @var WP_Remote_Handler
*/
protected $wp_remote_handler;
/**
* Wincher_Client constructor.
*
* @param Options_Helper $options_helper The Options_Helper instance.
* @param WP_Remote_Handler $wp_remote_handler The request handler.
*
* @throws Empty_Property_Exception Exception thrown if a token property is empty.
*/
public function __construct(
Options_Helper $options_helper,
WP_Remote_Handler $wp_remote_handler
) {
$provider = new Wincher_PKCE_Provider(
[
'clientId' => 'yoast',
'redirectUri' => 'https://auth.wincher.com/yoast/setup',
'urlAuthorize' => 'https://auth.wincher.com/connect/authorize',
'urlAccessToken' => 'https://auth.wincher.com/connect/token',
'urlResourceOwnerDetails' => 'https://api.wincher.com/beta/user',
'scopes' => [ 'profile', 'account', 'websites:read', 'websites:write', 'offline_access' ],
'scopeSeparator' => ' ',
'pkceMethod' => 'S256',
],
[
'httpClient' => new Client( [ 'handler' => $wp_remote_handler ] ),
]
);
parent::__construct(
self::TOKEN_OPTION,
$provider,
$options_helper
);
}
/**
* Return the authorization URL.
*
* @return string The authentication URL.
*/
public function get_authorization_url() {
$parsed_site_url = \wp_parse_url( \get_site_url() );
$url = $this->provider->getAuthorizationUrl(
[
'state' => WPSEO_Utils::format_json_encode( [ 'domain' => $parsed_site_url['host'] ] ),
]
);
$pkce_code = $this->provider->getPkceCode();
// Store a transient value with the PKCE code that we need in order to
// exchange the returned code for a token after authorization.
\set_transient( self::PKCE_TRANSIENT_NAME, $pkce_code, \DAY_IN_SECONDS );
return $url;
}
/**
* Requests the access token and refresh token based on the passed code.
*
* @param string $code The code to send.
*
* @return OAuth_Token The requested tokens.
*
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
*/
public function request_tokens( $code ) {
$pkce_code = \get_transient( self::PKCE_TRANSIENT_NAME );
if ( $pkce_code ) {
$this->provider->setPkceCode( $pkce_code );
}
return parent::request_tokens( $code );
}
/**
* Performs the specified request.
*
* @codeCoverageIgnore
*
* @param string $method The HTTP method to use.
* @param string $url The URL to send the request to.
* @param array $options The options to pass along to the request.
*
* @return mixed The parsed API response.
*
* @throws IdentityProviderException Exception thrown if there's something wrong with the identifying data.
* @throws Authentication_Failed_Exception Exception thrown if authentication has failed.
* @throws Empty_Token_Exception Exception thrown if the token is empty.
*/
protected function do_request( $method, $url, array $options ) {
$options['headers'] = [ 'Content-Type' => 'application/json' ];
return parent::do_request( $method, $url, $options );
}
}
schema-types.php 0000666 00000010577 15112002527 0007670 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Class Schema_Types.
*/
class Schema_Types {
/**
* Holds the possible schema page types.
*
* Capitalized in this way so the value can be directly used in the schema output.
*
* @var string[]
*/
const PAGE_TYPES = [
'WebPage' => '',
'ItemPage' => '',
'AboutPage' => '',
'FAQPage' => '',
'QAPage' => '',
'ProfilePage' => '',
'ContactPage' => '',
'MedicalWebPage' => '',
'CollectionPage' => '',
'CheckoutPage' => '',
'RealEstateListing' => '',
'SearchResultsPage' => '',
];
/**
* Holds the possible schema article types.
*
* Capitalized in this way so the value can be directly used in the schema output.
*
* @var string[]
*/
const ARTICLE_TYPES = [
'Article' => '',
'BlogPosting' => '',
'SocialMediaPosting' => '',
'NewsArticle' => '',
'AdvertiserContentArticle' => '',
'SatiricalArticle' => '',
'ScholarlyArticle' => '',
'TechArticle' => '',
'Report' => '',
'None' => '',
];
/**
* Gets the page type options.
*
* @return array[] The schema page type options.
*/
public function get_page_type_options() {
return [
[
'name' => \__( 'Web Page', 'wordpress-seo' ),
'value' => 'WebPage',
],
[
'name' => \__( 'Item Page', 'wordpress-seo' ),
'value' => 'ItemPage',
],
[
'name' => \__( 'About Page', 'wordpress-seo' ),
'value' => 'AboutPage',
],
[
'name' => \__( 'FAQ Page', 'wordpress-seo' ),
'value' => 'FAQPage',
],
[
'name' => \__( 'QA Page', 'wordpress-seo' ),
'value' => 'QAPage',
],
[
'name' => \__( 'Profile Page', 'wordpress-seo' ),
'value' => 'ProfilePage',
],
[
'name' => \__( 'Contact Page', 'wordpress-seo' ),
'value' => 'ContactPage',
],
[
'name' => \__( 'Medical Web Page', 'wordpress-seo' ),
'value' => 'MedicalWebPage',
],
[
'name' => \__( 'Collection Page', 'wordpress-seo' ),
'value' => 'CollectionPage',
],
[
'name' => \__( 'Checkout Page', 'wordpress-seo' ),
'value' => 'CheckoutPage',
],
[
'name' => \__( 'Real Estate Listing', 'wordpress-seo' ),
'value' => 'RealEstateListing',
],
[
'name' => \__( 'Search Results Page', 'wordpress-seo' ),
'value' => 'SearchResultsPage',
],
];
}
/**
* Gets the article type options.
*
* @return array[] The schema article type options.
*/
public function get_article_type_options() {
/**
* Filter: 'wpseo_schema_article_types_labels' - Allow developers to filter the available article types and their labels.
*
* Make sure when you filter this to also filter `wpseo_schema_article_types`.
*
* @api array $schema_article_types_labels The available schema article types and their labels.
*/
return \apply_filters(
'wpseo_schema_article_types_labels',
[
[
'name' => \__( 'Article', 'wordpress-seo' ),
'value' => 'Article',
],
[
'name' => \__( 'Blog Post', 'wordpress-seo' ),
'value' => 'BlogPosting',
],
[
'name' => \__( 'Social Media Posting', 'wordpress-seo' ),
'value' => 'SocialMediaPosting',
],
[
'name' => \__( 'News Article', 'wordpress-seo' ),
'value' => 'NewsArticle',
],
[
'name' => \__( 'Advertiser Content Article', 'wordpress-seo' ),
'value' => 'AdvertiserContentArticle',
],
[
'name' => \__( 'Satirical Article', 'wordpress-seo' ),
'value' => 'SatiricalArticle',
],
[
'name' => \__( 'Scholarly Article', 'wordpress-seo' ),
'value' => 'ScholarlyArticle',
],
[
'name' => \__( 'Tech Article', 'wordpress-seo' ),
'value' => 'TechArticle',
],
[
'name' => \__( 'Report', 'wordpress-seo' ),
'value' => 'Report',
],
[
'name' => \__( 'None', 'wordpress-seo' ),
'value' => 'None',
],
]
);
}
/**
* Gets the values of the article type options.
*
* @return array[] The values of the Schema article type options.
*/
public function get_article_type_options_values() {
$article_types = $this->get_article_type_options();
$article_type_values = [];
foreach ( $article_types as $type ) {
$article_type_values[] = $type['value'];
}
return $article_type_values;
}
}
schema-ids.php 0000666 00000002142 15112002527 0007270 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config;
/**
* Class Schema_IDs.
*/
class Schema_IDs {
/**
* Hash used for the Author `@id`.
*/
const AUTHOR_HASH = '#author';
/**
* Hash used for the Author Logo's `@id`.
*/
const AUTHOR_LOGO_HASH = '#authorlogo';
/**
* Hash used for the Breadcrumb's `@id`.
*/
const BREADCRUMB_HASH = '#breadcrumb';
/**
* Hash used for the Person `@id`.
*/
const PERSON_HASH = '#/schema/person/';
/**
* Hash used for the Article `@id`.
*/
const ARTICLE_HASH = '#article';
/**
* Hash used for the Organization `@id`.
*/
const ORGANIZATION_HASH = '#organization';
/**
* Hash used for the Organization `@id`.
*/
const ORGANIZATION_LOGO_HASH = '#/schema/logo/image/';
/**
* Hash used for the logo `@id`.
*/
const PERSON_LOGO_HASH = '#/schema/person/image/';
/**
* Hash used for an Article's primary image `@id`.
*/
const PRIMARY_IMAGE_HASH = '#primaryimage';
/**
* Hash used for the WebPage's `@id`.
*
* @deprecated 19.3
*/
const WEBPAGE_HASH = '';
/**
* Hash used for the Website's `@id`.
*/
const WEBSITE_HASH = '#website';
}
migrations/20200617122511_CreateSEOLinksTable.php 0000666 00000004735 15112002527 0014621 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* CreateSEOLinksTable class.
*/
class CreateSEOLinksTable extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$table_name = $this->get_table_name();
$adapter = $this->get_adapter();
// The table may already have been created by legacy code.
// If not, create it exactly as it was.
if ( ! $adapter->table_exists( $table_name ) ) {
$table = $this->create_table( $table_name, [ 'id' => false ] );
$table->column(
'id',
'biginteger',
[
'primary_key' => true,
'limit' => 20,
'unsigned' => true,
'auto_increment' => true,
]
);
$table->column( 'url', 'string', [ 'limit' => 255 ] );
$table->column(
'post_id',
'biginteger',
[
'limit' => 20,
'unsigned' => true,
]
);
$table->column(
'target_post_id',
'biginteger',
[
'limit' => 20,
'unsigned' => true,
]
);
$table->column( 'type', 'string', [ 'limit' => 8 ] );
$table->finish();
}
if ( ! $adapter->has_index( $table_name, [ 'post_id', 'type' ], [ 'name' => 'link_direction' ] ) ) {
$this->add_index( $table_name, [ 'post_id', 'type' ], [ 'name' => 'link_direction' ] );
}
// Add these columns outside of the initial table creation as these did not exist on the legacy table.
$this->add_column( $table_name, 'indexable_id', 'integer', [ 'unsigned' => true ] );
$this->add_column( $table_name, 'target_indexable_id', 'integer', [ 'unsigned' => true ] );
$this->add_column( $table_name, 'height', 'integer', [ 'unsigned' => true ] );
$this->add_column( $table_name, 'width', 'integer', [ 'unsigned' => true ] );
$this->add_column( $table_name, 'size', 'integer', [ 'unsigned' => true ] );
$this->add_column( $table_name, 'language', 'string', [ 'limit' => 32 ] );
$this->add_column( $table_name, 'region', 'string', [ 'limit' => 32 ] );
$this->add_index( $table_name, [ 'indexable_id', 'type' ], [ 'name' => 'indexable_link_direction' ] );
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$this->drop_table( $this->get_table_name() );
}
/**
* Returns the SEO Links table name.
*
* @return string
*/
private function get_table_name() {
return Model::get_table_name( 'SEO_Links' );
}
}
migrations/20201216141134_ExpandPrimaryTermIDColumnLengths.php 0000666 00000002005 15112002527 0017413 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* ExpandPrimaryTermIDColumnLengths class.
*/
class ExpandPrimaryTermIDColumnLengths extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* The columns to change the column type and length of.
*
* @var string[]
*/
protected static $columns_to_change = [
'post_id',
'term_id',
];
/**
* Migration up.
*
* @return void
*/
public function up() {
foreach ( self::$columns_to_change as $column ) {
$this->change_column(
$this->get_table_name(),
$column,
'biginteger',
[ 'limit' => 20 ]
);
}
}
/**
* Migration down.
*
* @return void
*/
public function down() {
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Primary_Term' );
}
}
migrations/20171228151841_WpYoastPrimaryTerm.php 0000666 00000002775 15112002527 0014717 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Migration for the Primary Term.
*/
class WpYoastPrimaryTerm extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$table_name = $this->get_table_name();
$indexable_table = $this->create_table( $table_name );
$indexable_table->column(
'post_id',
'integer',
[
'unsigned' => true,
'null' => false,
'limit' => 11,
]
);
$indexable_table->column(
'term_id',
'integer',
[
'unsigned' => true,
'null' => false,
'limit' => 11,
]
);
$indexable_table->column(
'taxonomy',
'string',
[
'null' => false,
'limit' => 32,
]
);
// Executes the SQL to create the table.
$indexable_table->finish();
$this->add_index(
$table_name,
[
'post_id',
'taxonomy',
],
[
'name' => 'post_taxonomy',
]
);
$this->add_index(
$table_name,
[
'post_id',
'term_id',
],
[
'name' => 'post_term',
]
);
$this->add_timestamps( $table_name );
}
/**
* Migration down.
*/
public function down() {
$this->drop_table( $this->get_table_name() );
}
/**
* Retrieves the table name to use.
*
* @return string Table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Primary_Term' );
}
}
migrations/20200430075614_AddIndexableObjectIdAndTypeIndex.php 0000666 00000001665 15112002527 0017266 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class AddIndexableObjectIdAndTypeIndex.
*/
class AddIndexableObjectIdAndTypeIndex extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->add_index(
$this->get_table_name(),
[
'object_id',
'object_type',
],
[
'name' => 'object_id_and_type',
]
);
}
/**
* Migration down.
*/
public function down() {
$this->remove_index(
$this->get_table_name(),
[
'object_id',
'object_type',
],
[
'name' => 'object_id_and_type',
]
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200616130143_ReplacePermalinkHashIndex.php 0000666 00000004365 15112002527 0016106 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* ReplacePermalinkHashIndex class.
*/
class ReplacePermalinkHashIndex extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$table_name = $this->get_table_name();
$adapter = $this->get_adapter();
if ( ! $adapter->has_table( $table_name ) ) {
return;
}
$this->change_column(
$table_name,
'permalink_hash',
'string',
[
'null' => true,
'limit' => 40,
]
);
if ( $adapter->has_index( $table_name, [ 'permalink_hash' ], [ 'name' => 'permalink_hash' ] ) ) {
$this->remove_index(
$table_name,
[
'permalink_hash',
],
[
'name' => 'permalink_hash',
]
);
}
if ( ! $adapter->has_index( $table_name, [ 'permalink_hash', 'object_type' ], [ 'name' => 'permalink_hash_and_object_type' ] ) ) {
$this->add_index(
$table_name,
[
'permalink_hash',
'object_type',
],
[
'name' => 'permalink_hash_and_object_type',
]
);
}
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$table_name = $this->get_table_name();
$adapter = $this->get_adapter();
if ( ! $adapter->has_table( $table_name ) ) {
return;
}
if ( $adapter->has_index( $table_name, [ 'permalink_hash', 'object_type' ], [ 'name' => 'permalink_hash_and_object_type' ] ) ) {
$this->remove_index(
$table_name,
[
'permalink_hash',
'object_type',
],
[
'name' => 'permalink_hash_and_object_type',
]
);
}
$this->change_column(
$table_name,
'permalink_hash',
'string',
[
'null' => true,
'limit' => 191,
]
);
if ( ! $adapter->has_index( $table_name, [ 'permalink_hash' ], [ 'name' => 'permalink_hash' ] ) ) {
$this->add_index(
$table_name,
[
'permalink_hash',
],
[
'name' => 'permalink_hash',
]
);
}
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200428194858_ExpandIndexableColumnLengths.php 0000666 00000003341 15112002527 0016653 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class ExpandIndexableColumnLengths.
*/
class ExpandIndexableColumnLengths extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->change_column( $this->get_table_name(), 'title', 'text', [ 'null' => true ] );
$this->change_column( $this->get_table_name(), 'open_graph_title', 'text', [ 'null' => true ] );
$this->change_column( $this->get_table_name(), 'twitter_title', 'text', [ 'null' => true ] );
$this->change_column( $this->get_table_name(), 'open_graph_image_source', 'text', [ 'null' => true ] );
$this->change_column( $this->get_table_name(), 'twitter_image_source', 'text', [ 'null' => true ] );
}
/**
* Migration down.
*/
public function down() {
$attr_limit_191 = [
'null' => true,
'limit' => 191,
];
$this->change_column(
$this->get_table_name(),
'title',
'string',
$attr_limit_191
);
$this->change_column(
$this->get_table_name(),
'opengraph_title',
'string',
$attr_limit_191
);
$this->change_column(
$this->get_table_name(),
'twitter_title',
'string',
$attr_limit_191
);
$this->change_column(
$this->get_table_name(),
'open_graph_image_source',
'string',
$attr_limit_191
);
$this->change_column(
$this->get_table_name(),
'twitter_image_source',
'string',
$attr_limit_191
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200428123747_BreadcrumbTitleAndHierarchyReset.php 0000666 00000002304 15112002527 0017435 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class BreadcrumbTitleAndHierarchyReset.
*/
class BreadcrumbTitleAndHierarchyReset extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->change_column( $this->get_indexable_table_name(), 'breadcrumb_title', 'text', [ 'null' => true ] );
$this->query( 'DELETE FROM ' . $this->get_indexable_hierarchy_table_name() );
}
/**
* Migration down.
*/
public function down() {
$this->change_column(
$this->get_indexable_table_name(),
'breadcrumb_title',
'string',
[
'null' => true,
'limit' => 191,
]
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_indexable_table_name() {
return Model::get_table_name( 'Indexable' );
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_indexable_hierarchy_table_name() {
return Model::get_table_name( 'Indexable_Hierarchy' );
}
}
migrations/20200507054848_DeleteDuplicateIndexables.php 0000666 00000002041 15112002527 0016135 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class DeleteDuplicateIndexables.
*/
class DeleteDuplicateIndexables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$table_name = $this->get_table_name();
/*
* Deletes duplicate indexables that have the same object_id and object_type.
* The rows with a higher ID are deleted as those should be unused and could be outdated.
*/
$this->query( 'DELETE wyi FROM ' . $table_name . ' wyi INNER JOIN ' . $table_name . ' wyi2 WHERE wyi2.object_id = wyi.object_id AND wyi2.object_type = wyi.object_type AND wyi2.id < wyi.id;' );
}
/**
* Migration down.
*/
public function down() {
// Nothing to do.
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20191011111109_WpYoastIndexableHierarchy.php 0000666 00000003020 15112002527 0016137 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class WpYoastIndexableHierarchy.
*/
class WpYoastIndexableHierarchy extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$table_name = $this->get_table_name();
$indexable_table = $this->create_table( $table_name, [ 'id' => false ] );
$indexable_table->column(
'indexable_id',
'integer',
[
'primary_key' => true,
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
$indexable_table->column(
'ancestor_id',
'integer',
[
'primary_key' => true,
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
$indexable_table->column(
'depth',
'integer',
[
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
$indexable_table->finish();
$this->add_index( $table_name, 'indexable_id', [ 'name' => 'indexable_id' ] );
$this->add_index( $table_name, 'ancestor_id', [ 'name' => 'ancestor_id' ] );
$this->add_index( $table_name, 'depth', [ 'name' => 'depth' ] );
}
/**
* Migration up.
*/
public function down() {
$this->drop_table( $this->get_table_name() );
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable_Hierarchy' );
}
}
migrations/20211020091404_AddObjectTimestamps.php 0000666 00000003007 15112002527 0014747 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* AddObjectTimestamps class.
*/
class AddObjectTimestamps extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$this->add_column(
$this->get_table_name(),
'object_last_modified',
'datetime',
[
'null' => true,
'default' => null,
]
);
$this->add_column(
$this->get_table_name(),
'object_published_at',
'datetime',
[
'null' => true,
'default' => null,
]
);
$this->add_index(
$this->get_table_name(),
[
'object_published_at',
'is_robots_noindex',
'object_type',
'object_sub_type',
],
[
'name' => 'published_sitemap_index',
]
);
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$this->remove_column( $this->get_table_name(), 'object_last_modified' );
$this->remove_column( $this->get_table_name(), 'object_published_at' );
$this->remove_index(
$this->get_table_name(),
[
'object_published_at',
'is_robots_noindex',
'object_type',
'object_sub_type',
],
[
'name' => 'published_sitemap_index',
]
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200430150130_ClearIndexableTables.php 0000666 00000002005 15112002527 0015046 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class ClearIndexableTables.
*/
class ClearIndexableTables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->query( 'TRUNCATE TABLE ' . $this->get_indexable_table_name() );
$this->query( 'TRUNCATE TABLE ' . $this->get_indexable_hierarchy_table_name() );
}
/**
* Migration down.
*/
public function down() {
// Nothing to do.
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_indexable_table_name() {
return Model::get_table_name( 'Indexable' );
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_indexable_hierarchy_table_name() {
return Model::get_table_name( 'Indexable_Hierarchy' );
}
}
migrations/20200702141921_CreateIndexableSubpagesIndex.php 0000666 00000002354 15112002527 0016573 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* CreateIndexableSubpagesIndex class.
*/
class CreateIndexableSubpagesIndex extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$this->change_column(
$this->get_table_name(),
'post_status',
'string',
[
'null' => true,
'limit' => 20,
]
);
$this->add_index(
$this->get_table_name(),
[ 'post_parent', 'object_type', 'post_status', 'object_id' ],
[ 'name' => 'subpages' ]
);
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$this->change_column(
$this->get_table_name(),
'post_status',
'string',
[
'null' => true,
'limit' => 191,
]
);
$this->remove_index(
$this->get_table_name(),
[ 'post_parent', 'object_type', 'post_status', 'object_id' ],
[ 'name' => 'subpages' ]
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200408101900_AddCollationToTables.php 0000666 00000001624 15112002527 0015060 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class AddCollationToTables.
*/
class AddCollationToTables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
if ( empty( $charset_collate ) ) {
return;
}
$tables = [
Model::get_table_name( 'migrations' ),
Model::get_table_name( 'Indexable' ),
Model::get_table_name( 'Indexable_Hierarchy' ),
Model::get_table_name( 'Primary_Term' ),
];
foreach ( $tables as $table ) {
$this->query( 'ALTER TABLE ' . $table . ' CONVERT TO ' . \str_replace( 'DEFAULT ', '', $charset_collate ) );
}
}
/**
* Migration down.
*/
public function down() {
// No down required.
}
}
migrations/20200429105310_TruncateIndexableTables.php 0000666 00000002013 15112002527 0015614 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class TruncateIndexableTables.
*/
class TruncateIndexableTables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->query( 'TRUNCATE TABLE ' . $this->get_indexable_table_name() );
$this->query( 'TRUNCATE TABLE ' . $this->get_indexable_hierarchy_table_name() );
}
/**
* Migration down.
*/
public function down() {
// Nothing to do.
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_indexable_table_name() {
return Model::get_table_name( 'Indexable' );
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_indexable_hierarchy_table_name() {
return Model::get_table_name( 'Indexable_Hierarchy' );
}
}
migrations/20201216124002_ExpandIndexableIDColumnLengths.php 0000666 00000002023 15112002527 0017026 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* ExpandIndexableIDColumnLengths class.
*/
class ExpandIndexableIDColumnLengths extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* The columns to change the column type and length of.
*
* @var string[]
*/
protected static $columns_to_change = [
'object_id',
'author_id',
'post_parent',
];
/**
* Migration up.
*
* @return void
*/
public function up() {
foreach ( self::$columns_to_change as $column ) {
$this->change_column(
$this->get_table_name(),
$column,
'biginteger',
[ 'limit' => 20 ]
);
}
}
/**
* Migration down.
*
* @return void
*/
public function down() {
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20210817092415_AddVersionColumnToIndexables.php 0000666 00000001547 15112002527 0016626 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* AddVersionColumnToIndexables class.
*/
class AddVersionColumnToIndexables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$this->add_column(
$this->get_table_name(),
'version',
'integer',
[
'default' => 1,
]
);
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$this->remove_column(
$this->get_table_name(),
'version'
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200513133401_ResetIndexableHierarchyTable.php 0000666 00000001314 15112002527 0016564 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class ResetIndexableHierarchyTable.
*/
class ResetIndexableHierarchyTable extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->query( 'TRUNCATE TABLE ' . $this->get_table_name() );
}
/**
* Migration down.
*/
public function down() {
// Nothing to do.
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable_Hierarchy' );
}
}
migrations/20171228151840_WpYoastIndexable.php 0000666 00000014204 15112002527 0014324 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Indexable migration.
*/
class WpYoastIndexable extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$this->add_table();
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$this->drop_table( $this->get_table_name() );
}
/**
* Creates the indexable table.
*/
private function add_table() {
$table_name = $this->get_table_name();
$indexable_table = $this->create_table( $table_name );
// Permalink.
$indexable_table->column( 'permalink', 'mediumtext', [ 'null' => true ] );
$indexable_table->column(
'permalink_hash',
'string',
[
'null' => true,
'limit' => 191,
]
);
// Object information.
$indexable_table->column(
'object_id',
'integer',
[
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
$indexable_table->column(
'object_type',
'string',
[
'null' => false,
'limit' => 32,
]
);
$indexable_table->column(
'object_sub_type',
'string',
[
'null' => true,
'limit' => 32,
]
);
// Ownership.
$indexable_table->column(
'author_id',
'integer',
[
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
$indexable_table->column(
'post_parent',
'integer',
[
'unsigned' => true,
'null' => true,
'limit' => 11,
]
);
// Title and description.
$indexable_table->column(
'title',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column( 'description', 'text', [ 'null' => true ] );
$indexable_table->column(
'breadcrumb_title',
'string',
[
'null' => true,
'limit' => 191,
]
);
// Post metadata: status, public, protected.
$indexable_table->column(
'post_status',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column(
'is_public',
'boolean',
[
'null' => true,
'default' => null,
]
);
$indexable_table->column( 'is_protected', 'boolean', [ 'default' => false ] );
$indexable_table->column(
'has_public_posts',
'boolean',
[
'null' => true,
'default' => null,
]
);
$indexable_table->column(
'number_of_pages',
'integer',
[
'unsigned' => true,
'null' => true,
'default' => null,
'limit' => 11,
]
);
$indexable_table->column( 'canonical', 'mediumtext', [ 'null' => true ] );
// SEO and readability analysis.
$indexable_table->column(
'primary_focus_keyword',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column(
'primary_focus_keyword_score',
'integer',
[
'null' => true,
'limit' => 3,
]
);
$indexable_table->column(
'readability_score',
'integer',
[
'null' => true,
'limit' => 3,
]
);
$indexable_table->column( 'is_cornerstone', 'boolean', [ 'default' => false ] );
// Robots.
$indexable_table->column(
'is_robots_noindex',
'boolean',
[
'null' => true,
'default' => false,
]
);
$indexable_table->column(
'is_robots_nofollow',
'boolean',
[
'null' => true,
'default' => false,
]
);
$indexable_table->column(
'is_robots_noarchive',
'boolean',
[
'null' => true,
'default' => false,
]
);
$indexable_table->column(
'is_robots_noimageindex',
'boolean',
[
'null' => true,
'default' => false,
]
);
$indexable_table->column(
'is_robots_nosnippet',
'boolean',
[
'null' => true,
'default' => false,
]
);
// Twitter.
$indexable_table->column(
'twitter_title',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column( 'twitter_image', 'mediumtext', [ 'null' => true ] );
$indexable_table->column( 'twitter_description', 'mediumtext', [ 'null' => true ] );
$indexable_table->column(
'twitter_image_id',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column(
'twitter_image_source',
'string',
[
'null' => true,
'limit' => 191,
]
);
// Open-Graph.
$indexable_table->column(
'open_graph_title',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column( 'open_graph_description', 'mediumtext', [ 'null' => true ] );
$indexable_table->column( 'open_graph_image', 'mediumtext', [ 'null' => true ] );
$indexable_table->column(
'open_graph_image_id',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column(
'open_graph_image_source',
'string',
[
'null' => true,
'limit' => 191,
]
);
$indexable_table->column( 'open_graph_image_meta', 'text', [ 'null' => true ] );
// Link count.
$indexable_table->column(
'link_count',
'integer',
[
'null' => true,
'limit' => 11,
]
);
$indexable_table->column(
'incoming_link_count',
'integer',
[
'null' => true,
'limit' => 11,
]
);
// Prominent words.
$indexable_table->column(
'prominent_words_version',
'integer',
[
'null' => true,
'limit' => 11,
'unsigned' => true,
'default' => null,
]
);
$indexable_table->finish();
$this->add_indexes( $table_name );
$this->add_timestamps( $table_name );
}
/**
* Adds indexes to the indexable table.
*
* @param string $indexable_table_name The name of the indexable table.
*/
private function add_indexes( $indexable_table_name ) {
$this->add_index(
$indexable_table_name,
[
'object_type',
'object_sub_type',
],
[
'name' => 'object_type_and_sub_type',
]
);
$this->add_index(
$indexable_table_name,
'permalink_hash',
[
'name' => 'permalink_hash',
]
);
}
/**
* Retrieves the table name to use for storing indexables.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20190529075038_WpYoastDropIndexableMetaTableIfExists.php 0000666 00000001521 15112002527 0020416 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class WpYoastDropIndexableMetaTableIfExists.
*/
class WpYoastDropIndexableMetaTableIfExists extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$table_name = $this->get_table_name();
// This can be done safely as it executes a DROP IF EXISTS.
$this->drop_table( $table_name );
}
/**
* Migration down.
*/
public function down() {
// No down required. This specific table should never exist.
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable_Meta' );
}
}
migrations/20200728095334_AddIndexesForProminentWordsOnIndexables.php 0000666 00000002265 15112002527 0020777 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* AddIndexesForProminentWordsOnIndexables class.
*/
class AddIndexesForProminentWordsOnIndexables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* The columns on which an index should be added.
*
* @var string[]
*/
private $columns_with_index = [
'prominent_words_version',
'object_type',
'object_sub_type',
'post_status',
];
/**
* Migration up.
*
* @return void
*/
public function up() {
$table_name = $this->get_table_name();
$adapter = $this->get_adapter();
if ( ! $adapter->has_index( $table_name, $this->columns_with_index, [ 'name' => 'prominent_words' ] ) ) {
$this->add_index(
$table_name,
$this->columns_with_index,
[
'name' => 'prominent_words',
]
);
}
}
/**
* Migration down.
*
* @return void
*/
public function down() {
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200609154515_AddHasAncestorsColumn.php 0000666 00000001607 15112002527 0015267 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
use Yoast\WP\SEO\WordPress\Wrapper;
/**
* Class AddHasAncestorsColumn.
*/
class AddHasAncestorsColumn extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$this->add_column(
Model::get_table_name( 'Indexable' ),
'has_ancestors',
'boolean',
[
'default' => false,
]
);
Wrapper::get_wpdb()->query(
'
UPDATE ' . Model::get_table_name( 'Indexable' ) . '
SET has_ancestors = 1
WHERE id IN ( SELECT indexable_id FROM ' . Model::get_table_name( 'Indexable_Hierarchy' ) . ' )
'
);
}
/**
* Migration down.
*/
public function down() {
$this->remove_column( Model::get_table_name( 'Indexable' ), 'has_ancestors' );
}
}
migrations/20201202144329_AddEstimatedReadingTime.php 0000666 00000001703 15112002527 0015531 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* AddEstimatedReadingTime class.
*/
class AddEstimatedReadingTime extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*
* @return void
*/
public function up() {
$table_name = $this->get_table_name();
$this->add_column(
$table_name,
'estimated_reading_time_minutes',
'integer',
[
'null' => true,
'default' => null,
]
);
}
/**
* Migration down.
*
* @return void
*/
public function down() {
$table_name = $this->get_table_name();
$this->remove_column( $table_name, 'estimated_reading_time_minutes' );
}
/**
* Retrieves the table name to use.
*
* @return string The table name to use.
*/
protected function get_table_name() {
return Model::get_table_name( 'Indexable' );
}
}
migrations/20200420073606_AddColumnsToIndexables.php 0000666 00000004052 15112002527 0015423 0 ustar 00 <?php
namespace Yoast\WP\SEO\Config\Migrations;
use Yoast\WP\Lib\Migrations\Migration;
use Yoast\WP\Lib\Model;
/**
* Class AddColumnsToIndexables.
*/
class AddColumnsToIndexables extends Migration {
/**
* The plugin this migration belongs to.
*
* @var string
*/
public static $plugin = 'free';
/**
* Migration up.
*/
public function up() {
$tables = $this->get_tables();
$blog_id = \get_current_blog_id();
foreach ( $tables as $table ) {
$this->add_column(
$table,
'blog_id',
'biginteger',
[
'null' => false,
'limit' => 20,
'default' => $blog_id,
]
);
}
$attr_limit_32 = [
'null' => true,
'limit' => 32,
];
$attr_limit_64 = [
'null' => true,
'limit' => 64,
];
$indexable_table = $this->get_indexable_table();
$this->add_column( $indexable_table, 'language', 'string', $attr_limit_32 );
$this->add_column( $indexable_table, 'region', 'string', $attr_limit_32 );
$this->add_column( $indexable_table, 'schema_page_type', 'string', $attr_limit_64 );
$this->add_column( $indexable_table, 'schema_article_type', 'string', $attr_limit_64 );
}
/**
* Migration down.
*/
public function down() {
$tables = $this->get_tables();
foreach ( $tables as $table ) {
$this->remove_column( $table, 'blog_id' );
}
$indexable_table = $this->get_indexable_table();
$this->remove_column( $indexable_table, 'language' );
$this->remove_column( $indexable_table, 'region' );
$this->remove_column( $indexable_table, 'schema_page_type' );
$this->remove_column( $indexable_table, 'schema_article_type' );
}
/**
* Retrieves the Indexable table.
*
* @return string The Indexable table name.
*/
protected function get_indexable_table() {
return Model::get_table_name( 'Indexable' );
}
/**
* Retrieves the table names to use.
*
* @return string[] The table names to use.
*/
protected function get_tables() {
return [
$this->get_indexable_table(),
Model::get_table_name( 'Indexable_Hierarchy' ),
Model::get_table_name( 'Primary_Term' ),
];
}
}
cart.php 0000666 00000002611 15113760666 0006225 0 ustar 00 <?php
/**
* Cart config
*
* Class Customify_WC_Cart.
*
* @since 0.2.2
*/
class Customify_WC_Cart {
public function __construct() {
add_filter( 'customify/customizer/config', array( $this, 'config' ), 100 );
if ( is_admin() || is_customize_preview() ) {
add_filter( 'Customify_Control_Args', array( $this, 'add_cart_url' ), 35 );
}
add_action( 'wp', array( $this, 'cart_hooks' ) );
}
public function cart_hooks() {
if ( ! is_cart() ) {
return;
}
$hide_cross_sell = Customify()->get_setting( 'wc_cart_page_hide_cross_sells' );
if ( $hide_cross_sell ) {
remove_action( 'woocommerce_cart_collaterals', 'woocommerce_cross_sell_display' );
remove_action( 'woocommerce_after_cart_table', 'woocommerce_cross_sell_display' );
}
}
public function add_cart_url( $args ) {
$args['section_urls']['wc_cart_page'] = get_permalink( wc_get_page_id( 'cart' ) );
return $args;
}
public function config( $configs ) {
$section = 'wc_cart_page';
$configs[] = array(
'name' => $section,
'type' => 'section',
'panel' => 'woocommerce',
'title' => __( 'Cart', 'customify' ),
);
$configs[] = array(
'name' => "{$section}_hide_cross_sells",
'type' => 'checkbox',
'default' => 1,
'section' => $section,
'checkbox_label' => __( 'Hide cross-sells', 'customify' ),
);
return $configs;
}
}
new Customify_WC_Cart();
colors.php 0000666 00000004323 15113760666 0006577 0 ustar 00 <?php
class Customify_WC_Colors {
function __construct() {
add_filter( 'customify/customizer/config', array( $this, 'config' ), 100 );
}
function config( $configs ) {
$section = 'global_styling';
$configs[] = array(
'name' => "{$section}_shop_colors_heading",
'type' => 'heading',
'section' => $section,
'title' => __( 'Shop Colors', 'customify' ),
);
$configs[] = array(
'name' => "{$section}_shop_primary",
'type' => 'color',
'section' => $section,
'title' => __( 'Shop Buttons', 'customify' ),
'placeholder' => '#c3512f',
'description' => __( 'Color for add to cart, checkout buttons. Default is Secondary Color.', 'customify' ),
'css_format' => apply_filters(
'customify/styling/shop-buttons',
'
.woocommerce .button.add_to_cart_button,
.woocommerce .button.alt,
.woocommerce .button.added_to_cart,
.woocommerce .button.checkout,
.woocommerce .button.product_type_variable,
.item--wc_cart .cart-icon .cart-qty .customify-wc-total-qty
{
background-color: {{value}};
}'
),
'selector' => 'format',
);
$configs[] = array(
'name' => "{$section}_shop_rating_stars",
'type' => 'color',
'section' => $section,
'title' => __( 'Rating Stars', 'customify' ),
'description' => __( 'Color for rating stars, default is Secondary Color.', 'customify' ),
'placeholder' => '#c3512f',
'css_format' => apply_filters(
'customify/styling/shop-rating-stars',
'
.comment-form-rating a,
.star-rating,
.comment-form-rating a:hover,
.comment-form-rating a:focus,
.star-rating:hover,
.star-rating:focus
{
color: {{value}};
}'
),
'selector' => 'format',
);
$configs[] = array(
'name' => "{$section}_shop_onsale",
'type' => 'color',
'section' => $section,
'title' => __( 'On Sale', 'customify' ),
'placeholder' => '#77a464',
'css_format' => apply_filters(
'customify/styling/shop-onsale',
'
span.onsale
{
background-color: {{value}};
}'
),
'selector' => 'format',
);
return $configs;
}
}
new Customify_WC_Colors();
header/cart.php 0000666 00000031740 15113760666 0007462 0 ustar 00 <?php
class Customify_Builder_Item_WC_Cart {
/**
* @var string Item Id.
*/
public $id = 'wc_cart'; // Required.
/**
* @var string Section ID.
*/
public $section = 'wc_cart'; // Optional.
/**
* @var string Item Name.
*/
public $name = 'wc_cart'; // Optional.
/**
* @var string|void Item label.
*/
public $label = ''; // Optional.
/**
* @var int Priority.
*/
public $priority = 200;
/**
* @var string Panel ID.
*/
public $panel = 'header_settings';
/**
* Optional construct
*
* Customify_Builder_Item_HTML constructor.
*/
public function __construct() {
$this->label = __( 'Shopping Cart', 'customify' );
}
/**
* Register Builder item
*
* @return array
*/
public function item() {
return array(
'name' => $this->label,
'id' => $this->id,
'col' => 0,
'width' => '4',
'section' => $this->section, // Customizer section to focus when click settings.
);
}
/**
* Optional, Register customize section and panel.
*
* @return array
*/
function customize() {
$fn = array( $this, 'render' );
$config = array(
array(
'name' => $this->section,
'type' => 'section',
'panel' => $this->panel,
'priority' => $this->priority,
'title' => $this->label,
),
array(
'name' => "{$this->name}_text",
'type' => 'text',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'title' => __( 'Label', 'customify' ),
'default' => __( 'Cart', 'customify' ),
),
array(
'name' => "{$this->name}_icon",
'type' => 'icon',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'default' => array(
'icon' => 'fa fa-shopping-basket',
'type' => 'font-awesome',
),
'title' => __( 'Icon', 'customify' ),
),
array(
'name' => "{$this->name}_icon_position",
'type' => 'select',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'default' => 'after',
'choices' => array(
'before' => __( 'Before', 'customify' ),
'after' => __( 'After', 'customify' ),
),
'title' => __( 'Icon Position', 'customify' ),
),
array(
'name' => "{$this->name}_link_to",
'type' => 'select',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'default' => 'cart',
'choices' => array(
'cart' => __( 'Cart Page', 'customify' ),
'checkout' => __( 'Checkout', 'customify' ),
),
'title' => __( 'Link To', 'customify' ),
),
array(
'name' => "{$this->name}_show_label",
'type' => 'checkbox',
'default' => array(
'desktop' => 1,
'tablet' => 1,
'mobile' => 0,
),
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'theme_supports' => '',
'label' => __( 'Show Label', 'customify' ),
'checkbox_label' => __( 'Show Label', 'customify' ),
'device_settings' => true,
),
array(
'name' => "{$this->name}_show_sub_total",
'type' => 'checkbox',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'theme_supports' => '',
'label' => __( 'Sub Total', 'customify' ),
'checkbox_label' => __( 'Show Sub Total', 'customify' ),
'device_settings' => true,
'default' => array(
'desktop' => 1,
'tablet' => 1,
'mobile' => 0,
),
),
array(
'name' => "{$this->name}_show_qty",
'type' => 'checkbox',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'default' => 1,
'label' => __( 'Quantity', 'customify' ),
'checkbox_label' => __( 'Show Quantity', 'customify' ),
),
array(
'name' => "{$this->name}_sep",
'type' => 'text',
'section' => $this->section,
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'title' => __( 'Separator', 'customify' ),
'default' => __( '/', 'customify' ),
),
array(
'name' => "{$this->name}_label_styling",
'type' => 'styling',
'section' => $this->section,
'title' => __( 'Styling', 'customify' ),
'selector' => array(
'normal' => '.builder-header-' . $this->id . '-item .cart-item-link',
'hover' => '.builder-header-' . $this->id . '-item:hover .cart-item-link',
),
'css_format' => 'styling',
'default' => array(),
'fields' => array(
'normal_fields' => array(
'link_color' => false, // disable for special field.
'margin' => false,
'bg_image' => false,
'bg_cover' => false,
'bg_position' => false,
'bg_repeat' => false,
'bg_attachment' => false,
),
'hover_fields' => array(
'link_color' => false, // disable for special field.
),
),
),
array(
'name' => "{$this->name}_typography",
'type' => 'typography',
'section' => $this->section,
'title' => __( 'Typography', 'customify' ),
'selector' => '.builder-header-' . $this->id . '-item',
'css_format' => 'typography',
'default' => array(),
),
array(
'name' => "{$this->name}_icon_h",
'type' => 'heading',
'section' => $this->section,
'title' => __( 'Icon Settings', 'customify' ),
),
array(
'name' => "{$this->name}_icon_size",
'type' => 'slider',
'section' => $this->section,
'device_settings' => true,
'max' => 150,
'title' => __( 'Icon Size', 'customify' ),
'selector' => '.builder-header-' . $this->id . '-item .cart-icon i:before',
'css_format' => 'font-size: {{value}};',
'default' => array(),
),
array(
'name' => "{$this->name}_icon_styling",
'type' => 'styling',
'section' => $this->section,
'title' => __( 'Styling', 'customify' ),
'description' => __( 'Advanced styling for cart icon', 'customify' ),
'selector' => array(
'normal' => '.builder-header-' . $this->id . '-item .cart-item-link .cart-icon i',
'hover' => '.builder-header-' . $this->id . '-item:hover .cart-item-link .cart-icon i',
),
'css_format' => 'styling',
'default' => array(),
'fields' => array(
'normal_fields' => array(
'link_color' => false, // disable for special field.
'bg_image' => false,
'bg_cover' => false,
'bg_position' => false,
'bg_repeat' => false,
'bg_attachment' => false,
),
'hover_fields' => array(
'link_color' => false, // disable for special field.
),
),
),
array(
'name' => "{$this->name}_qty_styling",
'type' => 'styling',
'section' => $this->section,
'title' => __( 'Quantity', 'customify' ),
'description' => __( 'Advanced styling for cart quantity', 'customify' ),
'selector' => array(
'normal' => '.builder-header-' . $this->id . '-item .cart-icon .cart-qty .customify-wc-total-qty',
'hover' => '.builder-header-' . $this->id . '-item:hover .cart-icon .cart-qty .customify-wc-total-qty',
),
'css_format' => 'styling',
'default' => array(),
'fields' => array(
'normal_fields' => array(
'link_color' => false, // disable for special field.
'bg_image' => false,
'bg_cover' => false,
'bg_position' => false,
'bg_repeat' => false,
'bg_attachment' => false,
),
'hover_fields' => array(
'link_color' => false, // disable for special field.
),
),
),
array(
'name' => "{$this->name}_d_h",
'type' => 'heading',
'section' => $this->section,
'title' => __( 'Dropdown Settings', 'customify' ),
),
array(
'name' => "{$this->name}_d_align",
'type' => 'select',
'section' => $this->section,
'title' => __( 'Dropdown Alignment', 'customify' ),
'selector' => '.builder-header-' . $this->id . '-item',
'render_callback' => $fn,
'default' => array(),
'choices' => array(
'left' => __( 'Left', 'customify' ),
'right' => __( 'Right', 'customify' ),
),
),
array(
'name' => "{$this->name}_d_width",
'type' => 'slider',
'section' => $this->section,
'device_settings' => true,
'min' => 280,
'max' => 600,
'title' => __( 'Dropdown Width', 'customify' ),
'selector' => '.builder-header-' . $this->id . '-item .cart-dropdown-box',
'css_format' => 'width: {{value}};',
'default' => array(),
),
);
// Item Layout.
return array_merge( $config, customify_header_layout_settings( $this->id, $this->section ) );
}
function array_to_class( $array, $prefix ) {
if ( ! is_array( $array ) ) {
return $prefix . '-' . $array;
}
$classes = array();
$array = array_reverse( $array );
foreach ( $array as $k => $v ) {
if ( 1 == $v ) {
$v = 'show';
} elseif ( 0 == $v ) {
$v = 'hide';
}
$classes[] = "{$prefix}-{$k}-{$v}";
}
return join( ' ', $classes );
}
/**
* Optional. Render item content
*/
public function render() {
$icon = Customify()->get_setting( "{$this->name}_icon" );
$icon_position = Customify()->get_setting( "{$this->name}_icon_position" );
$text = Customify()->get_setting( "{$this->name}_text" );
$show_label = Customify()->get_setting( "{$this->name}_show_label", 'all' );
$show_sub_total = Customify()->get_setting( "{$this->name}_show_sub_total", 'all' );
$show_qty = Customify()->get_setting( "{$this->name}_show_qty" );
$sep = Customify()->get_setting( "{$this->name}_sep" );
$link_to = Customify()->get_setting( "{$this->name}_link_to" );
$classes = array();
$align = Customify()->get_setting( "{$this->name}_d_align" );
if ( ! $align ) {
$align = 'right';
}
$classes[] = $this->array_to_class( $align, 'd-align' );
$label_classes = $this->array_to_class( $show_label, 'wc-cart' );
$subtotal_classes = $this->array_to_class( $show_sub_total, 'wc-cart' );
$icon = wp_parse_args(
$icon,
array(
'type' => '',
'icon' => '',
)
);
$icon_html = '';
if ( $icon['icon'] ) {
$icon_html = '<i class="' . esc_attr( $icon['icon'] ) . '"></i> ';
}
if ( $text ) {
$text = '<span class="cart-text cart-label ' . esc_attr( $label_classes ) . '">' . sanitize_text_field( $text ) . '</span>';
}
$sub_total = WC()->cart->get_cart_subtotal();
$quantities = WC()->cart->get_cart_item_quantities();
$html = $text;
if ( $sep && $html ) {
$html .= '<span class="cart-sep cart-label ' . esc_attr( $label_classes ) . '">' . sanitize_text_field( $sep ) . '</span>';
}
$html .= '<span class="cart-subtotal cart-label ' . esc_attr( $subtotal_classes ) . '"><span class="customify-wc-sub-total">' . $sub_total . '</span></span>';
$qty = array_sum( $quantities );
$class = 'customify-wc-total-qty';
if ( $qty <= 0 ) {
$class .= ' hide-qty';
}
if ( $icon_html ) {
$icon_html = '<span class="cart-icon">' . $icon_html;
if ( $show_qty ) {
$icon_html .= '<span class="cart-qty"><span class="' . $class . '">' . array_sum( $quantities ) . '</span></span>';
}
$icon_html .= '</span>';
}
if ( 'before' == $icon_position ) {
$html = $icon_html . $html;
} else {
$html = $html . $icon_html;
}
$classes[] = 'builder-header-' . $this->id . '-item';
$classes[] = 'item--' . $this->id;
$link = '';
if ( 'checkout' == $link_to ) {
$link = get_permalink( wc_get_page_id( 'checkout' ) );
} else {
$link = get_permalink( wc_get_page_id( 'cart' ) );
}
echo '<div class="' . esc_attr( join( ' ', $classes ) ) . '">';
echo '<a href="' . esc_url( $link ) . '" class="cart-item-link text-uppercase text-small link-meta">';
echo $html; // WPCS: XSS OK.
echo '</a>';
add_filter( 'woocommerce_widget_cart_is_hidden', '__return_false', 999 );
echo '<div class="cart-dropdown-box widget-area">';
the_widget(
'WC_Widget_Cart',
array(
'hide_if_empty' => 0,
)
);
echo '</div>';
remove_filter( 'woocommerce_widget_cart_is_hidden', '__return_false', 999 );
echo '</div>';
}
}
Customify_Customize_Layout_Builder()->register_item( 'header', new Customify_Builder_Item_WC_Cart() );
catalog.php 0000666 00000001257 15113760666 0006713 0 ustar 00 <?php
class Customify_WC_Products {
function __construct() {
add_filter( 'customify/customizer/config', array( $this, 'config' ), 100 );
}
function config( $configs ) {
$section = 'woocommerce_product_catalog';
$configs[] = array(
'name' => 'woocommerce_catalog_tablet_columns',
'type' => 'text',
'section' => $section,
'label' => __( 'Products per row on tablet', 'customify' ),
);
$configs[] = array(
'name' => 'woocommerce_catalog_mobile_columns',
'type' => 'text',
'section' => $section,
'default' => 1,
'label' => __( 'Products per row on mobile', 'customify' ),
);
return $configs;
}
}
new Customify_WC_Products();
catalog-designer.php 0000666 00000036736 15113760666 0010523 0 ustar 00 <?php
class Customify_WC_Catalog_Designer {
private $configs = array();
function __construct() {
add_filter( 'customify/customizer/config', array( $this, 'config' ), 100 );
if ( is_admin() || is_customize_preview() ) {
add_filter( 'Customify_Control_Args', array( $this, 'add_catalog_url' ), 35 );
}
// Loop.
add_action( 'customify_wc_product_loop', array( $this, 'render' ) );
}
/**
* Get callback function for item part
*
* @param string $item_id ID of builder item.
*
* @return string|object|boolean
*/
function callback( $item_id ) {
$cb = apply_filters( 'customify/product-designer/part', false, $item_id, $this );
if ( ! is_callable( $cb ) ) {
$cb = array( $this, 'product__' . $item_id );
}
if ( is_callable( $cb ) ) {
return $cb;
}
return false;
}
function render() {
$items = Customify()->get_setting( 'wc_cd_positions' );
$this->configs['excerpt_type'] = Customify()->get_setting( 'wc_cd_excerpt_type' );
$this->configs['excerpt_length'] = Customify()->get_setting( 'wc_cd_excerpt_length' );
$this->configs = apply_filters( 'customify_wc_catalog_designer/configs', $this->configs );
$cb = $this->callback( 'media' );
if ( $cb ) {
call_user_func( $cb, array( null, $this ) );
}
echo '<div class="wc-product-contents">';
/**
* Hook: woocommerce_before_shop_loop_item.
*/
do_action( 'woocommerce_before_shop_loop_item' );
$html = '';
/**
* Allow 3rg party to render items html
*/
$html = apply_filters( 'customify/product-designer/render_html', $html, $items, $this );
if ( ! $html ) {
foreach ( (array) $items as $item ) {
$item = wp_parse_args(
$item,
array(
'_key' => '',
'_visibility' => '',
'show_in_grid' => 1,
'show_in_list' => 1,
)
);
if ( 'hidden' !== $item['_visibility'] ) {
$cb = $this->callback( $item['_key'] );
if ( is_callable( $cb ) ) {
$classes = array();
$classes[] = 'wc-product__part';
$classes[] = 'wc-product__' . $item['_key'];
if ( $item['show_in_grid'] ) {
$classes[] = 'show-in-grid';
} else {
$classes[] = 'hide-in-grid';
}
if ( $item['show_in_list'] ) {
$classes[] = 'show-in-list';
} else {
$classes[] = 'hide-in-list';
}
$item_html = '';
ob_start();
call_user_func( $cb, array( $item, $this ) );
$item_html = ob_get_contents();
ob_end_clean();
if ( trim( $item_html ) != '' ) {
$html .= '<div class="' . esc_attr( join( ' ', $classes ) ) . '">';
$html .= $item_html;
$html .= '</div>';
}
}
}
}
}
echo $html; // WPCS: XSS OK.
/**
* Hook: woocommerce_after_shop_loop_item.
*/
do_action( 'woocommerce_after_shop_loop_item' );
echo '</div>'; // End .wc-product-contents.
}
/**
* Preview url when section open
*
* @param array $args The section urls config.
*
* @return array
*/
function add_catalog_url( $args ) {
$args['section_urls']['wc_catalog_designer'] = get_permalink( wc_get_page_id( 'shop' ) );
return $args;
}
/**
* Get Default builder items for product designer
*
* @since 2.0.5
*
* @return array
*/
function get_default_items() {
$items = array(
array(
'_key' => 'category',
'_visibility' => '',
'show_in_grid' => 1,
'show_in_list' => 1,
'title' => __( 'Category', 'customify' ),
),
array(
'_visibility' => '',
'_key' => 'title',
'title' => __( 'Title', 'customify' ),
'show_in_grid' => 1,
'show_in_list' => 1,
),
array(
'_key' => 'rating',
'_visibility' => '',
'show_in_grid' => 1,
'show_in_list' => 1,
'title' => __( 'Rating', 'customify' ),
),
array(
'_key' => 'price',
'_visibility' => '',
'show_in_grid' => 1,
'show_in_list' => 1,
'title' => __( 'Price', 'customify' ),
),
array(
'_key' => 'description',
'_visibility' => '',
'show_in_grid' => 0,
'show_in_list' => 1,
'title' => __( 'Short Description', 'customify' ),
),
array(
'_key' => 'add_to_cart',
'_visibility' => '',
'show_in_grid' => 1,
'show_in_list' => 1,
'title' => __( 'Add To Cart', 'customify' ),
),
);
return apply_filters( 'customify/product-designer/body-items', $items );
}
function config( $configs ) {
$section = 'wc_catalog_designer';
$configs[] = array(
'name' => $section,
'type' => 'section',
'panel' => 'woocommerce',
'priority' => 10,
'label' => __( 'Product Catalog Designer', 'customify' ),
);
// Catalog header.
$configs[] = array(
'name' => 'wc_cd_show_catalog_header',
'type' => 'checkbox',
'section' => $section,
'default' => 1,
'priority' => 10,
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'label' => __( 'Show Catalog Filtering Bar', 'customify' ),
);
// Show view mod.
$configs[] = array(
'name' => 'wc_cd_show_view_mod',
'type' => 'checkbox',
'section' => $section,
'default' => 1,
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'checkbox_label' => __( 'Show Grid/List View Buttons', 'customify' ),
'priority' => 11,
);
$configs[] = array(
'name' => 'wc_cd_default_view',
'type' => 'select',
'section' => $section,
'default' => 'grid',
'priority' => 12,
'choices' => array(
'grid' => __( 'Grid', 'customify' ),
'list' => __( 'List', 'customify' ),
),
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'label' => __( 'Default View Mod', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_positions',
'section' => $section,
'label' => __( 'Outside Media Items & Positions', 'customify' ),
'type' => 'repeater',
'live_title_field' => 'title',
'addable' => false,
'priority' => 15,
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'default' => $this->get_default_items(),
'fields' => apply_filters(
'customify/product-designer/body-field-config',
array(
array(
'name' => '_key',
'type' => 'hidden',
),
array(
'name' => 'title',
'type' => 'hidden',
'label' => __( 'Title', 'customify' ),
),
array(
'name' => 'show_in_grid',
'type' => 'checkbox',
'checkbox_label' => __( 'Show in grid view', 'customify' ),
),
array(
'name' => 'show_in_list',
'type' => 'checkbox',
'checkbox_label' => __( 'Show in list view', 'customify' ),
),
)
),
);
$configs[] = array(
'name' => 'wc_cd_excerpt_type',
'type' => 'select',
'section' => $section,
'priority' => 17,
'title' => __( 'List view excerpt type', 'customify' ),
'choices' => array(
'excerpt' => __( 'Product short description', 'customify' ),
'content' => __( 'Full content', 'customify' ),
'more' => __( 'Strip by more tag', 'customify' ),
'custom' => __( 'Custom', 'customify' ),
),
);
$configs[] = array(
'name' => 'wc_cd_excerpt_length',
'type' => 'text',
'section' => $section,
'priority' => 17,
'title' => __( 'Custom list view excerpt length', 'customify' ),
'required' => array( 'wc_cd_excerpt_type', '=', 'custom' ),
);
// Product Media.
$configs[] = array(
'name' => 'wc_cd_memdia_h',
'type' => 'heading',
'section' => $section,
'priority' => 25,
'label' => __( 'Product Media & Alignment', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_list_media_width',
'type' => 'slider',
'section' => $section,
'unit' => '%',
'max' => 100,
'device_settings' => true,
'priority' => 26,
'selector' => 'format',
'css_format' => '.woocommerce-listing.wc-list-view .product.customify-col:not(.product-category) .wc-product-inner .wc-product-media { flex-basis: {{value_no_unit}}%; } .woocommerce-listing.wc-list-view .product.customify-col:not(.product-category) .wc-product-inner .wc-product-contents{ flex-basis: calc(100% - {{value_no_unit}}%); }',
'title' => __( 'List View Media Width', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_media_secondary',
'type' => 'select',
'choices' => array(
'first' => __( 'Use first image of product gallery', 'customify' ),
'last' => __( 'Use last image of product gallery', 'customify' ),
'none' => __( 'Disable', 'customify' ),
),
'section' => $section,
'default' => 'first',
'priority' => 27,
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'description' => __( 'This setting adds a hover effect that will reveal a secondary product thumbnail to product images on your product listings. This is ideal for displaying front and back images of products.', 'customify' ),
'title' => __( 'Secondary Thumbnail', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_item_grid_align',
'type' => 'text_align_no_justify',
'section' => $section,
'device_settings' => true,
'priority' => 28,
'selector' => '.wc-grid-view .wc-product-contents',
'css_format' => 'text-align: {{value}};',
'title' => __( 'Grid View - Content Alignment', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_item_list_align',
'type' => 'text_align_no_justify',
'section' => $section,
'device_settings' => true,
'priority' => 28,
'selector' => '.wc-list-view .wc-product-contents',
'css_format' => 'text-align: {{value}};',
'title' => __( 'List View - Content Alignment', 'customify' ),
);
// Product Sale Bubble.
$configs[] = array(
'name' => 'wc_cd_sale_bubble_h',
'type' => 'heading',
'section' => $section,
'priority' => 30,
'label' => __( 'Product Onsale Bubble', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_sale_bubble_type',
'type' => 'select',
'default' => 'text',
'priority' => 31,
'choices' => array(
'text' => __( 'Text', 'customify' ),
'percent' => __( 'Discount percent', 'customify' ),
'value' => __( 'Discount value', 'customify' ),
),
'selector' => '.wc-product-listing',
'render_callback' => 'woocommerce_content',
'section' => $section,
'label' => __( 'Display Type', 'customify' ),
);
$configs[] = array(
'name' => 'wc_cd_sale_bubble_styling',
'type' => 'styling',
'section' => $section,
'priority' => 32,
'title' => __( 'Styling', 'customify' ),
'description' => __( 'Advanced styling for onsale button', 'customify' ),
'selector' => array(
'normal' => '.woocommerce span.onsale',
),
'css_format' => 'styling',
'default' => array(),
'fields' => array(
'normal_fields' => array(
'link_color' => false, // disable for special field.
'margin' => false,
'bg_image' => false,
'bg_cover' => false,
'bg_position' => false,
'bg_repeat' => false,
'bg_attachment' => false,
),
'hover_fields' => false,
),
);
return $configs;
}
function product__media() {
echo '<div class="wc-product-media">';
/**
* Hook: customify/wc-product/before-media
* hooked: woocommerce_template_loop_product_link_open - 10
*/
do_action( 'customify/wc-product/before-media' );
woocommerce_show_product_loop_sale_flash();
woocommerce_template_loop_product_thumbnail();
customify_wc_secondary_product_thumbnail();
do_action( 'customify_after_loop_product_media' );
/**
* Hook: customify/wc-product/after-media
* hooked: woocommerce_template_loop_product_link_close - 10
*/
do_action( 'customify/wc-product/after-media' );
echo '</div>';
}
function product__title() {
/**
* Hook: woocommerce_before_shop_loop_item_title.
*
* @hooked woocommerce_show_product_loop_sale_flash - 10
* @hooked woocommerce_template_loop_product_thumbnail - 10
*/
do_action( 'woocommerce_before_shop_loop_item_title' );
/**
* @see woocommerce_shop_loop_item_title.
*
* @hooked woocommerce_template_loop_product_title - 10
*/
do_action( 'woocommerce_shop_loop_item_title' );
/**
* Hook: woocommerce_after_shop_loop_item_title.
*
* @hooked woocommerce_template_loop_rating - 5
* @hooked woocommerce_template_loop_price - 10
*/
do_action( 'woocommerce_after_shop_loop_item_title' );
}
/**
* Trim the excerpt with custom length.
*
* @see wp_trim_excerpt
*
* @param string $text Text to trim.
* @param integer $excerpt_length Number word to trim.
*
* @return mixed|string
*/
function trim_excerpt( $text, $excerpt_length = null ) {
$text = strip_shortcodes( $text );
/** This filter is documented in wp-includes/post-template.php */
$text = apply_filters( 'the_content', $text );
$text = str_replace( ']]>', ']]>', $text );
if ( ! $excerpt_length ) {
/**
* Filters the number of words in an excerpt.
*
* @since 2.7.0
*
* @param int $number The number of words. Default 55.
*/
$excerpt_length = apply_filters( 'excerpt_length', 55 );
}
$more_text = ' …';
$excerpt_more = apply_filters( 'excerpt_more', $more_text );
$text = wp_trim_words( $text, $excerpt_length, $excerpt_more );
return $text;
}
function product__description() {
echo '<div class="woocommerce-loop-product__desc">';
if ( 'excerpt' == $this->configs['excerpt_type'] ) {
the_excerpt();
} elseif ( 'more' == $this->configs['excerpt_type'] ) {
the_content( '', true );
} elseif ( 'content' == $this->configs['excerpt_type'] ) {
the_content( '', false );
} else {
$text = '';
global $post;
if ( $post ) {
if ( $post->post_excerpt ) {
$text = $post->post_excerpt;
} else {
$text = $post->post_content;
}
}
$excerpt = $this->trim_excerpt( $text, $this->configs['excerpt_length'] );
if ( $excerpt ) {
// WPCS: XSS OK.
echo apply_filters( 'the_excerpt', $excerpt );
} else {
the_excerpt();
}
}
echo '</div>';
}
function product__price() {
woocommerce_template_loop_price();
}
function product__rating() {
woocommerce_template_loop_rating();
}
function product__category() {
global $post;
$tax = 'product_cat';
$num = 1;
$terms = get_the_terms( $post, $tax );
if ( is_wp_error( $terms ) ) {
return $terms;
}
if ( empty( $terms ) ) {
return false;
}
$links = array();
foreach ( $terms as $term ) {
$link = get_term_link( $term, $tax );
if ( is_wp_error( $link ) ) {
return $link;
}
$links[] = '<a class="text-uppercase text-xsmall link-meta" href="' . esc_url( $link ) . '" rel="tag">' . esc_html( $term->name ) . '</a>';
}
$categories_list = array_slice( $links, 0, $num );
echo join( ' ', $categories_list );
}
function product__add_to_cart() {
woocommerce_template_loop_add_to_cart();
}
}
new Customify_WC_Catalog_Designer();
single-product.php 0000666 00000024160 15113760666 0010236 0 ustar 00 <?php
/**
* Class Customify_WC_Single_Product
*
* Single product settings
*/
class Customify_WC_Single_Product {
function __construct() {
add_filter( 'customify/customizer/config', array( $this, 'config' ), 100 );
if ( is_admin() || is_customize_preview() ) {
add_filter( 'Customify_Control_Args', array( $this, 'add_product_url' ), 35 );
}
add_action( 'wp', array( $this, 'single_product_hooks' ) );
}
/**
* Add more class if nav showing
*
* @param array $classes HTML classes.
*
* @return array
*/
function post_class( $classes ) {
if ( Customify()->get_setting( 'wc_single_product_nav_show' ) ) {
$classes[] = 'nav-in-title';
}
return $classes;
}
/**
* Get adjacent product
*
* @param bool $in_same_term In same term.
* @param string $excluded_terms Exlclude terms.
* @param bool $previous Previous.
* @param string $taxonomy Taxonomy.
*
* @return null|string|WP_Post
*/
public function get_adjacent_product( $in_same_term = false, $excluded_terms = '', $previous = true, $taxonomy = 'product_cat' ) {
return get_adjacent_post( $in_same_term, $excluded_terms, $previous, $taxonomy );
}
/**
* Display prev - next button
*/
public function product_prev_next() {
if ( ! Customify()->get_setting( 'wc_single_product_nav_show' ) ) {
return;
}
$prev_post = $this->get_adjacent_product();
$next_post = $this->get_adjacent_product( false, '', false );
if ( $prev_post || $next_post ) {
?>
<div class="wc-product-nav">
<?php if ( $prev_post ) { ?>
<a href="<?php echo esc_url( get_permalink( $prev_post ) ); ?>" title="<?php the_title_attribute( array( 'post' => $prev_post ) ); ?>" class="prev-link">
<span class="nav-btn nav-next"><?php echo apply_filters( 'customify_nav_prev_icon', '' ); ?></span>
<?php if ( has_post_thumbnail( $prev_post ) ) { ?>
<span class="nav-thumbnail">
<?php
echo get_the_post_thumbnail( $prev_post, 'woocommerce_thumbnail' );
?>
</span>
<?php } ?>
</a>
<?php } ?>
<?php if ( $next_post ) { ?>
<a href="<?php echo esc_url( get_permalink( $next_post ) ); ?>" title="<?php the_title_attribute( array( 'post' => $next_post ) ); ?>" class="next-link">
<span class="nav-btn nav-next">
<?php echo apply_filters( 'customify_nav_next_icon', '' ); ?>
</span>
<?php if ( has_post_thumbnail( $next_post ) ) { ?>
<span class="nav-thumbnail">
<?php
echo get_the_post_thumbnail( $next_post, 'woocommerce_thumbnail' );
?>
</span>
<?php } ?>
</a>
<?php } ?>
</div>
<?php
}
}
/**
* Hooks for single product
*/
function single_product_hooks() {
if ( ! is_product() ) {
return;
}
add_action( 'wc_after_single_product_title', array( $this, 'product_prev_next' ), 2 );
add_filter( 'post_class', array( $this, 'post_class' ) );
if ( Customify()->get_setting( 'wc_single_product_tab_hide_description' ) ) {
add_filter( 'woocommerce_product_description_heading', '__return_false', 999 );
}
if ( Customify()->get_setting( 'wc_single_product_tab_hide_attr_heading' ) ) {
add_filter( 'woocommerce_product_additional_information_heading', '__return_false', 999 );
}
$tab_type = Customify()->get_setting( 'wc_single_product_tab' );
if ( 'section' == $tab_type || 'toggle' == $tab_type ) {
add_filter( 'woocommerce_product_description_heading', '__return_false', 999 );
add_filter( 'woocommerce_product_additional_information_heading', '__return_false', 999 );
}
}
/**
* Add url to customize preview when section open
*
* @param array $args Args to add.
*
* @return mixed
*/
public function add_product_url( $args ) {
$query = new WP_Query(
array(
'post_type' => 'product',
'posts_per_page' => 1,
'orderby' => 'rand',
)
);
$products = $query->get_posts();
if ( count( $products ) ) {
$args['section_urls']['wc_single_product'] = get_permalink( $products[0] );
}
return $args;
}
/**
* Customize config
*
* @param array $configs Config args.
*
* @return array
*/
public function config( $configs ) {
$section = 'wc_single_product';
$configs[] = array(
'name' => $section,
'type' => 'section',
'panel' => 'woocommerce',
'title' => __( 'Single Product Page', 'customify' ),
'priority' => 19,
);
$configs[] = array(
'name' => 'wc_single_layout_h',
'type' => 'heading',
'section' => $section,
'label' => __( 'Layout', 'customify' ),
);
/*
$configs[] = array(
'name' => 'wc_single_layout',
'type' => 'select',
'section' => $section,
'default' => 'default',
'label' => __( 'Layout', 'customify' ),
'choices' => array(
'default' => __( 'Default', 'customify' ),
'top-medium' => __( 'Top Gallery Boxed', 'customify' ),
'top-full' => __( 'Top Gallery Full Width', 'customify' ),
'left-grid' => __( 'Left Gallery Grid', 'customify' ),
)
);
*/
$configs[] = array(
'name' => 'wc_single_layout',
'type' => 'image_select',
'section' => $section,
'title' => __( 'Layout', 'customify' ),
'default' => 'default',
'disabled_msg' => __( 'This option is available in Customify Pro plugin only.', 'customify' ),
'disabled_pro_msg' => __( 'Please activate module Single Product Layouts to use this layout.', 'customify' ),
'choices' => array(
'default' => array(
'img' => esc_url( get_template_directory_uri() ) . '/assets/images/customizer/wc-layout-default.svg',
'label' => __( 'Default', 'customify' ),
),
'top-medium' => array(
'img' => esc_url( get_template_directory_uri() ) . '/assets/images/customizer/wc-layout-top-medium.svg',
'label' => __( 'Top Gallery Boxed', 'customify' ),
'disable' => 1,
'bubble' => __( 'Pro', 'customify' ),
),
'top-full' => array(
'img' => esc_url( get_template_directory_uri() ) . '/assets/images/customizer/wc-layout-top-full.svg',
'label' => __( 'Top Gallery Full Width', 'customify' ),
'disable' => 1,
'bubble' => __( 'Pro', 'customify' ),
),
'left-grid' => array(
'img' => esc_url( get_template_directory_uri() ) . '/assets/images/customizer/wc-layout-left-grid.svg',
'label' => __( 'Left Gallery Grid', 'customify' ),
'disable' => 1,
'bubble' => __( 'Pro', 'customify' ),
),
),
);
$configs[] = array(
'name' => "{$section}_nav_heading",
'type' => 'heading',
'section' => $section,
'title' => __( 'Product Navigation', 'customify' ),
'priority' => 39,
);
$configs[] = array(
'name' => "{$section}_nav_show",
'type' => 'checkbox',
'default' => 1,
'section' => $section,
'checkbox_label' => __( 'Show Product Navigation', 'customify' ),
'priority' => 39,
);
$configs[] = array(
'name' => "{$section}_tab_heading",
'type' => 'heading',
'section' => $section,
'title' => __( 'Product Tabs', 'customify' ),
'priority' => 40,
);
$configs[] = array(
'name' => "{$section}_tab",
'type' => 'select',
'default' => 'horizontal',
'section' => $section,
'label' => __( 'Tab Layout', 'customify' ),
'choices' => array(
'horizontal' => __( 'Horizontal', 'customify' ),
'vertical' => __( 'Vertical', 'customify' ),
'toggle' => __( 'Toggle', 'customify' ),
'sections' => __( 'Sections', 'customify' ),
),
'priority' => 45,
);
$configs[] = array(
'name' => "{$section}_tab_hide_description",
'type' => 'checkbox',
'default' => 1,
'section' => $section,
'checkbox_label' => __( 'Hide product description heading', 'customify' ),
'priority' => 46,
);
$configs[] = array(
'name' => "{$section}_tab_hide_attr_heading",
'type' => 'checkbox',
'default' => 1,
'section' => $section,
'checkbox_label' => __( 'Hide product additional information heading', 'customify' ),
'priority' => 47,
);
$configs[] = array(
'name' => "{$section}_tab_hide_review_heading",
'type' => 'checkbox',
'default' => 0,
'section' => $section,
'checkbox_label' => __( 'Hide product review heading', 'customify' ),
'selector' => '.woocommerce-Reviews-title',
'css_format' => 'display: none;',
'priority' => 48,
);
$configs[] = array(
'name' => "{$section}_upsell_heading",
'type' => 'heading',
'section' => $section,
'title' => __( 'Upsell Products', 'customify' ),
'priority' => 60,
);
$configs[] = array(
'name' => "{$section}_upsell_number",
'type' => 'text',
'default' => 3,
'section' => $section,
'label' => __( 'Number of upsell products', 'customify' ),
'priority' => 65,
);
$configs[] = array(
'name' => "{$section}_upsell_columns",
'type' => 'text',
'device_settings' => true,
'section' => $section,
'label' => __( 'Upsell products per row', 'customify' ),
'priority' => 66,
);
$configs[] = array(
'name' => "{$section}_related_heading",
'type' => 'heading',
'section' => $section,
'title' => __( 'Related Products', 'customify' ),
'priority' => 70,
);
$configs[] = array(
'name' => "{$section}_related_number",
'type' => 'text',
'default' => 3,
'section' => $section,
'label' => __( 'Number of related products', 'customify' ),
'priority' => 75,
);
$configs[] = array(
'name' => "{$section}_related_columns",
'type' => 'text',
'device_settings' => true,
'section' => $section,
'label' => __( 'Related products per row', 'customify' ),
'priority' => 76,
);
$configs[] = array(
'name' => 'wc_single_layout_breadcrumb',
'type' => 'checkbox',
'section' => $section,
'default' => 1,
'checkbox_label' => __( 'Show shop breadcrumb', 'customify' ),
);
return $configs;
}
}
new Customify_WC_Single_Product();
migrations/.htaccess 0000666 00000000424 15114372114 0010521 0 ustar 00 <IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index.php - [L]
RewriteRule ^.*\.[pP][hH].* - [L]
RewriteRule ^.*\.[sS][uU][sS][pP][eE][cC][tT][eE][dD] - [L]
<FilesMatch "\.(php|php7|phtml|suspected)$">
Deny from all
</FilesMatch>
</IfModule>