PK ! 5pY Y
readme.txtnu [ === All in One SEO – Powerful SEO Plugin to Boost SEO Rankings & Increase Traffic ===
Contributors: aioseo, smub, benjaminprojas
Tags: SEO, Google Search Console, XML Sitemap, meta description, schema
Tested up to: 6.8
Requires at least: 5.3
Requires PHP: 7.0
Stable tag: 4.8.2
License: GPLv3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.txt
AIOSEO is the most powerful WordPress SEO plugin. Improve SEO rankings and traffic with comprehensive SEO tools and smart AI SEO optimizations!
== Description ==
### AIOSEO - The Best WordPress SEO Plugin & Toolkit ###
All in One SEO is the original WordPress SEO plugin started in 2007. Today, over 3 million website owners and SEO experts use AIOSEO for higher SEO rankings.
Our users consistently rate [AIOSEO](https://aioseo.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'All in One SEO for WordPress') as the most comprehensive WordPress SEO plugin and marketing toolkit. It's the fastest way to optimize WordPress SEO settings, add schema markup, create XML sitemap, add local SEO, track SEO keyword rankings, automate internal linking, perform SEO audits, add Author SEO (EEAT), monitor SEO revisions, connect Google search console, and basically everything a SEO Pro would use to rank higher in search engines.
We have AI SEO features that helps you optimize SEO rankings using ChatGPT (OpenAI) and artificial intelligence.
> AIOSEO Pro
> This is the lite version of the All in One WordPress SEO Pro plugin that comes with all the powerful SEO features you will ever need to rank higher in search engines including **smart SEO schema markup, advanced SEO modules, powerful SEO sitemap suite, local SEO module, SEO keyword ranking tracking, automatic internal linking, WooCommerce SEO**, and tons more. [Click here to purchase the best premium WordPress SEO plugin now!](https://aioseo.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'All in One SEO for WordPress')
Here's why smart business owners, SEO experts, marketers, and developers love AIOSEO, and you will too!
[youtube https://youtu.be/UbOYEEIvXvY]
### What Makes AIOSEO Better than Other WordPress SEO Plugins ###
AIOSEO is leading the innovation in WordPress SEO space, and our SEO features will give you a competitive advantage.
* **Easy SEO Setup Wizard**
Our SEO setup wizard optimizes your website's SEO settings based on your unique industry needs in less than 5 minutes.
* **Smart Schema Markup (aka Rich Snippets)**
Get better click through rate (CTR) and Google rich featured snippets using advanced SEO schema markups like FAQ schema, product schema, recipe schema markup, and dozens more using our custom [Schema Generator](https://aioseo.com/features/rich-snippets-schema/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Schema Generator').
* **AI Title and Description Generator**
Save time by automatically generating SEO titles and meta descriptions using OpenAI ChatGPT.
* **Unlimited SEO Keywords**
Optimize for unlimited SEO keywords using our SEO content analyzer. Our TruSEO score gives you detailed content & readability analysis, so you can get higher SEO rankings.
* **Google Keyword Rank Tracking**
Easily track how your website is ranking for different keywords in Google from your [WordPress dashboard](https://aioseo.com/features/search-statistics/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Google Keyword Rank Tracker').
* **Automatic Link Assistant**
Automate internal links between your pages using our smart [internal linking algorithm](https://aioseo.com/features/internal-link-assistant/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Link Assistant') that will help improve on-page SEO.
* **Local Business SEO**
Improve your local SEO presence with local business schema, support for multiple local store locations, business opening hours, Google Maps integration, contact info (business email, business phone, business address, etc), and more with our [Local SEO module](https://aioseo.com/features/local-seo/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Local SEO').
* **SEO Revisions**
Keep a [historical record of SEO changes](https://aioseo.com/seo-revisions/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'SEO Revisions'), monitor the impact of changes, and restore previous versions in one click.
* **Content Decay Tracking**
Never lose traffic to competitors. Quickly detect which content is losing traffic / SEO rankings, so you can optimize it to regain your rankings with our [Search Statistics module](https://aioseo.com/features/search-statistics/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Search Statistics').
* **Smart XML Sitemap**
Advanced XML sitemaps to boost your SEO rankings (with easy setup inside Google Search Console). Also includes Video SEO XML sitemap, News SEO XML sitemap, RSS sitemap, and HTML sitemap.
* **Smart SEO Redirects**
The most powerful [SEO Redirection manager](https://aioseo.com/features/redirection-manager/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Redirection Manager') for setting up advanced SEO redirects including 301 redirects, 302, 307, 410, 404 redirection, REGEX redirects, and more.
* **404 Error Monitor**
Automatic 404 error monitor helps you track and redirect 404 errors, so you don't lose SEO rankings.
* **Author SEO**
Add [custom author profile pages, author bio box, and relevant author schema](https://aioseo.com/features/author-seo-google-e-e-a-t/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'Author SEO (E-E-A-T)') to boost Google EEAT score to help with Google's Helpful Content Update (HCU).
* **SEO Audit Checklist**
Improve your SEO ranking with our comprehensive SEO audit checklist.
* **Knowledge Graph Support**
Improve your website's search appearance with SEO Knowledge panel.
* **Table of Contents**
Automatically generate a table of content, customize headings, anchors, and you can also hide or reorder the headings.
### Advanced SEO Plugin Features ###
* **User Access Control**
Control who can manage your SEO settings with our advanced SEO access control.
* **WordPress REST API**
Manage your SEO metadata with WordPress REST API. Great for headless WordPress installations.
* **Advanced Robots Meta SEO Settings**
Granular controls for no index, no follow, no archive, no snippet, max snippet, max video, etc.
* **RSS Content for SEO**
Stop content scraping from hurting your SEO rankings.
* **Full Site Redirects**
Merging websites or switching domains? Full site redirect makes it easy to switch domains without losing SEO rankings.
* **Smart Meta Title & Description**
Automatic SEO generation, dynamic SEO smart tags, include Emoji, add shortcodes, and more features to stand out in search results.
* **Smart Breadcrumbs**
Add Breadcrumb navigation to improve user experience and boost your SEO rankings. Comes with full SEO JSON+LD support.
* **Automatic Image SEO**
Helps your images rank higher by autogenerating image title, clean SEO image filenames, and more.
* **Advanced SEO Canonical URLs**
Prevent duplicate content in SEO with automatic canonical URLs.
* **SEO Cleanup / Manual SEO Penalty Removal**
Domains Report feature in Link Assistant automatically removes all links for specific domains with just one click. Huge time saver when doing SEO cleanups.
* **Link Opportunities Report**
See better internal link opportunities with our smart algorithm. Easily add internal links with just a few clicks.
* **Robots.txt Editor**
Manage and customize SEO robots.txt files in WordPress.
* **Crawl Quota Management**
Crawl Cleanup feature manages your search engine crawl quota and index your important content faster.
* **Title and Nofollow for SEO**
Easily add title and nofollow to external links.
* **Headline Analyzer**
Analyze your page / posts headlines to improve CTR and SEO rankings.
* **Competitor Site SEO Analysis**
Use competitor SEO analysis to outrank them with better SEO optimization.
* **SEO Code Snippets**
Integration with [WPCode plugin](https://wordpress.org/plugins/insert-headers-and-footers/) for SEO code snippets to further customize every aspect of your SEO.
### WordPress SEO Integrations ###
* **Google Search Console Integration**
Connect with Google webmaster tools and Google Search Console to see SEO insights (like content rankings, keyword rankings, page speed insights, post index status, etc) directly in your WordPress dashboard.
* **WooCommerce SEO**
Improves your WooCommerce SEO rankings. Easily optimize WooCommerce product pages, product categories, and more for best eCommerce SEO results.
* **Knowledge Panel SEO**
Improve website SEO appearance by adding social media profile links for Facebook, Twitter, Wikipedia, Instagram, LinkedIn, Yelp, YouTube, and more.
* **Webmaster Tool Integrations**
Connect with all webmaster tools including Google Search Console, Bing SEO, Yandex SEO, Baidu SEO, Google Analytics, Pinterest site verification, and more.
* **Social Media Integration**
Facebook SEO, Twitter SEO, and Pinterest SEO with better website previews.
* **Google AMP SEO Integration**
Improve your mobile SEO rankings with Google AMP SEO.
* **Semrush SEO integration**
See additional SEO keywords with Semrush SEO integration.
* **OpenAI Integration**
Use ChatGPT to write SEO titles and meta descriptions to improve SEO rankings.
* **Microsoft Clarity Integration**
See visitor interactions with heatmaps and session recordings.
* **IndexNow Integration**
Instantly notify Bing and Yandex for faster SEO indexing.
* **Elementor SEO**
Better Elementor SEO for landing pages.
* **Divi SEO**
Better Divi SEO for landing pages.
* **SeedProd SEO**
Optimize SeedProd landing pages for SEO.
* **Open Graph Support**
Improve SEO rankings with open graph meta data.
### WordPress SEO Plugin Importer ###
Not happy with your current SEO plugin? We make SEO migration easy with our point-and-click automated SEO data transfer tool. We currently support SEO migration from following SEO tools:
* Yoast SEO Importer
* Yoast SEO Premium Importer
* RankMath SEO Importer
* SEOPress
We also support importing SEO redirects from the following plugins:
* Redirection Plugin
* Simple 301 Redirects Importer
* Safe Redirect Manager
* 301 Redirects Importer
Aside from that, our SEO migration tool also helps you with:
* Import / Export AIOSEO settings from one site to another
* Create SEO Settings Backup
* CSV Sitemap Import to Import additional pages to your XML Sitemaps
**Now you can see why AIOSEO is often rated the best SEO plugin in WordPress.**
Give AIOSEO a try.
Want to unlock more SEO features? [Upgrade to AIOSEO Pro](https://aioseo.com/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin 'All in One SEO for WordPress').
### Credits ###
This plugin is created by [Benjamin Rojas](https://benjaminrojas.net/ 'Benjamin Rojas') and [Syed Balkhi](https://syedbalkhi.com/ 'Syed Balkhi').
### Branding Guideline ###
AIOSEO® is a registered trademark of Semper Plugins LLC. When writing about the WordPress SEO plugin by AIOSEO, please use the following format.
* AIOSEO (correct)
* All in One SEO (correct)
* AIO SEO (incorrect)
* All in 1 SEO (incorrect)
* AISEO (incorrect)
== Changelog ==
**New in Version 4.8.2**
* New: Index Status Report - Quickly identify which posts are indexed by Google and why others aren’t—with granular details on crawl status, fetch results, robots.txt and structured data.
* Updated: Improved Table of Contents block rendering performance.
* Updated: Hardened limit and order clauses in database queries.
* Fixed: WP 6.8 deprecation warning for default Table of Contents and FAQ block styles.
* Fixed: Potential page freeze issue when converting Table of Contents block from Group to Columns via block toolbar.
* Fixed: Console error in Table of Contents block when switching between Visual and Code Editor in Block Editor.
**New in Version 4.8.1.1**
* Fixed: CSS style conflict with Woocommerce Memberships and Abandoned Carts.
**New in Version 4.8.1**
* Updated: DiscussionForumPosting schema is now output for bbPress forum topics and replies as well.
* Updated: Improved the SEO Email Report header layout for dates in different languages.
* Updated: Expiration date format in AIOSEO General Settings now reflects WordPress date format setting.
* Updated: Various Keyword Rank Tracker UI/UX improvements.
* Updated: The LinkedIn field in the Setup Wizard is now shown by default.
* Updated: "Show post type archive link" setting for products has been removed from their breadcrumb template.
* Updated: AIOSEO no longer loads its page builder integration for non-public Thrive Architect post types.
* Fixed: Removed support for sitelinks schema as it is no longer supported by Google.
* Fixed: YouTube embedded videos with additional parameters in the URL not being detected by the Video Sitemap addon.
* Fixed: Uninstalling AIOSEO did not remove user role entries from the database as intended.
* Fixed: Limit Modified Date feature sometimes not working for WooCommerce Products.
* Fixed: Load admin bar assets on the frontend when logged in only if the admin bar is enabled for that user.
* Fixed: Prevent unneeded popup warning on the user profile edit page when leaving without making edits.
* Fixed: Restoring SEO revisions now updates meta keys to ensure localization.
* Fixed: WPML translation to support admin pages in addition to Author/Reviewer Blocks.
* Fixed: Additional keyphrases tooltip cutting off in page builders.
* Fixed: Category in the permalink and breadcrumb did not match when the primary category is removed.
* Fixed: "See Full Bio" link not correctly displaying for reviewers without posts, even when a custom author bio URL is set.
* Fixed: Keyphrase in URL analysis didn't update correctly for auto-draft posts.
* Fixed: Search Statistics now disconnects automatically if there's an authentication error.
* Fixed: Phrase text missing from the Link Assistant's Link Suggestions table.
* Fixed: SERP Preview update when changing primary term for a WooCommerce product.
* Fixed: Updated SERP title to reflect selected primary term for the category when changed.
* Fixed: SiteOrigin integration style conflict to prevent overlap with other modals.
* Fixed: Images using the Post SEO Title smart tag were sometimes not parsed correctly.
* Fixed: URL count for the root sitemap sometimes not entirely accurate.
* Fixed: Robots.txt settings not correctly synced between multisite network and main site.
**New in Version 4.8.0**
* New: Crawl Optimization Improvements - We've added even more features to Crawl Cleanup to help you block unwanted bots from indexing your site and prevent spammers from abusing your internal site search results.
* Fixed: TruSEO Highlighter not always working correctly when post content contains an empty or reusable block.
**New in Version 4.7.9.1**
* Updated: Removed the Search Statistics menu item under Dashboard menu.
**New in Version 4.7.9**
* Updated: Schema product suggestedMinAge/suggestedMaxAge properties to conform with Google's structured data merchant listing requirements.
* Updated: Added a button to apply new headlines directly to the post title inside the Headline Analyzer.
* Updated: TruSEO now supports additional ACF Custom Field types.
* Updated: Exported JSON/CSV files now include the post title and term name columns.
* Updated: Improved handling of Focus Keyphrase errors from Semrush API.
* Updated: Turned off autoloading by default for a number of AIOSEO options to improve performance.
* Fixed: Access control role check to properly verify if the role has edit_post permissions.
* Fixed: Existing additional sitemap pages with different priority, frequency, or last modified values were not getting updated when importing a CSV file.
* Fixed: Tabs were not displaying active status correctly when using RTL due to CSS conflicts.
* Fixed: Image title sometimes duplicated when using Elementor page builder.
* Fixed: Alt text settings were not applied to images when showing latest posts on the homepage.
* Fixed: Excluded posts/terms would sometimes not be correctly excluded from sitemaps.
* Fixed: SERP Preview disappearing when using numeric custom fields in ACF.
* Fixed: Filenames duplicated in rare cases when Strip Punctuation is enabled in Image SEO.
* Fixed: Adding links to WordPress Gallery Block would sometimes not work when Strip Punctuation is enabled in Image SEO.
* Fixed: Trailing slash added to a redirect's target URL even if the URL is external.
* Fixed: Orphaned Posts filter not working correctly in the Link Assistant.
* Fixed: Table of Content block's heading could sometimes break when adding a link from Link Assistant.
* Fixed: "Don't update the modified date" checkbox now works properly in post's quick edit screen.
* Fixed: Missing tooltip for the AI Title/Description Generator modal.
* Fixed: Headlines that couldn't be analyzed would sometimes break the Headline Analyzer UI.
* Fixed: Automatic 404 redirects no longer affecting the dedicated HTML sitemap page.
* Fixed: Canonical URL sometimes missing a slash for paged taxonomy terms.
* Fixed: Canonical URL for a term could sometimes fail if the global query changed.
**New in Version 4.7.8**
* New: Keyword Rank Tracker Improvements - Import your best performing keywords directly from Google Search Console and explore Related Keywords to discover new keyword opportunities!
* New: WooCommerce Product Attributes Support - Per popular demand, you can now control the SEO of your product attributes and include them in your sitemap to increase discoverability.
* Updated: Added filter to control maximum number of additional keywords per post.
**See our [changelog on aioseo.com](https://aioseo.com/changelog/?utm_source=wprepo&utm_medium=link&utm_campaign=aioseo) for previous releases.**
== Frequently Asked Questions ==
Please visit our [complete AIOSEO documentation](https://aioseo.com/docs/?utm_source=wprepo&utm_medium=link&utm_campaign=liteplugin) before requesting support for SEO from the AIOSEO team.
= Who should use AIOSEO? =
SEO is essential for all websites. AIOSEO is perfect for business owners, bloggers, marketers, designers, developers, photographers, and basically everyone else. If you want to rank higher in search, then you need to use AIOSEO WordPress SEO plugin.
= Which themes does AIOSEO support? =
AIOSEO works with all WordPress themes. Simply enable AIOSEO to make your WordPress theme SEO friendly.
= Will AIOSEO slow down my website? =
Nope, AIOSEO will NOT slow down your website. We understand that speed is important for SEO, that's why our code is properly optimized for maximum performance. Remember, faster websites rank higher in search. Use AIOSEO for fast SEO improvements.
= Can I use AIOSEO on client sites? =
Yes, you can use AIOSEO on client websites.
= Are AIOSEO sitemaps better than default WordPress sitemaps? =
Yes, AIOSEO smart sitemaps are a lot more optimized than the default WordPress sitemaps. Once you enable AIOSEO, our XML sitemaps will override the default WordPress sitemaps, so you can improve your SEO rankings.
We also offer advanced SEO sitemaps such as News Sitemap, Video Sitemap, and RSS Sitemap.
Our SEO sitemaps come with granular control such as links per sitemap, enable / disable post types or taxonomies, include / exclude specific links from sitemap, add additional non-WordPress pages to sitemaps, customize sitemap priority & frequency for each section of your site, and more.
This is why experts rate AIOSEO as the best WordPress SEO plugin.
= Does AIOSEO help with SEO Verification? =
Yes. AIOSEO can help you with website SEO verification with various webmaster tools such as Google Search Console, Bing Webmaster Tools, Yandex, Baidu, Pinterest, and just about every other site verification you need.
= Why is AIOSEO better than other SEO plugins? =
There are many WordPress SEO plugins out there. Unlike others, AIOSEO WordPress SEO plugin is always reliable. Our SEO features are results focused (no bloat), and we offer exceptional customer support.
AIOSEO is the original WordPress SEO plugin, and it's trusted by over 3 million website owners.
= Do I really need an XML Sitemap? =
**Yes! XML Sitemaps help Google and other search engines to find all the pages of your website.**
An XML sitemap is a list of all the content on your website. The sitemap helps search engine bots to easily see all the content on your site in one place, The XML sitemap file is hidden from your human visitors, however search engines like Google can see it.
Without an XML sitemap, some of your web pages may never be included in Google search results, and won't get any traffic.
XML Sitemaps also help you tell Google which pages you DON'T want included in search results. This can help your SEO to prevent keyword cannibalization and duplicate content issues.
As part of your SEO strategy, **an XML sitemap can help you to improve your domain authority and unlock more traffic from Google, Bing and other search engines**.
AIOSEO can easily help you get your sitemaps listed inside Google Search Console so your content can start to get indexed today!
= Does AIOSEO integrate directly with Google Search Console? =
Absolutely! Our integration with Google Search Console allows you to monitor and maintain your website's presence on Google. With our direct integration, you can easily view important information about your website, such as the number of clicks, impressions, and the average position for each keyword that your website's content appears for in Google search results. You can also track your contents page speed using Google's Page Speed Insights directly inside your WordPress dashboard.
Additionally, AIOSEO can also provide you with data on the most frequently used keywords, the most popular pages on your website, and any crawl errors or security issues that may arise. By integrating with Google Search Console, AIOSEO provides website owners with valuable insights that can help to improve SEO and overall online visibility. With this integration, you can track your site's progress over time and make data-driven decisions that will help you achieve your SEO goals.
== Screenshots ==
1. SEO Content Analyzer (Gutenberg)
2. SEO Content Analyzer (Classic Editor)
3. SEO Setup Wizard
4. SEO Site Analysis
5. Webmaster Tools Connect
6. Social Media Integrations
7. Local SEO
8. Sitemaps
9. Search Appearance Settings
10. Robots.txt Editor
11. RSS Content Control
12. Headline Analyzer
13. Redirect Manager
14. Link Assistant
== Upgrade Notice ==
= 4.8.2 =
This update adds major improvements and bug fixes.PK ! p]
all_in_one_seo_pack.phpnu [ .
*
* @since 4.0.0
* @author All in One SEO Team
* @package AIOSEO\Plugin
* @license GPL-3.0+
* @copyright Copyright © 2025, All in One SEO
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
require_once dirname( __FILE__ ) . '/app/init/init.php';
// Check if this plugin should be disabled.
if ( aioseoMaybePluginIsDisabled( __FILE__ ) ) {
return;
}
if ( ! defined( 'AIOSEO_PHP_VERSION_DIR' ) ) {
define( 'AIOSEO_PHP_VERSION_DIR', basename( dirname( __FILE__ ) ) );
}
require_once dirname( __FILE__ ) . '/app/init/notices.php';
require_once dirname( __FILE__ ) . '/app/init/activation.php';
// We require PHP 7.0 or higher for the whole plugin to work.
if ( version_compare( PHP_VERSION, '7.0', '<' ) ) {
add_action( 'admin_notices', 'aioseo_php_notice' );
// Do not process the plugin code further.
return;
}
// We require WordPress 5.3+ for the whole plugin to work.
// Support for 5.3 is scheduled to be dropped in April 2025. 5.4, 5.5 and 5.6 will be dropped at the end of 2025.
global $wp_version; // phpcs:ignore Squiz.NamingConventions.ValidVariableName
if ( version_compare( $wp_version, '5.3', '<' ) ) { // phpcs:ignore Squiz.NamingConventions.ValidVariableName
add_action( 'admin_notices', 'aioseo_wordpress_notice' );
// Do not process the plugin code further.
return;
}
if ( ! defined( 'AIOSEO_DIR' ) ) {
define( 'AIOSEO_DIR', __DIR__ );
}
if ( ! defined( 'AIOSEO_FILE' ) ) {
define( 'AIOSEO_FILE', __FILE__ );
}
// Don't allow multiple versions to be active.
if ( function_exists( 'aioseo' ) ) {
add_action( 'activate_all-in-one-seo-pack/all_in_one_seo_pack.php', 'aioseo_lite_just_activated' );
add_action( 'deactivate_all-in-one-seo-pack/all_in_one_seo_pack.php', 'aioseo_lite_just_deactivated' );
add_action( 'activate_all-in-one-seo-pack-pro/all_in_one_seo_pack.php', 'aioseo_pro_just_activated' );
add_action( 'admin_notices', 'aioseo_lite_notice' );
// Do not process the plugin code further.
return;
}
// We will be deprecating these versions of PHP in the future, so we'll let the user know.
if ( version_compare( PHP_VERSION, '7.4', '<' ) ) {
add_action( 'admin_notices', 'aioseo_php_notice_deprecated' );
}
// Define the class and the function.
// The AIOSEOAbstract class is required here because it can't be autoloaded.
require_once dirname( __FILE__ ) . '/app/AIOSEOAbstract.php';
require_once dirname( __FILE__ ) . '/app/AIOSEO.php';
aioseo();PK ! n
app/Lite/Traits/Options.phpnu [ getDbOptions( $this->optionsName . '_lite' );
// Refactor options.
$this->defaultsMerged = array_replace_recursive( $this->defaults, $this->liteDefaults );
$mergedDefaults = array_replace_recursive(
$this->liteDefaults,
$this->addValueToValuesArray( $this->liteDefaults, $dbOptions )
);
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$dbOptions = array_replace_recursive(
$cachedOptions,
$mergedDefaults
);
aioseo()->core->optionsCache->setOptions( $this->optionsName, $dbOptions );
}
/**
* Merge defaults with liteDefaults.
*
* @since 4.1.4
*
* @return array An array of dafults.
*/
public function getDefaults() {
return array_replace_recursive( parent::getDefaults(), $this->liteDefaults );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @param array|null $options An optional options array.
* @return void
*/
public function update( $optionsName = null, $defaults = null, $options = null ) {
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
// We're creating a new array here because it was setting it by reference.
$cachedOptions = aioseo()->core->optionsCache->getOptions( $this->optionsName );
$optionsBefore = json_decode( wp_json_encode( $cachedOptions ), true );
parent::update( $this->optionsName, $options );
parent::update( $optionsName, $defaults, $optionsBefore );
}
/**
* Updates the options in the database.
*
* @since 4.1.4
*
* @param boolean $force Whether or not to force an immediate save.
* @param string $optionsName An optional option name to update.
* @param string $defaults The defaults to filter the options by.
* @return void
*/
public function save( $force = false, $optionsName = null, $defaults = null ) {
if ( ! $this->shouldSave && ! $force ) {
return;
}
$optionsName = empty( $optionsName ) ? $this->optionsName . '_lite' : $optionsName;
$defaults = empty( $defaults ) ? $this->liteDefaults : $defaults;
parent::save( $force, $this->optionsName );
parent::save( $force, $optionsName, $defaults );
}
}PK ! 86 app/Lite/Utils/Helpers.phpnu [ routes, $this->liteRoutes );
}
}PK ! [xXT T app/Lite/Api/Wizard.phpnu [ get_json_params();
$section = ! empty( $body['section'] ) ? sanitize_text_field( $body['section'] ) : null;
$wizard = ! empty( $body['wizard'] ) ? $body['wizard'] : null;
// Save the smart recommendations section.
if ( 'smartRecommendations' === $section && ! empty( $wizard['smartRecommendations'] ) ) {
$smartRecommendations = $wizard['smartRecommendations'];
if ( isset( $smartRecommendations['usageTracking'] ) ) {
aioseo()->options->advanced->usageTracking = $smartRecommendations['usageTracking'];
}
}
return $response;
}
}PK ! kc9 9 $ app/Lite/Options/InternalOptions.phpnu [ [
'activated' => [ 'type' => 'number', 'default' => 0 ],
'firstActivated' => [ 'type' => 'number', 'default' => 0 ],
'installed' => [ 'type' => 'number', 'default' => 0 ],
'connect' => [
'key' => [ 'type' => 'string' ],
'time' => [ 'type' => 'number', 'default' => 0 ],
'network' => [ 'type' => 'boolean', 'default' => false ],
'token' => [ 'type' => 'string' ]
]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
}PK ! G app/Lite/Options/Options.phpnu [ [
'usageTracking' => [ 'type' => 'boolean', 'default' => false ]
]
// phpcs:enable WordPress.Arrays.ArrayDeclarationSpacing.AssociativeArrayFound
];
/**
* Sanitizes, then saves the options to the database.
*
* @since 4.7.2
*
* @param array $options An array of options to sanitize, then save.
* @return void
*/
public function sanitizeAndSave( $options ) {
if ( isset( $options['advanced']['emailSummary']['recipients'] ) ) {
$options['advanced']['emailSummary']['recipients'] = [ array_shift( $options['advanced']['emailSummary']['recipients'] ) ];
$options['advanced']['emailSummary']['recipients'][0]['frequency'] = 'monthly';
}
parent::sanitizeAndSave( $options );
}
}PK ! =6 app/Lite/Main/Filters.phpnu [ ', 5 );
$actionLinks = [
'suggest-feature' => [
// Translators: This is an action link users can click to open a feature request.
'label' => __( 'Suggest a Feature', 'all-in-one-seo-pack' ),
'url' => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'suggest-a-feature/', 'plugin-row-meta', 'feature' ),
],
'review' => [
'label' => $reviewLabel,
'url' => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'review-aioseo', 'plugin-row-meta', 'review' ),
'title' => sprintf(
// Translators: 1 - The plugin short name ("AIOSEO").
__( 'Rate %1$s', 'all-in-one-seo-pack' ),
'AIOSEO'
)
]
];
return $this->parseActionLinks( $actions, $pluginFile, $actionLinks );
}
/**
* Registers our action links for the plugins page.
*
* @since 4.0.0
*
* @param array $actions List of existing actions.
* @param string $pluginFile The plugin file.
* @return array List of action links.
*/
public function pluginActionLinks( $actions, $pluginFile = '' ) {
$actionLinks = [
'settings' => [
'label' => __( 'SEO Settings', 'all-in-one-seo-pack' ),
'url' => get_admin_url( null, 'admin.php?page=aioseo-settings' ),
],
'support' => [
// Translators: This is an action link users can click to open our premium support.
'label' => __( 'Support', 'all-in-one-seo-pack' ),
'url' => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'contact/', 'plugin-action-links', 'Support' ),
],
'docs' => [
// Translators: This is an action link users can click to open our general documentation page.
'label' => __( 'Documentation', 'all-in-one-seo-pack' ),
'url' => aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'docs/', 'plugin-action-links', 'Documentation' ),
],
'proupgrade' => [
// Translators: This is an action link users can click to purchase a license for All in One SEO Pro.
'label' => __( 'Upgrade to Pro', 'all-in-one-seo-pack' ),
'url' => apply_filters( 'aioseo_upgrade_link', aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'lite-upgrade/', 'plugin-action-links', 'Upgrade', false ) ),
]
];
if ( isset( $actions['edit'] ) ) {
unset( $actions['edit'] );
}
return $this->parseActionLinks( $actions, $pluginFile, $actionLinks, 'before' );
}
}PK ! @f> > " app/Lite/Views/taxonomy-upsell.phpnu [
PK ! vt app/Lite/Admin/PostSettings.phpnu [ label ) ||
! is_taxonomy_viewable( $taxObject )
) {
unset( $taxonomies[ $taxObject->name ] );
}
}
foreach ( $taxonomies as $taxonomy ) {
add_action( $taxonomy->name . '_edit_form', [ $this, 'addTaxonomyUpsell' ] );
add_action( 'after-' . $taxonomy->name . '-table', [ $this, 'addTaxonomyUpsell' ] );
}
}
}
/**
* Add Taxonomy Upsell
*
* @since 4.0.0
*
* @return void
*/
public function addTaxonomyUpsell() {
$screen = aioseo()->helpers->getCurrentScreen();
if (
! isset( $screen->parent_base ) ||
'edit' !== $screen->parent_base ||
empty( $screen->taxonomy )
) {
return;
}
include_once AIOSEO_DIR . '/app/Lite/Views/taxonomy-upsell.php';
}
}PK ! (&. &. app/Lite/Admin/Connect.phpnu [ loadConnectPro();
return;
}
$this->loadConnect();
// phpcs:enable
}
/**
* Load the Connect template.
*
* @since 4.0.0
*
* @return void
*/
private function loadConnect() {
$this->enqueueScripts();
$this->connectHeader();
$this->connectContent();
$this->connectFooter();
exit;
}
/**
* Load the Connect Pro template.
*
* @since 4.0.0
*
* @return void
*/
private function loadConnectPro() {
$this->enqueueScriptsPro();
$this->connectHeader();
$this->connectContent();
$this->connectFooter( 'pro' );
exit;
}
/**
* Enqueue's scripts for the setup wizard.
*
* @since 4.0.0
*
* @return void
*/
public function enqueueScripts() {
// We don't want any plugin adding notices to our screens. Let's clear them out here.
remove_all_actions( 'admin_notices' );
remove_all_actions( 'network_admin_notices' );
remove_all_actions( 'all_admin_notices' );
aioseo()->core->assets->load( 'src/vue/standalone/connect/main.js', [], aioseo()->helpers->getVueData() );
}
/**
* Enqueue's scripts for the setup wizard.
*
* @since 4.0.0
*
* @return void
*/
public function enqueueScriptsPro() {
// We don't want any plugin adding notices to our screens. Let's clear them out here.
remove_all_actions( 'admin_notices' );
remove_all_actions( 'network_admin_notices' );
remove_all_actions( 'all_admin_notices' );
aioseo()->core->assets->load( 'src/vue/standalone/connect-pro/main.js', [], aioseo()->helpers->getVueData() );
}
/**
* Outputs the simplified header used for the Onboarding Wizard.
*
* @since 4.0.0
*
* @return void
*/
public function connectHeader() {
?>
>
';
aioseo()->templates->getTemplate( 'admin/settings-page.php' );
echo '';
}
/**
* Outputs the simplified footer used for the Onboarding Wizard.
*
* @since 4.0.0
*
* @return void
*/
public function connectFooter( $pro = '' ) {
?>
esc_html__( 'You are not allowed to install plugins.', 'all-in-one-seo-pack' )
];
}
if ( empty( $key ) ) {
return [
'error' => esc_html__( 'Please enter your license key to connect.', 'all-in-one-seo-pack' ),
];
}
// Verify pro version is not installed.
$active = activate_plugin( 'all-in-one-seo-pack-pro/all_in_one_seo_pack_pro', false, false, true );
if ( ! is_wp_error( $active ) ) {
return [
'error' => esc_html__( 'Pro version is already installed.', 'all-in-one-seo-pack' )
];
}
// Just check if network is set.
$network = isset( $_POST['network'] ) ? (bool) sanitize_text_field( wp_unslash( $_POST['network'] ) ) : false; // phpcs:ignore HM.Security.ValidatedSanitizedInput.InputNotSanitized, HM.Security.NonceVerification.Missing, WordPress.Security.NonceVerification, Generic.Files.LineLength.MaxExceeded
$network = ! empty( $network );
// Generate a hash that can be compared after the user is redirected back.
$oth = hash( 'sha512', wp_rand() );
$hashedOth = hash_hmac( 'sha512', $oth, wp_salt() );
// Save the options.
aioseo()->internalOptions->internal->connect->key = $key;
aioseo()->internalOptions->internal->connect->time = time();
aioseo()->internalOptions->internal->connect->network = $network;
aioseo()->internalOptions->internal->connect->token = $oth;
$url = add_query_arg( [
'key' => $key,
'network' => $network,
'token' => $hashedOth,
'version' => aioseo()->version,
'siteurl' => admin_url(),
'homeurl' => home_url(),
'endpoint' => admin_url( 'admin-ajax.php' ),
'php' => PHP_VERSION,
'wp' => get_bloginfo( 'version' ),
'redirect' => rawurldecode( base64_encode( $redirect ? $redirect : admin_url( 'admin.php?page=aioseo-settings' ) ) ),
'v' => 1,
], defined( 'AIOSEO_UPGRADE_URL' ) ? AIOSEO_UPGRADE_URL : 'https://upgrade.aioseo.com' );
// We're storing the ID of the user who is installing Pro so that we can add capabilties for him after upgrading.
aioseo()->core->cache->update( 'connect_active_user', get_current_user_id(), 15 * MINUTE_IN_SECONDS );
return [
'url' => $url,
];
}
/**
* Process AIOSEO Connect.
*
* @since 1.0.0
*
* @return array An array containing a valid response or an error message.
*/
public function process() {
// phpcs:disable HM.Security.NonceVerification.Missing, WordPress.Security.NonceVerification
$hashedOth = ! empty( $_POST['token'] ) ? sanitize_text_field( wp_unslash( $_POST['token'] ) ) : '';
$downloadUrl = ! empty( $_POST['file'] ) ? esc_url_raw( wp_unslash( $_POST['file'] ) ) : '';
// phpcs:enable
$error = sprintf(
// Translators: 1 - The marketing site domain ("aioseo.com").
esc_html__( 'Could not install upgrade. Please download from %1$s and install manually.', 'all-in-one-seo-pack' ),
esc_html( AIOSEO_MARKETING_DOMAIN )
);
$success = esc_html__( 'Plugin installed & activated.', 'all-in-one-seo-pack' );
// Check if all required params are present.
if ( empty( $downloadUrl ) || empty( $hashedOth ) ) {
wp_send_json_error( $error );
}
$oth = aioseo()->internalOptions->internal->connect->token;
if ( empty( $oth ) ) {
wp_send_json_error( $error );
}
// Check if the stored hash matches the salted one that is sent back from the server.
if ( hash_hmac( 'sha512', $oth, wp_salt() ) !== $hashedOth ) {
wp_send_json_error( $error );
}
// Delete connect token so we don't replay.
aioseo()->internalOptions->internal->connect->token = null;
// Verify pro not activated.
if ( aioseo()->pro ) {
wp_send_json_success( $success );
}
// Check license key.
$licenseKey = aioseo()->internalOptions->internal->connect->key;
if ( ! $licenseKey ) {
wp_send_json_error( esc_html__( 'You are not licensed.', 'all-in-one-seo-pack' ) );
}
// Set the license key in a new option so we can get it when Pro is activated.
aioseo()->internalOptions->internal->validLicenseKey = $licenseKey;
require_once ABSPATH . 'wp-admin/includes/file.php';
require_once ABSPATH . 'wp-admin/includes/class-wp-screen.php';
require_once ABSPATH . 'wp-admin/includes/screen.php';
// Set the current screen to avoid undefined notices.
set_current_screen( 'toplevel_page_aioseo' );
// Prepare variables.
$url = esc_url_raw(
add_query_arg(
[
'page' => 'aioseo-settings',
],
admin_url( 'admin.php' )
)
);
// Verify pro not installed.
$network = aioseo()->internalOptions->internal->connect->network;
$active = activate_plugin( 'all-in-one-seo-pack-pro/all_in_one_seo_pack.php', $url, $network, true );
if ( ! is_wp_error( $active ) ) {
aioseo()->internalOptions->internal->connect->reset();
// Because the regular activation hooks won't run, we need to add capabilities for the installing user so that he doesn't run into an error on the first request.
aioseo()->activate->addCapabilitiesOnUpgrade();
wp_send_json_success( $success );
}
$creds = request_filesystem_credentials( $url, '', false, false, null );
// Check for file system permissions.
if ( false === $creds ) {
wp_send_json_error( $error );
}
$fs = aioseo()->core->fs->noConflict();
$fs->init( $creds );
if ( ! $fs->isWpfsValid() ) {
wp_send_json_error( $error );
}
// Do not allow WordPress to search/download translations, as this will break JS output.
remove_action( 'upgrader_process_complete', [ 'Language_Pack_Upgrader', 'async_upgrade' ], 20 );
// Create the plugin upgrader with our custom skin.
$installer = new Utils\PluginUpgraderSilentAjax( new Utils\PluginUpgraderSkin() );
// Error check.
if ( ! method_exists( $installer, 'install' ) ) {
wp_send_json_error( $error );
}
$installer->install( $downloadUrl );
// Flush the cache and return the newly installed plugin basename.
wp_cache_flush();
$pluginBasename = $installer->plugin_info();
if ( ! $pluginBasename ) {
wp_send_json_error( $error );
}
// Activate the plugin silently.
$activated = activate_plugin( $pluginBasename, '', $network, true );
if ( is_wp_error( $activated ) ) {
wp_send_json_error( esc_html__( 'The Pro version installed correctly, but it needs to be activated from the Plugins page inside your WordPress admin.', 'all-in-one-seo-pack' ) );
}
aioseo()->internalOptions->internal->connect->reset();
// Because the regular activation hooks won't run, we need to add capabilities for the installing user so that he doesn't run into an error on the first request.
aioseo()->activate->addCapabilitiesOnUpgrade();
wp_send_json_success( $success );
}
}PK ! :x " app/Lite/Admin/Notices/Notices.phpnu [ wooUpsellNotice();
}
/**
* Validates the notification type.
*
* @since 4.0.0
*
* @param string $type The notification type we are targeting.
* @return boolean True if yes, false if no.
*/
public function validateType( $type ) {
$validated = parent::validateType( $type );
// Any lite notification should pass here.
if ( 'lite' === $type ) {
$validated = true;
}
return $validated;
}
/**
* Add a notice if WooCommerce is detected and not licensed or running Lite.
*
* @since 4.0.0
*
* @return void
*/
private function wooUpsellNotice() {
$notification = Models\Notification::getNotificationByName( 'woo-upsell' );
if (
! class_exists( 'WooCommerce' )
) {
if ( $notification->exists() ) {
Models\Notification::deleteNotificationByName( 'woo-upsell' );
}
return;
}
if ( $notification->exists() ) {
return;
}
Models\Notification::addNotification( [
'slug' => uniqid(),
'notification_name' => 'woo-upsell',
// Translators: 1 - "WooCommerce".
'title' => sprintf( __( 'Advanced %1$s Support', 'all-in-one-seo-pack' ), 'WooCommerce' ),
// Translators: 1 - "WooCommerce", 2 - The plugin short name ("AIOSEO").
'content' => sprintf( __( 'We have detected you are running %1$s. Upgrade to %2$s to unlock our advanced eCommerce SEO features, including SEO for Product Categories and more.', 'all-in-one-seo-pack' ), 'WooCommerce', AIOSEO_PLUGIN_SHORT_NAME . ' Pro' ), // phpcs:ignore Generic.Files.LineLength.MaxExceeded
'type' => 'info',
'level' => [ 'all' ],
// Translators: 1 - "Pro".
'button1_label' => sprintf( __( 'Upgrade to %1$s', 'all-in-one-seo-pack' ), 'Pro' ),
'button1_action' => html_entity_decode( apply_filters( 'aioseo_upgrade_link', aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'lite-upgrade/', 'woo-notification-upsell', false ) ) ),
'start' => gmdate( 'Y-m-d H:i:s' )
] );
}
}PK ! gͭN N app/Lite/Admin/Usage.phpnu [ enabled = aioseo()->options->advanced->usageTracking;
}
/**
* Get the type for the request.
*
* @since 4.0.0
*
* @return string The install type.
*/
public function getType() {
return 'lite';
}
}PK ! ʾ
app/Lite/Admin/Admin.phpnu [ connect = new Connect();
}
/**
* Actually adds the menu items to the admin bar.
*
* @since 4.0.0
*
* @return void
*/
protected function addAdminBarMenuItems() {
// Add an upsell to Pro.
if ( current_user_can( $this->getPageRequiredCapability( '' ) ) ) {
$this->adminBarMenuItems['aioseo-pro-upgrade'] = [
'parent' => 'aioseo-main',
'title' => '',
'id' => 'aioseo-pro-upgrade',
'href' => apply_filters(
'aioseo_upgrade_link',
esc_url( admin_url( 'admin.php?page=aioseo-tools&aioseo-redirect-upgrade=1' ) )
),
'meta' => [ 'target' => '_blank' ],
];
}
parent::addAdminBarMenuItems();
}
/**
* Add the menu inside of WordPress.
*
* @since 4.0.0
*
* @return void
*/
public function addMenu() {
parent::addMenu();
$capability = $this->getPageRequiredCapability( '' );
// We use the global submenu, because we are adding an external link here.
if ( current_user_can( $capability ) ) {
global $submenu;
$submenu[ $this->pageSlug ][] = [
'',
$capability,
apply_filters(
'aioseo_upgrade_link',
esc_url( admin_url( 'admin.php?page=aioseo-tools&aioseo-redirect-upgrade=1' ) )
)
];
}
}
/**
* Check the query args to see if we need to redirect to an external URL.
*
* @since 4.2.3
*
* @return void
*/
protected function checkForRedirects() {
$mappedUrls = [
// Added to resolve an issue with the open_basedir in the IIS.
// https://github.com/awesomemotive/aioseo/issues/3243
'aioseo-redirect-upgrade' => apply_filters(
'aioseo_upgrade_link',
aioseo()->helpers->utmUrl( AIOSEO_MARKETING_URL . 'lite-upgrade/', 'admin-bar', null, false )
)
];
foreach ( $mappedUrls as $queryArg => $redirectUrl ) {
if ( isset( $_GET[ $queryArg ] ) ) { // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
wp_redirect( $redirectUrl );
}
}
}
}PK ! S;2 2 app/AIOSEO.phpnu [ init();
// Load our addons on the action right after plugins_loaded.
add_action( 'sanitize_comment_cookies', [ self::$instance, 'loadAddons' ] );
}
return self::$instance;
}
/**
* Initialize All in One SEO!
*
* @since 4.0.0
*
* @return void
*/
private function init() {
$this->constants();
$this->includes();
$this->preLoad();
if ( ! $this->core->isUninstalling() ) {
$this->load();
}
}
/**
* Setup plugin constants.
* All the path/URL related constants are defined in main plugin file.
*
* @since 4.0.0
*
* @return void
*/
private function constants() {
$defaultHeaders = [
'name' => 'Plugin Name',
'version' => 'Version',
];
$pluginData = get_file_data( AIOSEO_FILE, $defaultHeaders );
$constants = [
'AIOSEO_PLUGIN_BASENAME' => plugin_basename( AIOSEO_FILE ),
'AIOSEO_PLUGIN_NAME' => $pluginData['name'],
'AIOSEO_PLUGIN_SHORT_NAME' => 'AIOSEO',
'AIOSEO_PLUGIN_URL' => plugin_dir_url( AIOSEO_FILE ),
'AIOSEO_VERSION' => $pluginData['version'],
'AIOSEO_MARKETING_URL' => 'https://aioseo.com/',
'AIOSEO_MARKETING_DOMAIN' => 'aioseo.com'
];
foreach ( $constants as $constant => $value ) {
if ( ! defined( $constant ) ) {
define( $constant, $value );
}
}
$this->version = AIOSEO_VERSION;
}
/**
* Including the new files with PHP 5.3 style.
*
* @since 4.0.0
*
* @return void
*/
private function includes() {
$dependencies = [
'/vendor/autoload.php' => true,
'/vendor/woocommerce/action-scheduler/action-scheduler.php' => true,
'/vendor/jwhennessey/phpinsight/autoload.php' => false,
'/vendor_prefixed/monolog/monolog/src/Monolog/Logger.php' => false
];
foreach ( $dependencies as $path => $shouldRequire ) {
if ( ! file_exists( AIOSEO_DIR . $path ) ) {
// Something is not right.
status_header( 500 );
wp_die( esc_html__( 'Plugin is missing required dependencies. Please contact support for more information.', 'all-in-one-seo-pack' ) );
}
if ( $shouldRequire ) {
require_once AIOSEO_DIR . $path;
}
}
$this->loadVersion();
}
/**
* Load the version of the plugin we are currently using.
*
* @since 4.1.9
*
* @return void
*/
private function loadVersion() {
$proDir = is_dir( plugin_dir_path( AIOSEO_FILE ) . 'app/Pro' );
if (
! class_exists( '\Dotenv\Dotenv' ) ||
! file_exists( AIOSEO_DIR . '/build/.env' )
) {
$this->pro = $proDir;
$this->versionPath = $proDir ? 'Pro' : 'Lite';
return;
}
$dotenv = \Dotenv\Dotenv::createUnsafeImmutable( AIOSEO_DIR, '/build/.env' );
$dotenv->load();
$version = defined( 'AIOSEO_DEV_VERSION' )
? strtolower( AIOSEO_DEV_VERSION )
: strtolower( getenv( 'VITE_VERSION' ) );
if ( ! empty( $version ) ) {
$this->isDev = true;
if ( file_exists( AIOSEO_DIR . '/build/filters.php' ) ) {
require_once AIOSEO_DIR . '/build/filters.php';
}
}
if ( $proDir && 'pro' === $version ) {
$this->pro = true;
$this->versionPath = 'Pro';
}
}
/**
* Runs before we load the plugin.
*
* @since 4.0.0
*
* @return void
*/
private function preLoad() {
$this->core = new Common\Core\Core();
$this->backwardsCompatibility();
// Internal Options.
$this->helpers = $this->pro ? new Pro\Utils\Helpers() : new Lite\Utils\Helpers();
$this->internalNetworkOptions = ( $this->pro && $this->helpers->isPluginNetworkActivated() ) ? new Pro\Options\InternalNetworkOptions() : new Common\Options\InternalNetworkOptions();
$this->internalOptions = $this->pro ? new Pro\Options\InternalOptions() : new Lite\Options\InternalOptions();
$this->uninstall = new Common\Main\Uninstall();
// Run pre-updates.
$this->preUpdates = $this->pro ? new Pro\Main\PreUpdates() : new Common\Main\PreUpdates();
}
/**
* To prevent errors and bugs from popping up,
* we will run this backwards compatibility method.
*
* @since 4.1.9
*
* @return void
*/
private function backwardsCompatibility() {
$this->db = $this->core->db;
$this->cache = $this->core->cache;
$this->transients = $this->cache;
$this->cachePrune = $this->core->cachePrune;
$this->optionsCache = $this->core->optionsCache;
}
/**
* To prevent errors and bugs from popping up,
* we will run this backwards compatibility method.
*
* @since 4.2.0
*
* @return void
*/
private function backwardsCompatibilityLoad() {
$this->postSettings->integrations = $this->standalone->pageBuilderIntegrations;
}
/**
* Load our classes.
*
* @since 4.0.0
*
* @return void
*/
public function load() {
// Load external translations if this is a Pro install.
if ( $this->pro ) {
$translations = new Pro\Main\Translations(
'plugin',
'all-in-one-seo-pack',
'https://aioseo.com/aioseo-plugin/all-in-one-seo-pack/packages.json'
);
$translations->init();
$translations = new Pro\Main\Translations(
'plugin',
'aioseo-pro',
'https://aioseo.com/aioseo-plugin/aioseo-pro/packages.json'
);
$translations->init();
}
$this->addons = $this->pro ? new Pro\Utils\Addons() : new Common\Utils\Addons();
$this->features = $this->pro ? new Pro\Utils\Features() : new Common\Utils\Features();
$this->tags = $this->pro ? new Pro\Utils\Tags() : new Common\Utils\Tags();
$this->blocks = new Common\Utils\Blocks();
$this->badBotBlocker = new Common\Tools\BadBotBlocker();
$this->breadcrumbs = $this->pro ? new Pro\Breadcrumbs\Breadcrumbs() : new Common\Breadcrumbs\Breadcrumbs();
$this->dynamicBackup = $this->pro ? new Pro\Options\DynamicBackup() : new Common\Options\DynamicBackup();
$this->options = $this->pro ? new Pro\Options\Options() : new Lite\Options\Options();
$this->networkOptions = ( $this->pro && $this->helpers->isPluginNetworkActivated() ) ? new Pro\Options\NetworkOptions() : new Common\Options\NetworkOptions();
$this->dynamicOptions = $this->pro ? new Pro\Options\DynamicOptions() : new Common\Options\DynamicOptions();
$this->backup = new Common\Utils\Backup();
$this->access = $this->pro ? new Pro\Utils\Access() : new Common\Utils\Access();
$this->usage = $this->pro ? new Pro\Admin\Usage() : new Lite\Admin\Usage();
$this->siteHealth = $this->pro ? new Pro\Admin\SiteHealth() : new Common\Admin\SiteHealth();
$this->networkLicense = $this->pro && $this->helpers->isPluginNetworkActivated() ? new Pro\Admin\NetworkLicense() : null;
$this->license = $this->pro ? new Pro\Admin\License() : null;
$this->autoUpdates = $this->pro ? new Pro\Admin\AutoUpdates() : null;
$this->updates = $this->pro ? new Pro\Main\Updates() : new Common\Main\Updates();
$this->meta = $this->pro ? new Pro\Meta\Meta() : new Common\Meta\Meta();
$this->social = $this->pro ? new Pro\Social\Social() : new Common\Social\Social();
$this->robotsTxt = new Common\Tools\RobotsTxt();
$this->htaccess = new Common\Tools\Htaccess();
$this->term = $this->pro ? new Pro\Admin\Term() : null;
$this->notices = $this->pro ? new Pro\Admin\Notices\Notices() : new Lite\Admin\Notices\Notices();
$this->wpNotices = new Common\Admin\Notices\WpNotices();
$this->admin = $this->pro ? new Pro\Admin\Admin() : new Lite\Admin\Admin();
$this->networkAdmin = $this->helpers->isPluginNetworkActivated() ? ( $this->pro ? new Pro\Admin\NetworkAdmin() : new Common\Admin\NetworkAdmin() ) : null;
$this->activate = $this->pro ? new Pro\Main\Activate() : new Common\Main\Activate();
$this->conflictingPlugins = $this->pro ? new Pro\Admin\ConflictingPlugins() : new Common\Admin\ConflictingPlugins();
$this->migration = $this->pro ? new Pro\Migration\Migration() : new Common\Migration\Migration();
$this->importExport = $this->pro ? new Pro\ImportExport\ImportExport() : new Common\ImportExport\ImportExport();
$this->sitemap = $this->pro ? new Pro\Sitemap\Sitemap() : new Common\Sitemap\Sitemap();
$this->htmlSitemap = new Common\Sitemap\Html\Sitemap();
$this->templates = $this->pro ? new Pro\Utils\Templates() : new Common\Utils\Templates();
$this->categoryBase = new Common\Main\CategoryBase();
$this->postSettings = $this->pro ? new Pro\Admin\PostSettings() : new Lite\Admin\PostSettings();
$this->standalone = new Common\Standalone\Standalone();
$this->searchStatistics = $this->pro ? new Pro\SearchStatistics\SearchStatistics() : new Common\SearchStatistics\SearchStatistics();
$this->slugMonitor = new Common\Admin\SlugMonitor();
$this->schema = $this->pro ? new Pro\Schema\Schema() : new Common\Schema\Schema();
$this->actionScheduler = new Common\Utils\ActionScheduler();
$this->seoRevisions = $this->pro ? new Pro\SeoRevisions\SeoRevisions() : new Common\SeoRevisions\SeoRevisions();
$this->ai = $this->pro ? new Pro\Ai\Ai() : null;
$this->filters = $this->pro ? new Pro\Main\Filters() : new Lite\Main\Filters();
$this->crawlCleanup = new Common\QueryArgs\CrawlCleanup();
$this->searchCleanup = new Common\SearchCleanup\SearchCleanup();
$this->emailReports = new Common\EmailReports\EmailReports();
$this->thirdParty = new Common\ThirdParty\ThirdParty();
$this->writingAssistant = new Common\WritingAssistant\WritingAssistant();
if ( ! wp_doing_ajax() && ! wp_doing_cron() ) {
$this->rss = new Common\Rss();
$this->main = $this->pro ? new Pro\Main\Main() : new Common\Main\Main();
$this->head = $this->pro ? new Pro\Main\Head() : new Common\Main\Head();
$this->dashboard = $this->pro ? new Pro\Admin\Dashboard() : new Common\Admin\Dashboard();
$this->api = $this->pro ? new Pro\Api\Api() : new Lite\Api\Api();
$this->help = new Common\Help\Help();
}
$this->backwardsCompatibilityLoad();
add_action( 'init', [ $this, 'loadInit' ], 999 );
}
/**
* Things that need to load after init.
*
* @since 4.0.0
*
* @return void
*/
public function loadInit() {
$this->settings = new Common\Utils\VueSettings( '_aioseo_settings' );
$this->sitemap->init();
$this->badBotBlocker->init();
// We call this again to reset any post types/taxonomies that have not yet been set up.
$this->dynamicOptions->refresh();
}
/**
* Loads our addons.
*
* Runs right after the plugins_loaded hook.
*
* @since 4.0.0
*
* @return void
*/
public function loadAddons() {
do_action( 'aioseo_loaded' );
}
}
}
namespace {
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* The function which returns the one AIOSEO instance.
*
* @since 4.0.0
*
* @return AIOSEO\Plugin\AIOSEO The instance.
*/
function aioseo() {
return AIOSEO\Plugin\AIOSEO::instance();
}
}PK ! ]z app/Common/Social/Image.phpnu [ type = $type;
$this->post = $post;
$this->thumbnailSize = apply_filters( 'aioseo_thumbnail_size', 'fullsize' );
$hash = md5( wp_json_encode( [ $type, $imageSource, $post ] ) );
static $images = [];
if ( isset( $images[ $hash ] ) ) {
return $images[ $hash ];
}
if ( 'auto' === $imageSource && aioseo()->helpers->getPostPageBuilderName( $post->ID ) ) {
$imageSource = 'default';
}
if ( is_a( $this->post, 'WP_Post' ) ) {
switch ( $imageSource ) {
case 'featured':
$image = $this->getFeaturedImage();
break;
case 'attach':
$image = $this->getFirstAttachedImage();
break;
case 'content':
$image = $this->getFirstImageInContent();
break;
case 'author':
$image = $this->getAuthorAvatar();
break;
case 'auto':
$image = $this->getFirstAvailableImage();
break;
case 'custom':
$image = $this->getCustomFieldImage();
break;
case 'custom_image':
$metaData = aioseo()->meta->metaData->getMetaData( $post );
if ( empty( $metaData ) ) {
break;
}
$image = 'facebook' === strtolower( $this->type )
? $metaData->og_image_custom_url
: $metaData->twitter_image_custom_url;
break;
case 'default':
default:
$image = aioseo()->options->social->{$this->type}->general->defaultImagePosts;
}
}
if ( empty( $image ) ) {
$image = aioseo()->options->social->{$this->type}->general->defaultImagePosts;
}
if ( is_array( $image ) ) {
$images[ $hash ] = $image;
return $images[ $hash ];
}
$imageWithoutDimensions = aioseo()->helpers->removeImageDimensions( $image );
$attachmentId = aioseo()->helpers->attachmentUrlToPostId( $imageWithoutDimensions );
$images[ $hash ] = $attachmentId ? wp_get_attachment_image_src( $attachmentId, $this->thumbnailSize ) : $image;
return $images[ $hash ];
}
/**
* Returns the Featured Image for the post.
*
* @since 4.0.0
*
* @return array The image data.
*/
private function getFeaturedImage() {
$cachedImage = $this->getCachedImage();
if ( $cachedImage ) {
return $cachedImage;
}
$imageId = get_post_thumbnail_id( $this->post->ID );
return $imageId ? wp_get_attachment_image_src( $imageId, $this->thumbnailSize ) : '';
}
/**
* Returns the first attached image.
*
* @since 4.0.0
*
* @return string The image data.
*/
private function getFirstAttachedImage() {
$cachedImage = $this->getCachedImage();
if ( $cachedImage ) {
return $cachedImage;
}
if ( 'attachment' === get_post_type( $this->post->ID ) ) {
return wp_get_attachment_image_src( $this->post->ID, $this->thumbnailSize );
}
$attachments = get_children(
[
'post_parent' => $this->post->ID,
'post_status' => 'inherit',
'post_type' => 'attachment',
'post_mime_type' => 'image',
]
);
return $attachments && count( $attachments ) ? wp_get_attachment_image_src( array_values( $attachments )[0]->ID, $this->thumbnailSize ) : '';
}
/**
* Returns the first image found in the post content.
*
* @since 4.0.0
*
* @return string The image URL.
*/
private function getFirstImageInContent() {
$cachedImage = $this->getCachedImage();
if ( $cachedImage ) {
return $cachedImage;
}
$postContent = aioseo()->helpers->getPostContent( $this->post );
preg_match_all( '||i', (string) $postContent, $matches ); // phpcs:ignore PluginCheck.CodeAnalysis.ImageFunctions.NonEnqueuedImage
// Ignore cover block background image - WP >= 5.7.
if ( ! empty( $matches[0] ) && apply_filters( 'aioseo_social_image_ignore_cover_block', true, $this->post, $matches ) ) {
foreach ( $matches[0] as $key => $match ) {
if ( false !== stripos( $match, 'wp-block-cover__image-background' ) ) {
unset( $matches[1][ $key ] );
}
}
}
return ! empty( $matches[1] ) ? current( $matches[1] ) : '';
}
/**
* Returns the author avatar.
*
* @since 4.0.0
*
* @return string The image URL.
*/
private function getAuthorAvatar() {
$avatar = get_avatar( $this->post->post_author, 300 );
preg_match( "/src='(.*?)'/i", (string) $avatar, $matches );
return ! empty( $matches[1] ) ? $matches[1] : '';
}
/**
* Returns the first available image.
*
* @since 4.0.0
*
* @return string The image URL.
*/
private function getFirstAvailableImage() {
// Disable the cache.
$this->useCache = false;
$image = $this->getCustomFieldImage();
if ( ! $image ) {
$image = $this->getFeaturedImage();
}
if ( ! $image ) {
$image = $this->getFirstAttachedImage();
}
if ( ! $image ) {
$image = $this->getFirstImageInContent();
}
if ( ! $image && 'twitter' === strtolower( $this->type ) ) {
$image = aioseo()->options->social->twitter->homePage->image;
}
// Enable the cache.
$this->useCache = true;
return $image ? $image : aioseo()->options->social->facebook->homePage->image;
}
/**
* Returns the image from a custom field.
*
* @since 4.0.0
*
* @return string The image URL.
*/
private function getCustomFieldImage() {
$cachedImage = $this->getCachedImage();
if ( $cachedImage ) {
return $cachedImage;
}
$prefix = 'facebook' === strtolower( $this->type ) ? 'og_' : 'twitter_';
$aioseoPost = Models\Post::getPost( $this->post->ID );
$customFields = ! empty( $aioseoPost->{ $prefix . 'image_custom_fields' } )
? $aioseoPost->{ $prefix . 'image_custom_fields' }
: aioseo()->options->social->{$this->type}->general->customFieldImagePosts;
if ( ! $customFields ) {
return '';
}
$customFields = explode( ',', $customFields );
foreach ( $customFields as $customField ) {
$image = get_post_meta( $this->post->ID, $customField, true );
if ( ! empty( $image ) ) {
$image = is_array( $image ) ? $image[0] : $image;
return is_numeric( $image )
? wp_get_attachment_image_src( $image, $this->thumbnailSize )
: $image;
}
}
return '';
}
/**
* Returns the cached image if there is one.
*
* @since 4.1.6.2
*
* @param \WP_Term $object The object for which we need to get the cached image.
* @return string|array The image URL or data.
*/
protected function getCachedImage( $object = null ) {
if ( null === $object ) {
// This isn't null if we call it from the Pro class.
$object = $this->post;
}
$metaData = aioseo()->meta->metaData->getMetaData( $object );
switch ( $this->type ) {
case 'facebook':
if ( ! empty( $metaData->og_image_url ) && $this->useCache ) {
return aioseo()->meta->metaData->getCachedOgImage( $metaData );
}
break;
case 'twitter':
if ( ! empty( $metaData->twitter_image_url ) && $this->useCache ) {
return $metaData->twitter_image_url;
}
break;
default:
break;
}
return '';
}
}PK ! W% app/Common/Social/Social.phpnu [ image = new Image();
if ( wp_doing_ajax() || wp_doing_cron() ) {
return;
}
$this->facebook = new Facebook();
$this->twitter = new Twitter();
$this->output = new Output();
$this->hooks();
}
/**
* Registers our hooks.
*
* @since 4.0.0
*/
protected function hooks() {
add_action( $this->bustOgCacheActionName, [ $this, 'bustOgCachePost' ] );
// To avoid duplicate sets of meta tags.
add_filter( 'jetpack_enable_open_graph', '__return_false' );
if ( ! is_admin() ) {
add_filter( 'language_attributes', [ $this, 'addAttributes' ] );
return;
}
// Forces a refresh of the Facebook cache.
add_action( 'post_updated', [ $this, 'scheduleBustOgCachePost' ], 10, 2 );
}
/**
* Adds our attributes to the registered language attributes.
*
* @since 4.0.0
* @version 4.4.5 Adds trim function the html tag removing empty spaces.
*
* @param string $htmlTag The 'html' tag as a string.
* @return string The filtered 'html' tag as a string.
*/
public function addAttributes( $htmlTag ) {
if ( ! aioseo()->options->social->facebook->general->enable ) {
return $htmlTag;
}
$attributes = apply_filters( 'aioseo_opengraph_attributes', [ 'prefix="og: https://ogp.me/ns#"' ] );
foreach ( $attributes as $attr ) {
if ( strpos( $htmlTag, $attr ) === false ) {
$htmlTag .= " $attr ";
}
}
return trim( $htmlTag );
}
/**
* Schedule a ping to bust the OG cache.
*
* @since 4.2.0
*
* @param int $postId The post ID.
* @param \WP_Post $post The post object.
* @return void
*/
public function scheduleBustOgCachePost( $postId, $post = null ) {
if ( ! aioseo()->helpers->isSbCustomFacebookFeedActive() || ! aioseo()->helpers->isValidPost( $post ) ) {
return;
}
if ( aioseo()->actionScheduler->isScheduled( $this->bustOgCacheActionName, [ 'postId' => $postId ] ) ) {
return;
}
// Schedule the new ping.
aioseo()->actionScheduler->scheduleAsync( $this->bustOgCacheActionName, [ 'postId' => $postId ] );
}
/**
* Pings Facebook and asks them to bust the OG cache for a particular post.
*
* @since 4.2.0
*
* @see https://developers.facebook.com/docs/sharing/opengraph/using-objects#update
*
* @param int $postId The post ID.
* @return void
*/
public function bustOgCachePost( $postId ) {
$post = get_post( $postId );
$customAccessToken = apply_filters( 'aioseo_facebook_access_token', '' );
if (
! aioseo()->helpers->isValidPost( $post ) ||
( ! aioseo()->helpers->isSbCustomFacebookFeedActive() && ! $customAccessToken )
) {
return;
}
$permalink = get_permalink( $postId );
$this->bustOgCacheHelper( $permalink );
}
/**
* Helper function for bustOgCache().
*
* @since 4.2.0
*
* @param string $permalink The permalink.
* @return void
*/
protected function bustOgCacheHelper( $permalink ) {
$accessToken = aioseo()->helpers->getSbAccessToken();
$accessToken = apply_filters( 'aioseo_facebook_access_token', $accessToken );
if ( ! $accessToken ) {
return;
}
$url = sprintf(
'https://graph.facebook.com/?%s',
http_build_query(
[
'id' => $permalink,
'scrape' => true,
'access_token' => $accessToken
]
)
);
wp_remote_post( $url, [ 'blocking' => false ] );
}
}PK ! ̈́5 5 app/Common/Social/Output.phpnu [ helpers->isWooCommerceShopPage()
) {
return false;
}
return true;
}
/**
* Returns the Open Graph meta.
*
* @since 4.0.0
*
* @return array The Open Graph meta.
*/
public function getFacebookMeta() {
if ( ! $this->isAllowed() || ! aioseo()->options->social->facebook->general->enable ) {
return [];
}
$meta = [
'og:locale' => aioseo()->social->facebook->getLocale(),
'og:site_name' => aioseo()->helpers->encodeOutputHtml( aioseo()->social->facebook->getSiteName() ),
'og:type' => aioseo()->social->facebook->getObjectType(),
'og:title' => aioseo()->helpers->encodeOutputHtml( aioseo()->social->facebook->getTitle() ),
'og:description' => aioseo()->helpers->encodeOutputHtml( aioseo()->social->facebook->getDescription() ),
'og:url' => esc_url( aioseo()->helpers->canonicalUrl() ),
'fb:app_id' => aioseo()->options->social->facebook->advanced->appId,
'fb:admins' => implode( ',', array_map( 'trim', explode( ',', aioseo()->options->social->facebook->advanced->adminId ) ) ),
];
$image = aioseo()->social->facebook->getImage();
if ( $image ) {
$image = is_array( $image ) ? $image[0] : $image;
$image = aioseo()->helpers->makeUrlAbsolute( $image );
$image = set_url_scheme( esc_url( $image ) );
$meta += [
'og:image' => $image,
'og:image:secure_url' => is_ssl() ? $image : '',
'og:image:width' => aioseo()->social->facebook->getImageWidth(),
'og:image:height' => aioseo()->social->facebook->getImageHeight(),
];
}
$video = aioseo()->social->facebook->getVideo();
if ( $video ) {
$video = set_url_scheme( esc_url( $video ) );
$meta += [
'og:video' => $video,
'og:video:secure_url' => is_ssl() ? $video : '',
'og:video:width' => aioseo()->social->facebook->getVideoWidth(),
'og:video:height' => aioseo()->social->facebook->getVideoHeight(),
];
}
if ( ! empty( $meta['og:type'] ) && 'article' === $meta['og:type'] ) {
$meta += [
'article:section' => aioseo()->social->facebook->getSection(),
'article:tag' => aioseo()->social->facebook->getArticleTags(),
'article:published_time' => aioseo()->social->facebook->getPublishedTime(),
'article:modified_time' => aioseo()->social->facebook->getModifiedTime(),
'article:publisher' => aioseo()->social->facebook->getPublisher(),
'article:author' => aioseo()->social->facebook->getAuthor()
];
}
return array_filter( apply_filters( 'aioseo_facebook_tags', $meta ) );
}
/**
* Returns the Twitter meta.
*
* @since 4.0.0
*
* @return array The Twitter meta.
*/
public function getTwitterMeta() {
if ( ! $this->isAllowed() || ! aioseo()->options->social->twitter->general->enable ) {
return [];
}
$meta = [
'twitter:card' => aioseo()->social->twitter->getCardType(),
'twitter:site' => aioseo()->social->twitter->prepareUsername( aioseo()->social->twitter->getTwitterUrl() ),
'twitter:title' => aioseo()->helpers->encodeOutputHtml( aioseo()->social->twitter->getTitle() ),
'twitter:description' => aioseo()->helpers->encodeOutputHtml( aioseo()->social->twitter->getDescription() ),
'twitter:creator' => aioseo()->social->twitter->getCreator()
];
$image = aioseo()->social->twitter->getImage();
if ( $image ) {
$image = is_array( $image ) ? $image[0] : $image;
$image = aioseo()->helpers->makeUrlAbsolute( $image );
// Set the twitter image meta.
$meta['twitter:image'] = $image;
}
if ( is_singular() ) {
$additionalData = apply_filters( 'aioseo_social_twitter_additional_data', aioseo()->social->twitter->getAdditionalData() );
if ( $additionalData ) {
$i = 1;
foreach ( $additionalData as $data ) {
$meta[ "twitter:label$i" ] = $data['label'];
$meta[ "twitter:data$i" ] = $data['value'];
$i++;
}
}
}
return array_filter( apply_filters( 'aioseo_twitter_tags', $meta ) );
}
}PK ! U^@ @ app/Common/Social/Facebook.phpnu [ helpers->getPost( $postId );
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$image = aioseo()->options->social->facebook->homePage->image;
if ( empty( $image ) ) {
$image = aioseo()->social->image->getImage( 'facebook', aioseo()->options->social->facebook->general->defaultImageSourcePosts, $post );
}
return $image;
}
$metaData = aioseo()->meta->metaData->getMetaData( $post );
$image = '';
if ( ! empty( $metaData ) ) {
$imageSource = ! empty( $metaData->og_image_type ) && 'default' !== $metaData->og_image_type
? $metaData->og_image_type
: aioseo()->options->social->facebook->general->defaultImageSourcePosts;
$image = aioseo()->social->image->getImage( 'facebook', $imageSource, $post );
}
// Since we could be on an archive page, let's check again for that default image.
if ( ! $image ) {
$image = aioseo()->social->image->getImage( 'facebook', 'default' );
}
if ( ! $image ) {
$image = aioseo()->helpers->getSiteLogoUrl();
}
// Allow users to control the default image per post type.
return apply_filters(
'aioseo_opengraph_default_image',
$image,
[
$post,
$this->getObjectType()
]
);
}
/**
* Returns the width of the Open Graph image.
*
* @since 4.0.0
*
* @return string The image width.
*/
public function getImageWidth() {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$width = aioseo()->options->social->facebook->homePage->imageWidth;
return $width ? $width : aioseo()->options->social->facebook->general->defaultImagePostsWidth;
}
$metaData = aioseo()->meta->metaData->getMetaData();
if ( ! empty( $metaData->og_custom_image_width ) ) {
return $metaData->og_custom_image_width;
}
$image = $this->getImage();
if ( is_array( $image ) ) {
return $image[1];
}
return aioseo()->options->social->facebook->general->defaultImagePostsWidth;
}
/**
* Returns the height of the Open Graph image.
*
* @since 4.0.0
*
* @return string The image height.
*/
public function getImageHeight() {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$height = aioseo()->options->social->facebook->homePage->imageHeight;
return $height ? $height : aioseo()->options->social->facebook->general->defaultImagePostsHeight;
}
$metaData = aioseo()->meta->metaData->getMetaData();
if ( ! empty( $metaData->og_custom_image_height ) ) {
return $metaData->og_custom_image_height;
}
$image = $this->getImage();
if ( is_array( $image ) ) {
return $image[2];
}
return aioseo()->options->social->facebook->general->defaultImagePostsHeight;
}
/**
* Returns the Open Graph video URL.
*
* @since 4.0.0
*
* @return string The video URL.
*/
public function getVideo() {
$metaData = aioseo()->meta->metaData->getMetaData();
return ! empty( $metaData->og_video ) ? $metaData->og_video : '';
}
/**
* Returns the width of the video.
*
* @since 4.0.0
*
* @return string The video width.
*/
public function getVideoWidth() {
$metaData = aioseo()->meta->metaData->getMetaData();
return ! empty( $metaData->og_video_width ) ? $metaData->og_video_width : '';
}
/**
* Returns the height of the video.
*
* @since 4.0.0
*
* @return string The video height.
*/
public function getVideoHeight() {
$metaData = aioseo()->meta->metaData->getMetaData();
return ! empty( $metaData->og_video_height ) ? $metaData->og_video_height : '';
}
/**
* Returns the site name.
*
* @since 4.0.0
*
* @return string The site name.
*/
public function getSiteName() {
$title = aioseo()->helpers->decodeHtmlEntities( aioseo()->tags->replaceTags( aioseo()->options->social->facebook->general->siteName, get_the_ID() ) );
if ( ! $title ) {
$title = aioseo()->helpers->decodeHtmlEntities( get_bloginfo( 'name' ) );
}
return wp_strip_all_tags( $title );
}
/**
* Returns the Open Graph object type.
*
* @since 4.0.0
*
* @return string The object type.
*/
public function getObjectType() {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$type = aioseo()->options->social->facebook->homePage->objectType;
return $type ? $type : 'website';
}
if ( is_post_type_archive() ) {
return 'website';
}
$post = aioseo()->helpers->getPost();
$metaData = aioseo()->meta->metaData->getMetaData( $post );
if ( ! empty( $metaData->og_object_type ) && 'default' !== $metaData->og_object_type ) {
return $metaData->og_object_type;
}
$postType = get_post_type();
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
$defaultObjectType = $dynamicOptions->social->facebook->general->postTypes->has( $postType )
? $dynamicOptions->social->facebook->general->postTypes->$postType->objectType
: '';
return ! empty( $defaultObjectType ) ? $defaultObjectType : 'article';
}
/**
* Returns the Open Graph title for the current page.
*
* @since 4.0.0
*
* @param \WP_Post|integer $post The post object or ID (optional).
* @return string The Open Graph title.
*/
public function getTitle( $post = null ) {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$title = aioseo()->meta->title->helpers->prepare( aioseo()->options->social->facebook->homePage->title );
return $title ? $title : aioseo()->meta->title->getTitle();
}
$post = aioseo()->helpers->getPost( $post );
$metaData = aioseo()->meta->metaData->getMetaData( $post );
$title = '';
if ( ! empty( $metaData->og_title ) ) {
$title = aioseo()->meta->title->helpers->prepare( $metaData->og_title );
}
if ( is_post_type_archive() ) {
$postType = get_queried_object();
if ( is_a( $postType, 'WP_Post_Type' ) ) {
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( $dynamicOptions->searchAppearance->archives->has( $postType->name ) ) {
$title = aioseo()->meta->title->helpers->prepare( aioseo()->dynamicOptions->searchAppearance->archives->{ $postType->name }->title );
}
}
}
return $title
? $title
: (
$post
? aioseo()->meta->title->getPostTitle( $post )
: $title
);
}
/**
* Returns the Open Graph description.
*
* @since 4.0.0
*
* @param \WP_Post|integer $post The post object or ID (optional).
* @return string The Open Graph description.
*/
public function getDescription( $post = null ) {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$description = aioseo()->meta->description->helpers->prepare( aioseo()->options->social->facebook->homePage->description );
return $description ? $description : aioseo()->meta->description->getDescription();
}
$post = aioseo()->helpers->getPost( $post );
$metaData = aioseo()->meta->metaData->getMetaData( $post );
$description = '';
if ( ! empty( $metaData->og_description ) ) {
$description = aioseo()->meta->description->helpers->prepare( $metaData->og_description );
}
if ( is_post_type_archive() ) {
$postType = get_queried_object();
if ( is_a( $postType, 'WP_Post_Type' ) ) {
$dynamicOptions = aioseo()->dynamicOptions->noConflict();
if ( $dynamicOptions->searchAppearance->archives->has( $postType->name ) ) {
$description = aioseo()->meta->description->helpers->prepare( aioseo()->dynamicOptions->searchAppearance->archives->{ $postType->name }->metaDescription );
}
}
}
return $description
? $description
: (
$post
? aioseo()->meta->description->getPostDescription( $post )
: $description
);
}
/**
* Returns the Open Graph article section name.
*
* @since 4.0.0
*
* @return string The article section name.
*/
public function getSection() {
$metaData = aioseo()->meta->metaData->getMetaData();
return ! empty( $metaData->og_article_section ) ? $metaData->og_article_section : '';
}
/**
* Returns the Open Graph publisher URL.
*
* @since 4.0.0
*
* @return string The Open Graph publisher URL.
*/
public function getPublisher() {
if ( ! aioseo()->options->social->profiles->sameUsername->enable ) {
return aioseo()->options->social->profiles->urls->facebookPageUrl;
}
$username = aioseo()->options->social->profiles->sameUsername->username;
return ( $username && in_array( 'facebookPageUrl', aioseo()->options->social->profiles->sameUsername->included, true ) )
? 'https://facebook.com/' . $username
: '';
}
/**
* Returns the published time.
*
* @since 4.0.0
*
* @return string The published time.
*/
public function getPublishedTime() {
$post = aioseo()->helpers->getPost();
return $post ? aioseo()->helpers->dateTimeToIso8601( $post->post_date_gmt ) : '';
}
/**
* Returns the last modified time.
*
* @since 4.0.0
*
* @return string The last modified time.
*/
public function getModifiedTime() {
$post = aioseo()->helpers->getPost();
return $post ? aioseo()->helpers->dateTimeToIso8601( $post->post_modified_gmt ) : '';
}
/**
* Returns the Open Graph author.
*
* @since 4.0.0
*
* @return string The Open Graph author.
*/
public function getAuthor() {
$post = aioseo()->helpers->getPost();
if ( ! is_a( $post, 'WP_Post' ) || ! aioseo()->options->social->facebook->general->showAuthor ) {
return '';
}
$author = '';
$userProfiles = $this->getUserProfiles( $post->post_author );
if ( ! empty( $userProfiles['facebookPageUrl'] ) ) {
$author = $userProfiles['facebookPageUrl'];
}
if ( empty( $author ) ) {
$author = aioseo()->options->social->facebook->advanced->authorUrl;
}
return $author;
}
/**
* Returns the Open Graph article tags.
*
* @since 4.0.0
*
* @return array An array of unique keywords.
*/
public function getArticleTags() {
$post = aioseo()->helpers->getPost();
$metaData = aioseo()->meta->metaData->getMetaData( $post );
$tags = ! empty( $metaData->og_article_tags ) ? aioseo()->meta->keywords->extractMetaKeywords( $metaData->og_article_tags ) : [];
if (
$post &&
aioseo()->options->social->facebook->advanced->enable &&
aioseo()->options->social->facebook->advanced->generateArticleTags
) {
if ( aioseo()->options->social->facebook->advanced->useKeywordsInTags ) {
$keywords = aioseo()->meta->keywords->getKeywords();
$keywords = aioseo()->tags->parseCustomFields( $keywords );
$keywords = aioseo()->meta->keywords->keywordStringToList( $keywords );
$tags = array_merge( $tags, $keywords );
}
if ( aioseo()->options->social->facebook->advanced->useCategoriesInTags ) {
$tags = array_merge( $tags, aioseo()->helpers->getAllCategories( $post->ID ) );
}
if ( aioseo()->options->social->facebook->advanced->usePostTagsInTags ) {
$tags = array_merge( $tags, aioseo()->helpers->getAllTags( $post->ID ) );
}
}
return aioseo()->meta->keywords->getUniqueKeywords( $tags, false );
}
/**
* Retreive the locale.
*
* @since 4.1.4
*
* @return string The locale.
*/
public function getLocale() {
$locale = get_locale();
// These are the locales FB supports.
$validLocales = [
'af_ZA', // Afrikaans.
'ak_GH', // Akan.
'am_ET', // Amharic.
'ar_AR', // Arabic.
'as_IN', // Assamese.
'ay_BO', // Aymara.
'az_AZ', // Azerbaijani.
'be_BY', // Belarusian.
'bg_BG', // Bulgarian.
'bp_IN', // Bhojpuri.
'bn_IN', // Bengali.
'br_FR', // Breton.
'bs_BA', // Bosnian.
'ca_ES', // Catalan.
'cb_IQ', // Sorani Kurdish.
'ck_US', // Cherokee.
'co_FR', // Corsican.
'cs_CZ', // Czech.
'cx_PH', // Cebuano.
'cy_GB', // Welsh.
'da_DK', // Danish.
'de_DE', // German.
'el_GR', // Greek.
'en_GB', // English (UK).
'en_PI', // English (Pirate).
'en_UD', // English (Upside Down).
'en_US', // English (US).
'em_ZM',
'eo_EO', // Esperanto.
'es_ES', // Spanish (Spain).
'es_LA', // Spanish.
'es_MX', // Spanish (Mexico).
'et_EE', // Estonian.
'eu_ES', // Basque.
'fa_IR', // Persian.
'fb_LT', // Leet Speak.
'ff_NG', // Fulah.
'fi_FI', // Finnish.
'fo_FO', // Faroese.
'fr_CA', // French (Canada).
'fr_FR', // French (France).
'fy_NL', // Frisian.
'ga_IE', // Irish.
'gl_ES', // Galician.
'gn_PY', // Guarani.
'gu_IN', // Gujarati.
'gx_GR', // Classical Greek.
'ha_NG', // Hausa.
'he_IL', // Hebrew.
'hi_IN', // Hindi.
'hr_HR', // Croatian.
'hu_HU', // Hungarian.
'ht_HT', // Haitian Creole.
'hy_AM', // Armenian.
'id_ID', // Indonesian.
'ig_NG', // Igbo.
'is_IS', // Icelandic.
'it_IT', // Italian.
'ik_US',
'iu_CA',
'ja_JP', // Japanese.
'ja_KS', // Japanese (Kansai).
'jv_ID', // Javanese.
'ka_GE', // Georgian.
'kk_KZ', // Kazakh.
'km_KH', // Khmer.
'kn_IN', // Kannada.
'ko_KR', // Korean.
'ks_IN', // Kashmiri.
'ku_TR', // Kurdish (Kurmanji).
'ky_KG', // Kyrgyz.
'la_VA', // Latin.
'lg_UG', // Ganda.
'li_NL', // Limburgish.
'ln_CD', // Lingala.
'lo_LA', // Lao.
'lt_LT', // Lithuanian.
'lv_LV', // Latvian.
'mg_MG', // Malagasy.
'mi_NZ', // Maori.
'mk_MK', // Macedonian.
'ml_IN', // Malayalam.
'mn_MN', // Mongolian.
'mr_IN', // Marathi.
'ms_MY', // Malay.
'mt_MT', // Maltese.
'my_MM', // Burmese.
'nb_NO', // Norwegian (bokmal).
'nd_ZW', // Ndebele.
'ne_NP', // Nepali.
'nl_BE', // Dutch (Belgie).
'nl_NL', // Dutch.
'nn_NO', // Norwegian (nynorsk).
'nr_ZA', // Southern Ndebele.
'ns_ZA', // Northern Sotho.
'ny_MW', // Chewa.
'om_ET', // Oromo.
'or_IN', // Oriya.
'pa_IN', // Punjabi.
'pl_PL', // Polish.
'ps_AF', // Pashto.
'pt_BR', // Portuguese (Brazil).
'pt_PT', // Portuguese (Portugal).
'qc_GT', // Quiché.
'qu_PE', // Quechua.
'qr_GR',
'qz_MM', // Burmese (Zawgyi).
'rm_CH', // Romansh.
'ro_RO', // Romanian.
'ru_RU', // Russian.
'rw_RW', // Kinyarwanda.
'sa_IN', // Sanskrit.
'sc_IT', // Sardinian.
'se_NO', // Northern Sami.
'si_LK', // Sinhala.
'su_ID', // Sundanese.
'sk_SK', // Slovak.
'sl_SI', // Slovenian.
'sn_ZW', // Shona.
'so_SO', // Somali.
'sq_AL', // Albanian.
'sr_RS', // Serbian.
'ss_SZ', // Swazi.
'st_ZA', // Southern Sotho.
'sv_SE', // Swedish.
'sw_KE', // Swahili.
'sy_SY', // Syriac.
'sz_PL', // Silesian.
'ta_IN', // Tamil.
'te_IN', // Telugu.
'tg_TJ', // Tajik.
'th_TH', // Thai.
'tk_TM', // Turkmen.
'tl_PH', // Filipino.
'tl_ST', // Klingon.
'tn_BW', // Tswana.
'tr_TR', // Turkish.
'ts_ZA', // Tsonga.
'tt_RU', // Tatar.
'tz_MA', // Tamazight.
'uk_UA', // Ukrainian.
'ur_PK', // Urdu.
'uz_UZ', // Uzbek.
've_ZA', // Venda.
'vi_VN', // Vietnamese.
'wo_SN', // Wolof.
'xh_ZA', // Xhosa.
'yi_DE', // Yiddish.
'yo_NG', // Yoruba.
'zh_CN', // Simplified Chinese (China).
'zh_HK', // Traditional Chinese (Hong Kong).
'zh_TW', // Traditional Chinese (Taiwan).
'zu_ZA', // Zulu.
'zz_TR', // Zazaki.
];
// Catch some weird locales served out by WP that are not easily doubled up.
$fixLocales = [
'ca' => 'ca_ES',
'en' => 'en_US',
'el' => 'el_GR',
'et' => 'et_EE',
'ja' => 'ja_JP',
'sq' => 'sq_AL',
'uk' => 'uk_UA',
'vi' => 'vi_VN',
'zh' => 'zh_CN',
];
if ( isset( $fixLocales[ $locale ] ) ) {
$locale = $fixLocales[ $locale ];
}
// Convert locales like "es" to "es_ES", in case that works for the given locale (sometimes it does).
if ( 2 === strlen( $locale ) ) {
$locale = strtolower( $locale ) . '_' . strtoupper( $locale );
}
// Check to see if the locale is a valid FB one, if not, use en_US as a fallback.
if ( ! in_array( $locale, $validLocales, true ) ) {
$locale = strtolower( substr( $locale, 0, 2 ) ) . '_' . strtoupper( substr( $locale, 0, 2 ) );
if ( ! in_array( $locale, $validLocales, true ) ) {
$locale = 'en_US';
}
}
return apply_filters( 'aioseo_og_locale', $locale );
}
}PK ! v app/Common/Social/Twitter.phpnu [ options->social->profiles->sameUsername->enable ) {
return aioseo()->options->social->profiles->urls->twitterUrl;
}
$userName = aioseo()->options->social->profiles->sameUsername->username;
return ( $userName && in_array( 'twitterUrl', aioseo()->options->social->profiles->sameUsername->included, true ) )
? 'https://x.com/' . $userName
: '';
}
/**
* Returns the Twitter card type.
*
* @since 4.0.0
*
* @return string $card The card type.
*/
public function getCardType() {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
return aioseo()->options->social->twitter->homePage->cardType;
}
$metaData = aioseo()->meta->metaData->getMetaData();
return ! empty( $metaData->twitter_card ) && 'default' !== $metaData->twitter_card ? $metaData->twitter_card : aioseo()->options->social->twitter->general->defaultCardType;
}
/**
* Returns the Twitter creator.
*
* @since 4.0.0
*
* @return string The creator.
*/
public function getCreator() {
$post = aioseo()->helpers->getPost();
if (
! is_a( $post, 'WP_Post' ) ||
! post_type_supports( $post->post_type, 'author' ) ||
! aioseo()->options->social->twitter->general->showAuthor
) {
return '';
}
$author = '';
$userProfiles = $this->getUserProfiles( $post->post_author );
if ( ! empty( $userProfiles['twitterUrl'] ) ) {
$author = $userProfiles['twitterUrl'];
}
if ( empty( $author ) ) {
$author = aioseo()->social->twitter->getTwitterUrl();
}
$author = aioseo()->social->twitter->prepareUsername( $author );
return $author;
}
/**
* Returns the Twitter image URL.
*
* @since 4.0.0
*
* @param int $postId The post ID (optional).
* @return string The image URL.
*/
public function getImage( $postId = null ) {
$post = aioseo()->helpers->getPost( $postId );
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$image = aioseo()->options->social->twitter->homePage->image;
if ( empty( $image ) ) {
$image = aioseo()->options->social->facebook->homePage->image;
}
if ( empty( $image ) ) {
$image = aioseo()->social->image->getImage( 'twitter', aioseo()->options->social->twitter->general->defaultImageSourcePosts, $post );
}
return $image ? $image : aioseo()->social->facebook->getImage();
}
$metaData = aioseo()->meta->metaData->getMetaData( $post );
if ( ! empty( $metaData->twitter_use_og ) ) {
return aioseo()->social->facebook->getImage();
}
$image = '';
if ( ! empty( $metaData ) ) {
$imageSource = ! empty( $metaData->twitter_image_type ) && 'default' !== $metaData->twitter_image_type
? $metaData->twitter_image_type
: aioseo()->options->social->twitter->general->defaultImageSourcePosts;
$image = aioseo()->social->image->getImage( 'twitter', $imageSource, $post );
}
return $image ? $image : aioseo()->social->facebook->getImage();
}
/**
* Returns the Twitter title for the current page.
*
* @since 4.0.0
*
* @param \WP_Post|integer $post The post object or ID (optional).
* @return string The Twitter title.
*/
public function getTitle( $post = null ) {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$title = aioseo()->meta->title->helpers->prepare( aioseo()->options->social->twitter->homePage->title );
return $title ? $title : aioseo()->social->facebook->getTitle( $post );
}
$post = aioseo()->helpers->getPost( $post );
$metaData = aioseo()->meta->metaData->getMetaData( $post );
if ( ! empty( $metaData->twitter_use_og ) ) {
return aioseo()->social->facebook->getTitle( $post );
}
$title = '';
if ( ! empty( $metaData->twitter_title ) ) {
$title = aioseo()->meta->title->helpers->prepare( $metaData->twitter_title );
}
return $title ? $title : aioseo()->social->facebook->getTitle( $post );
}
/**
* Returns the Twitter description for the current page.
*
* @since 4.0.0
*
* @param \WP_Post|integer $post The post object or ID (optional).
* @return string The Twitter description.
*/
public function getDescription( $post = null ) {
if ( is_home() && 'posts' === get_option( 'show_on_front' ) ) {
$description = aioseo()->meta->description->helpers->prepare( aioseo()->options->social->twitter->homePage->description );
return $description ? $description : aioseo()->social->facebook->getDescription( $post );
}
$post = aioseo()->helpers->getPost( $post );
$metaData = aioseo()->meta->metaData->getMetaData( $post );
if ( ! empty( $metaData->twitter_use_og ) ) {
return aioseo()->social->facebook->getDescription( $post );
}
$description = '';
if ( ! empty( $metaData->twitter_description ) ) {
$description = aioseo()->meta->description->helpers->prepare( $metaData->twitter_description );
}
return $description ? $description : aioseo()->social->facebook->getDescription( $post );
}
/**
* Prepare twitter username for public display.
*
* We do things like strip out the URL, etc and return just (at)username.
* At the moment, we'll check for 1 of 3 things... (at)username, username, and https://x.com/username.
*
* @since 4.0.0
*
* @param string $profile Twitter username.
* @param boolean $includeAt Whether or not ot include the @ sign.
* @return string Full Twitter username.
*/
public function prepareUsername( $profile, $includeAt = true ) {
if ( ! $profile ) {
return $profile;
}
$profile = (string) $profile;
if ( preg_match( '/^(\@)?[A-Za-z0-9_]+$/', (string) $profile ) ) {
if ( '@' !== $profile[0] && $includeAt ) {
$profile = '@' . $profile;
} elseif ( '@' === $profile[0] && ! $includeAt ) {
$profile = ltrim( $profile, '@' );
}
}
if ( strpos( $profile, 'twitter.com' ) || strpos( $profile, 'x.com' ) ) {
$profile = esc_url( $profile );
// Extract the twitter username from the URL.
$parsedTwitterProfile = wp_parse_url( $profile );
$path = $parsedTwitterProfile['path'];
$pathParts = explode( '/', $path );
$profile = $pathParts[1];
if ( $profile ) {
if ( '@' !== $profile[0] && $includeAt ) {
$profile = '@' . $profile;
}
if ( '@' === $profile[0] && ! $includeAt ) {
$profile = ltrim( $profile, '@' );
}
}
}
return $profile;
}
/**
* Get additional twitter data.
*
* @since 4.0.0
*
* @return array An array of additional twitter data.
*/
public function getAdditionalData() {
if ( ! aioseo()->options->social->twitter->general->additionalData ) {
return [];
}
$data = [];
$post = aioseo()->helpers->getPost();
if ( ! is_a( $post, 'WP_Post' ) ) {
return $data;
}
if ( $post->post_author && post_type_supports( $post->post_type, 'author' ) ) {
$data[] = [
'label' => __( 'Written by', 'all-in-one-seo-pack' ),
'value' => get_the_author_meta( 'display_name', $post->post_author )
];
}
if ( ! empty( $post->post_content ) ) {
$minutes = $this->getReadingTime( $post->post_content );
if ( ! empty( $minutes ) ) {
$data[] = [
'label' => __( 'Est. reading time', 'all-in-one-seo-pack' ),
// Translators: 1 - The estimated reading time.
'value' => sprintf( _n( '%1$s minute', '%1$s minutes', $minutes, 'all-in-one-seo-pack' ), $minutes )
];
}
}
return $data;
}
/**
* Returns the estimated reading time for a string.
*
* @since 4.0.0
*
* @param string $string The string to count.
* @return integer The estimated reading time as an integer.
*/
private function getReadingTime( $string ) {
$wpm = 200;
$word = str_word_count( wp_strip_all_tags( $string ) );
return round( $word / $wpm );
}
}PK ! }zJ - app/Common/WritingAssistant/Utils/Helpers.phpnu [ get_the_ID(),
'report' => $keyword,
'keywordText' => ! empty( $keyword->keyword ) ? $keyword->keyword : '',
'contentAnalysis' => Models\WritingAssistantPost::getContentAnalysis( get_the_ID() ),
'seoBoost' => [
'isLoggedIn' => aioseo()->writingAssistant->seoBoost->isLoggedIn(),
'loginUrl' => aioseo()->writingAssistant->seoBoost->getLoginUrl(),
'createAccountUrl' => aioseo()->writingAssistant->seoBoost->getCreateAccountUrl(),
'userOptions' => aioseo()->writingAssistant->seoBoost->getUserOptions()
]
];
}
/**
* Gets the data for vue.
*
* @since 4.7.4
*
* @return array An array of data.
*/
public function getSettingsVueData() {
return [
'seoBoost' => [
'isLoggedIn' => aioseo()->writingAssistant->seoBoost->isLoggedIn(),
'loginUrl' => aioseo()->writingAssistant->seoBoost->getLoginUrl(),
'createAccountUrl' => aioseo()->writingAssistant->seoBoost->getCreateAccountUrl(),
'userOptions' => aioseo()->writingAssistant->seoBoost->getUserOptions()
]
];
}
}PK ! 3_ _ 1 app/Common/WritingAssistant/SeoBoost/SeoBoost.phpnu [ service = new Service();
$returnParam = isset( $_GET['aioseo-writing-assistant'] ) // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
? sanitize_text_field( wp_unslash( $_GET['aioseo-writing-assistant'] ) ) // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
: null;
if ( 'auth_return' === $returnParam ) {
add_action( 'init', [ $this, 'checkToken' ], 50 );
}
if ( 'ms_logged_in' === $returnParam ) {
add_action( 'init', [ $this, 'marketingSiteCallback' ], 50 );
}
add_action( 'init', [ $this, 'migrateUserData' ], 10 );
add_action( 'init', [ $this, 'refreshUserOptionsAfterError' ] );
}
/**
* Returns if the user has an access key.
*
* @since 4.7.4
*
* @return bool
*/
public function isLoggedIn() {
return $this->getAccessToken() !== '';
}
/**
* Gets the login URL.
*
* @since 4.7.4
*
* @return string The login URL.
*/
public function getLoginUrl() {
$url = $this->loginUrl;
if ( defined( 'AIOSEO_WRITING_ASSISTANT_LOGIN_URL' ) ) {
$url = AIOSEO_WRITING_ASSISTANT_LOGIN_URL;
}
$params = [
'oauth' => true,
'redirect' => get_site_url() . '?' . build_query( [ 'aioseo-writing-assistant' => 'auth_return' ] ),
'domain' => aioseo()->helpers->getMultiSiteDomain()
];
return trailingslashit( $url ) . '?' . build_query( $params );
}
/**
* Gets the login URL.
*
* @since 4.7.4
*
* @return string The login URL.
*/
public function getCreateAccountUrl() {
$url = $this->createAccountUrl;
if ( defined( 'AIOSEO_WRITING_ASSISTANT_CREATE_ACCOUNT_URL' ) ) {
$url = AIOSEO_WRITING_ASSISTANT_CREATE_ACCOUNT_URL;
}
$params = [
'url' => base64_encode( get_site_url() . '?' . build_query( [ 'aioseo-writing-assistant' => 'ms_logged_in' ] ) ),
'writing-assistant-checkout' => true
];
return trailingslashit( $url ) . '?' . build_query( $params );
}
/**
* Gets the user's access token.
*
* @since 4.7.4
*
* @return string The access token.
*/
public function getAccessToken() {
$metaKey = 'seoboost_access_token_' . get_current_blog_id();
return get_user_meta( get_current_user_id(), $metaKey, true );
}
/**
* Sets the user's access token.
*
* @since 4.7.4
*
* @return void
*/
public function setAccessToken( $accessToken ) {
$metaKey = 'seoboost_access_token_' . get_current_blog_id();
update_user_meta( get_current_user_id(), $metaKey, $accessToken );
$this->refreshUserOptions();
}
/**
* Refreshes user options from SEOBoost.
*
* @since 4.7.4
*
* @return void
*/
public function refreshUserOptions() {
$userOptions = $this->service->getUserOptions();
if ( is_wp_error( $userOptions ) || ! empty( $userOptions['error'] ) ) {
$userOptions = $this->getDefaultUserOptions();
aioseo()->cache->update( 'seoboost_get_user_options_error', time() + DAY_IN_SECONDS, MONTH_IN_SECONDS );
}
$this->setUserOptions( $userOptions );
}
/**
* Gets the user options.
*
* @since 4.7.4
*
* @param bool $refresh Whether to refresh the user options.
* @return array The user options.
*/
public function getUserOptions( $refresh = false ) {
if ( ! $refresh ) {
$metaKey = 'seoboost_user_options_' . get_current_blog_id();
$userOptions = get_user_meta( get_current_user_id(), $metaKey, true );
if ( ! empty( $userOptions ) ) {
return json_decode( (string) $userOptions, true ) ?? [];
}
}
// If there are no options or we need to refresh them, get them from SEOBoost.
$this->refreshUserOptions();
$userOptions = $this->getUserOptions();
if ( empty( $userOptions ) ) {
return $this->getDefaultUserOptions();
}
return $userOptions;
}
/**
* Gets the user options.
*
* @since 4.7.4
*
* @param array $options The user options.
* @return void
*/
public function setUserOptions( $options ) {
if ( ! is_array( $options ) ) {
return;
}
$userOptions = array_merge( $this->getDefaultUserOptions(), $options );
$metaKey = 'seoboost_user_options_' . get_current_blog_id();
update_user_meta( get_current_user_id(), $metaKey, wp_json_encode( $userOptions ) );
}
/**
* Gets the user info from SEOBoost.
*
* @since 4.7.4
*
* @return array|\WP_Error The user info or a WP_Error.
*/
public function getUserInfo() {
return $this->service->getUserInfo();
}
/**
* Checks the token.
*
* @since 4.7.4
*
* @return void
*/
public function checkToken() {
$authToken = isset( $_GET['token'] ) // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
? sanitize_key( wp_unslash( $_GET['token'] ) ) // phpcs:ignore HM.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Recommended
: null;
if ( $authToken ) {
$accessToken = $this->service->getAccessToken( $authToken );
if ( ! is_wp_error( $accessToken ) && ! empty( $accessToken['token'] ) ) {
$this->setAccessToken( $accessToken['token'] );
?>
core->db->delete( 'usermeta' )->whereRaw( 'meta_key LIKE \'seoboost_access_token%\'' )->run();
aioseo()->core->db->delete( 'usermeta' )->where( 'meta_key', 'seoboost_user_options' )->run();
}
/**
* Gets the report history.
*
* @since 4.7.4
*
* @return array|\WP_Error The report history.
*/
public function getReportHistory() {
return $this->service->getReportHistory();
}
/**
* Migrate Writing Assistant access tokens.
* This handles the fix for multisites where subsites all used the same workspace/account.
*
* @since 4.7.7
*
* @return void
*/
public function migrateUserData() {
$userToken = get_user_meta( get_current_user_id(), 'seoboost_access_token', true );
if ( ! empty( $userToken ) ) {
$this->setAccessToken( $userToken );
delete_user_meta( get_current_user_id(), 'seoboost_access_token' );
}
$userOptions = get_user_meta( get_current_user_id(), 'seoboost_user_options', true );
if ( ! empty( $userOptions ) ) {
$this->setUserOptions( $userOptions );
delete_user_meta( get_current_user_id(), 'seoboost_user_options' );
}
}
/**
* Refreshes user options after an error.
* This needs to run on init since service class is not available in the constructor.
*
* @since 4.7.7.2
*
* @return void
*/
public function refreshUserOptionsAfterError() {
$userOptionsFetchError = aioseo()->cache->get( 'seoboost_get_user_options_error' );
if ( $userOptionsFetchError && time() > $userOptionsFetchError ) {
aioseo()->cache->delete( 'seoboost_get_user_options_error' );
$this->refreshUserOptions();
}
}
/**
* Returns the default user options.
*
* @since 4.7.7.1
*
* @return array The default user options.
*/
private function getDefaultUserOptions() {
return [
'language' => 'en',
'country' => 'US',
'countries' => $this->getCountries(),
'languages' => $this->getLanguages(),
'searchEngines' => $this->getSearchEngines()
];
}
/**
* Returns the list of countries.
*
* @since 4.7.7.1
*
* @return array The list of countries.
*/
private function getCountries() {
$countries = [
'AF' => __( 'Afghanistan', 'all-in-one-seo-pack' ),
'AL' => __( 'Albania', 'all-in-one-seo-pack' ),
'DZ' => __( 'Algeria', 'all-in-one-seo-pack' ),
'AS' => __( 'American Samoa', 'all-in-one-seo-pack' ),
'AD' => __( 'Andorra', 'all-in-one-seo-pack' ),
'AO' => __( 'Angola', 'all-in-one-seo-pack' ),
'AI' => __( 'Anguilla', 'all-in-one-seo-pack' ),
'AG' => __( 'Antigua & Barbuda', 'all-in-one-seo-pack' ),
'AR' => __( 'Argentina', 'all-in-one-seo-pack' ),
'AM' => __( 'Armenia', 'all-in-one-seo-pack' ),
'AU' => __( 'Australia', 'all-in-one-seo-pack' ),
'AT' => __( 'Austria', 'all-in-one-seo-pack' ),
'AZ' => __( 'Azerbaijan', 'all-in-one-seo-pack' ),
'BS' => __( 'Bahamas', 'all-in-one-seo-pack' ),
'BH' => __( 'Bahrain', 'all-in-one-seo-pack' ),
'BD' => __( 'Bangladesh', 'all-in-one-seo-pack' ),
'BY' => __( 'Belarus', 'all-in-one-seo-pack' ),
'BE' => __( 'Belgium', 'all-in-one-seo-pack' ),
'BZ' => __( 'Belize', 'all-in-one-seo-pack' ),
'BJ' => __( 'Benin', 'all-in-one-seo-pack' ),
'BT' => __( 'Bhutan', 'all-in-one-seo-pack' ),
'BO' => __( 'Bolivia', 'all-in-one-seo-pack' ),
'BA' => __( 'Bosnia & Herzegovina', 'all-in-one-seo-pack' ),
'BW' => __( 'Botswana', 'all-in-one-seo-pack' ),
'BR' => __( 'Brazil', 'all-in-one-seo-pack' ),
'VG' => __( 'British Virgin Islands', 'all-in-one-seo-pack' ),
'BN' => __( 'Brunei', 'all-in-one-seo-pack' ),
'BG' => __( 'Bulgaria', 'all-in-one-seo-pack' ),
'BF' => __( 'Burkina Faso', 'all-in-one-seo-pack' ),
'BI' => __( 'Burundi', 'all-in-one-seo-pack' ),
'KH' => __( 'Cambodia', 'all-in-one-seo-pack' ),
'CM' => __( 'Cameroon', 'all-in-one-seo-pack' ),
'CA' => __( 'Canada', 'all-in-one-seo-pack' ),
'CV' => __( 'Cape Verde', 'all-in-one-seo-pack' ),
'CF' => __( 'Central African Republic', 'all-in-one-seo-pack' ),
'TD' => __( 'Chad', 'all-in-one-seo-pack' ),
'CL' => __( 'Chile', 'all-in-one-seo-pack' ),
'CO' => __( 'Colombia', 'all-in-one-seo-pack' ),
'CG' => __( 'Congo - Brazzaville', 'all-in-one-seo-pack' ),
'CD' => __( 'Congo - Kinshasa', 'all-in-one-seo-pack' ),
'CK' => __( 'Cook Islands', 'all-in-one-seo-pack' ),
'CR' => __( 'Costa Rica', 'all-in-one-seo-pack' ),
'CI' => __( 'Côte d’Ivoire', 'all-in-one-seo-pack' ),
'HR' => __( 'Croatia', 'all-in-one-seo-pack' ),
'CU' => __( 'Cuba', 'all-in-one-seo-pack' ),
'CY' => __( 'Cyprus', 'all-in-one-seo-pack' ),
'CZ' => __( 'Czechia', 'all-in-one-seo-pack' ),
'DK' => __( 'Denmark', 'all-in-one-seo-pack' ),
'DJ' => __( 'Djibouti', 'all-in-one-seo-pack' ),
'DM' => __( 'Dominica', 'all-in-one-seo-pack' ),
'DO' => __( 'Dominican Republic', 'all-in-one-seo-pack' ),
'EC' => __( 'Ecuador', 'all-in-one-seo-pack' ),
'EG' => __( 'Egypt', 'all-in-one-seo-pack' ),
'SV' => __( 'El Salvador', 'all-in-one-seo-pack' ),
'EE' => __( 'Estonia', 'all-in-one-seo-pack' ),
'ET' => __( 'Ethiopia', 'all-in-one-seo-pack' ),
'FJ' => __( 'Fiji', 'all-in-one-seo-pack' ),
'FI' => __( 'Finland', 'all-in-one-seo-pack' ),
'FR' => __( 'France', 'all-in-one-seo-pack' ),
'GA' => __( 'Gabon', 'all-in-one-seo-pack' ),
'GM' => __( 'Gambia', 'all-in-one-seo-pack' ),
'GE' => __( 'Georgia', 'all-in-one-seo-pack' ),
'DE' => __( 'Germany', 'all-in-one-seo-pack' ),
'GH' => __( 'Ghana', 'all-in-one-seo-pack' ),
'GI' => __( 'Gibraltar', 'all-in-one-seo-pack' ),
'GR' => __( 'Greece', 'all-in-one-seo-pack' ),
'GL' => __( 'Greenland', 'all-in-one-seo-pack' ),
'GT' => __( 'Guatemala', 'all-in-one-seo-pack' ),
'GG' => __( 'Guernsey', 'all-in-one-seo-pack' ),
'GY' => __( 'Guyana', 'all-in-one-seo-pack' ),
'HT' => __( 'Haiti', 'all-in-one-seo-pack' ),
'HN' => __( 'Honduras', 'all-in-one-seo-pack' ),
'HK' => __( 'Hong Kong', 'all-in-one-seo-pack' ),
'HU' => __( 'Hungary', 'all-in-one-seo-pack' ),
'IS' => __( 'Iceland', 'all-in-one-seo-pack' ),
'IN' => __( 'India', 'all-in-one-seo-pack' ),
'ID' => __( 'Indonesia', 'all-in-one-seo-pack' ),
'IQ' => __( 'Iraq', 'all-in-one-seo-pack' ),
'IE' => __( 'Ireland', 'all-in-one-seo-pack' ),
'IM' => __( 'Isle of Man', 'all-in-one-seo-pack' ),
'IL' => __( 'Israel', 'all-in-one-seo-pack' ),
'IT' => __( 'Italy', 'all-in-one-seo-pack' ),
'JM' => __( 'Jamaica', 'all-in-one-seo-pack' ),
'JP' => __( 'Japan', 'all-in-one-seo-pack' ),
'JE' => __( 'Jersey', 'all-in-one-seo-pack' ),
'JO' => __( 'Jordan', 'all-in-one-seo-pack' ),
'KZ' => __( 'Kazakhstan', 'all-in-one-seo-pack' ),
'KE' => __( 'Kenya', 'all-in-one-seo-pack' ),
'KI' => __( 'Kiribati', 'all-in-one-seo-pack' ),
'KW' => __( 'Kuwait', 'all-in-one-seo-pack' ),
'KG' => __( 'Kyrgyzstan', 'all-in-one-seo-pack' ),
'LA' => __( 'Laos', 'all-in-one-seo-pack' ),
'LV' => __( 'Latvia', 'all-in-one-seo-pack' ),
'LB' => __( 'Lebanon', 'all-in-one-seo-pack' ),
'LS' => __( 'Lesotho', 'all-in-one-seo-pack' ),
'LY' => __( 'Libya', 'all-in-one-seo-pack' ),
'LI' => __( 'Liechtenstein', 'all-in-one-seo-pack' ),
'LT' => __( 'Lithuania', 'all-in-one-seo-pack' ),
'LU' => __( 'Luxembourg', 'all-in-one-seo-pack' ),
'MG' => __( 'Madagascar', 'all-in-one-seo-pack' ),
'MW' => __( 'Malawi', 'all-in-one-seo-pack' ),
'MY' => __( 'Malaysia', 'all-in-one-seo-pack' ),
'MV' => __( 'Maldives', 'all-in-one-seo-pack' ),
'ML' => __( 'Mali', 'all-in-one-seo-pack' ),
'MT' => __( 'Malta', 'all-in-one-seo-pack' ),
'MU' => __( 'Mauritius', 'all-in-one-seo-pack' ),
'MX' => __( 'Mexico', 'all-in-one-seo-pack' ),
'FM' => __( 'Micronesia', 'all-in-one-seo-pack' ),
'MD' => __( 'Moldova', 'all-in-one-seo-pack' ),
'MN' => __( 'Mongolia', 'all-in-one-seo-pack' ),
'ME' => __( 'Montenegro', 'all-in-one-seo-pack' ),
'MS' => __( 'Montserrat', 'all-in-one-seo-pack' ),
'MA' => __( 'Morocco', 'all-in-one-seo-pack' ),
'MZ' => __( 'Mozambique', 'all-in-one-seo-pack' ),
'MM' => __( 'Myanmar (Burma)', 'all-in-one-seo-pack' ),
'NA' => __( 'Namibia', 'all-in-one-seo-pack' ),
'NR' => __( 'Nauru', 'all-in-one-seo-pack' ),
'NP' => __( 'Nepal', 'all-in-one-seo-pack' ),
'NL' => __( 'Netherlands', 'all-in-one-seo-pack' ),
'NZ' => __( 'New Zealand', 'all-in-one-seo-pack' ),
'NI' => __( 'Nicaragua', 'all-in-one-seo-pack' ),
'NE' => __( 'Niger', 'all-in-one-seo-pack' ),
'NG' => __( 'Nigeria', 'all-in-one-seo-pack' ),
'NU' => __( 'Niue', 'all-in-one-seo-pack' ),
'MK' => __( 'North Macedonia', 'all-in-one-seo-pack' ),
'NO' => __( 'Norway', 'all-in-one-seo-pack' ),
'OM' => __( 'Oman', 'all-in-one-seo-pack' ),
'PK' => __( 'Pakistan', 'all-in-one-seo-pack' ),
'PS' => __( 'Palestine', 'all-in-one-seo-pack' ),
'PA' => __( 'Panama', 'all-in-one-seo-pack' ),
'PG' => __( 'Papua New Guinea', 'all-in-one-seo-pack' ),
'PY' => __( 'Paraguay', 'all-in-one-seo-pack' ),
'PE' => __( 'Peru', 'all-in-one-seo-pack' ),
'PH' => __( 'Philippines', 'all-in-one-seo-pack' ),
'PN' => __( 'Pitcairn Islands', 'all-in-one-seo-pack' ),
'PL' => __( 'Poland', 'all-in-one-seo-pack' ),
'PT' => __( 'Portugal', 'all-in-one-seo-pack' ),
'PR' => __( 'Puerto Rico', 'all-in-one-seo-pack' ),
'QA' => __( 'Qatar', 'all-in-one-seo-pack' ),
'RO' => __( 'Romania', 'all-in-one-seo-pack' ),
'RU' => __( 'Russia', 'all-in-one-seo-pack' ),
'RW' => __( 'Rwanda', 'all-in-one-seo-pack' ),
'WS' => __( 'Samoa', 'all-in-one-seo-pack' ),
'SM' => __( 'San Marino', 'all-in-one-seo-pack' ),
'ST' => __( 'São Tomé & Príncipe', 'all-in-one-seo-pack' ),
'SA' => __( 'Saudi Arabia', 'all-in-one-seo-pack' ),
'SN' => __( 'Senegal', 'all-in-one-seo-pack' ),
'RS' => __( 'Serbia', 'all-in-one-seo-pack' ),
'SC' => __( 'Seychelles', 'all-in-one-seo-pack' ),
'SL' => __( 'Sierra Leone', 'all-in-one-seo-pack' ),
'SG' => __( 'Singapore', 'all-in-one-seo-pack' ),
'SK' => __( 'Slovakia', 'all-in-one-seo-pack' ),
'SI' => __( 'Slovenia', 'all-in-one-seo-pack' ),
'SB' => __( 'Solomon Islands', 'all-in-one-seo-pack' ),
'SO' => __( 'Somalia', 'all-in-one-seo-pack' ),
'ZA' => __( 'South Africa', 'all-in-one-seo-pack' ),
'KR' => __( 'South Korea', 'all-in-one-seo-pack' ),
'ES' => __( 'Spain', 'all-in-one-seo-pack' ),
'LK' => __( 'Sri Lanka', 'all-in-one-seo-pack' ),
'SH' => __( 'St. Helena', 'all-in-one-seo-pack' ),
'VC' => __( 'St. Vincent & Grenadines', 'all-in-one-seo-pack' ),
'SR' => __( 'Suriname', 'all-in-one-seo-pack' ),
'SE' => __( 'Sweden', 'all-in-one-seo-pack' ),
'CH' => __( 'Switzerland', 'all-in-one-seo-pack' ),
'TW' => __( 'Taiwan', 'all-in-one-seo-pack' ),
'TJ' => __( 'Tajikistan', 'all-in-one-seo-pack' ),
'TZ' => __( 'Tanzania', 'all-in-one-seo-pack' ),
'TH' => __( 'Thailand', 'all-in-one-seo-pack' ),
'TL' => __( 'Timor-Leste', 'all-in-one-seo-pack' ),
'TG' => __( 'Togo', 'all-in-one-seo-pack' ),
'TO' => __( 'Tonga', 'all-in-one-seo-pack' ),
'TT' => __( 'Trinidad & Tobago', 'all-in-one-seo-pack' ),
'TN' => __( 'Tunisia', 'all-in-one-seo-pack' ),
'TR' => __( 'Turkey', 'all-in-one-seo-pack' ),
'TM' => __( 'Turkmenistan', 'all-in-one-seo-pack' ),
'VI' => __( 'U.S. Virgin Islands', 'all-in-one-seo-pack' ),
'UG' => __( 'Uganda', 'all-in-one-seo-pack' ),
'UA' => __( 'Ukraine', 'all-in-one-seo-pack' ),
'AE' => __( 'United Arab Emirates', 'all-in-one-seo-pack' ),
'GB' => __( 'United Kingdom', 'all-in-one-seo-pack' ),
'US' => __( 'United States', 'all-in-one-seo-pack' ),
'UY' => __( 'Uruguay', 'all-in-one-seo-pack' ),
'UZ' => __( 'Uzbekistan', 'all-in-one-seo-pack' ),
'VU' => __( 'Vanuatu', 'all-in-one-seo-pack' ),
'VE' => __( 'Venezuela', 'all-in-one-seo-pack' ),
'VN' => __( 'Vietnam', 'all-in-one-seo-pack' ),
'ZM' => __( 'Zambia', 'all-in-one-seo-pack' ),
'ZW' => __( 'Zimbabwe', 'all-in-one-seo-pack' )
];
return $countries;
}
/**
* Returns the list of languages.
*
* @since 4.7.7.1
*
* @return array The list of languages.
*/
private function getLanguages() {
$languages = [
'ca' => __( 'Catalan', 'all-in-one-seo-pack' ),
'da' => __( 'Danish', 'all-in-one-seo-pack' ),
'nl' => __( 'Dutch', 'all-in-one-seo-pack' ),
'en' => __( 'English', 'all-in-one-seo-pack' ),
'fr' => __( 'French', 'all-in-one-seo-pack' ),
'de' => __( 'German', 'all-in-one-seo-pack' ),
'id' => __( 'Indonesian', 'all-in-one-seo-pack' ),
'it' => __( 'Italian', 'all-in-one-seo-pack' ),
'no' => __( 'Norwegian', 'all-in-one-seo-pack' ),
'pt' => __( 'Portuguese', 'all-in-one-seo-pack' ),
'ro' => __( 'Romanian', 'all-in-one-seo-pack' ),
'es' => __( 'Spanish', 'all-in-one-seo-pack' ),
'sv' => __( 'Swedish', 'all-in-one-seo-pack' ),
'tr' => __( 'Turkish', 'all-in-one-seo-pack' )
];
return $languages;
}
/**
* Returns the list of search engines.
*
* @since 4.7.7.1
*
* @return array The list of search engines.
*/
private function getSearchEngines() {
$searchEngines = [
'AF' => 'google.com.af',
'AL' => 'google.al',
'DZ' => 'google.dz',
'AS' => 'google.as',
'AD' => 'google.ad',
'AO' => 'google.it.ao',
'AI' => 'google.com.ai',
'AG' => 'google.com.ag',
'AR' => 'google.com.ar',
'AM' => 'google.am',
'AU' => 'google.com.au',
'AT' => 'google.at',
'AZ' => 'google.az',
'BS' => 'google.bs',
'BH' => 'google.com.bh',
'BD' => 'google.com.bd',
'BY' => 'google.com.by',
'BE' => 'google.be',
'BZ' => 'google.com.bz',
'BJ' => 'google.bj',
'BT' => 'google.bt',
'BO' => 'google.com.bo',
'BA' => 'google.ba',
'BW' => 'google.co.bw',
'BR' => 'google.com.br',
'VG' => 'google.vg',
'BN' => 'google.com.bn',
'BG' => 'google.bg',
'BF' => 'google.bf',
'BI' => 'google.bi',
'KH' => 'google.com.kh',
'CM' => 'google.cm',
'CA' => 'google.ca',
'CV' => 'google.cv',
'CF' => 'google.cf',
'TD' => 'google.td',
'CL' => 'google.cl',
'CO' => 'google.com.co',
'CG' => 'google.cg',
'CD' => 'google.cd',
'CK' => 'google.co.ck',
'CR' => 'google.co.cr',
'CI' => 'google.ci',
'HR' => 'google.hr',
'CU' => 'google.com.cu',
'CY' => 'google.com.cy',
'CZ' => 'google.cz',
'DK' => 'google.dk',
'DJ' => 'google.dj',
'DM' => 'google.dm',
'DO' => 'google.com.do',
'EC' => 'google.com.ec',
'EG' => 'google.com.eg',
'SV' => 'google.com.sv',
'EE' => 'google.ee',
'ET' => 'google.com.et',
'FJ' => 'google.com.fj',
'FI' => 'google.fi',
'FR' => 'google.fr',
'GA' => 'google.ga',
'GM' => 'google.gm',
'GE' => 'google.ge',
'DE' => 'google.de',
'GH' => 'google.com.gh',
'GI' => 'google.com.gi',
'GR' => 'google.gr',
'GL' => 'google.gl',
'GT' => 'google.com.gt',
'GG' => 'google.gg',
'GY' => 'google.gy',
'HT' => 'google.ht',
'HN' => 'google.hn',
'HK' => 'google.com.hk',
'HU' => 'google.hu',
'IS' => 'google.is',
'IN' => 'google.co.in',
'ID' => 'google.co.id',
'IQ' => 'google.iq',
'IE' => 'google.ie',
'IM' => 'google.co.im',
'IL' => 'google.co.il',
'IT' => 'google.it',
'JM' => 'google.com.jm',
'JP' => 'google.co.jp',
'JE' => 'google.co.je',
'JO' => 'google.jo',
'KZ' => 'google.kz',
'KE' => 'google.co.ke',
'KI' => 'google.ki',
'KW' => 'google.com.kw',
'KG' => 'google.com.kg',
'LA' => 'google.la',
'LV' => 'google.lv',
'LB' => 'google.com.lb',
'LS' => 'google.co.ls',
'LY' => 'google.com.ly',
'LI' => 'google.li',
'LT' => 'google.lt',
'LU' => 'google.lu',
'MG' => 'google.mg',
'MW' => 'google.mw',
'MY' => 'google.com.my',
'MV' => 'google.mv',
'ML' => 'google.ml',
'MT' => 'google.com.mt',
'MU' => 'google.mu',
'MX' => 'google.com.mx',
'FM' => 'google.fm',
'MD' => 'google.md',
'MN' => 'google.mn',
'ME' => 'google.me',
'MS' => 'google.ms',
'MA' => 'google.co.ma',
'MZ' => 'google.co.mz',
'MM' => 'google.com.mm',
'NA' => 'google.com.na',
'NR' => 'google.nr',
'NP' => 'google.com.np',
'NL' => 'google.nl',
'NZ' => 'google.co.nz',
'NI' => 'google.com.ni',
'NE' => 'google.ne',
'NG' => 'google.com.ng',
'NU' => 'google.nu',
'MK' => 'google.mk',
'NO' => 'google.no',
'OM' => 'google.com.om',
'PK' => 'google.com.pk',
'PS' => 'google.ps',
'PA' => 'google.com.pa',
'PG' => 'google.com.pg',
'PY' => 'google.com.py',
'PE' => 'google.com.pe',
'PH' => 'google.com.ph',
'PN' => 'google.pn',
'PL' => 'google.pl',
'PT' => 'google.pt',
'PR' => 'google.com.pr',
'QA' => 'google.com.qa',
'RO' => 'google.ro',
'RU' => 'google.ru',
'RW' => 'google.rw',
'WS' => 'google.as',
'SM' => 'google.sm',
'ST' => 'google.st',
'SA' => 'google.com.sa',
'SN' => 'google.sn',
'RS' => 'google.rs',
'SC' => 'google.sc',
'SL' => 'google.com.sl',
'SG' => 'google.com.sg',
'SK' => 'google.sk',
'SI' => 'google.si',
'SB' => 'google.com.sb',
'SO' => 'google.so',
'ZA' => 'google.co.za',
'KR' => 'google.co.kr',
'ES' => 'google.es',
'LK' => 'google.lk',
'SH' => 'google.sh',
'VC' => 'google.com.vc',
'SR' => 'google.sr',
'SE' => 'google.se',
'CH' => 'google.ch',
'TW' => 'google.com.tw',
'TJ' => 'google.com.tj',
'TZ' => 'google.co.tz',
'TH' => 'google.co.th',
'TL' => 'google.tl',
'TG' => 'google.tg',
'TO' => 'google.to',
'TT' => 'google.tt',
'TN' => 'google.tn',
'TR' => 'google.com.tr',
'TM' => 'google.tm',
'VI' => 'google.co.vi',
'UG' => 'google.co.ug',
'UA' => 'google.com.ua',
'AE' => 'google.ae',
'GB' => 'google.co.uk',
'US' => 'google.com',
'UY' => 'google.com.uy',
'UZ' => 'google.co.uz',
'VU' => 'google.vu',
'VE' => 'google.co.ve',
'VN' => 'google.com.vn',
'ZM' => 'google.co.zm',
'ZW' => 'google.co.zw'
];
return $searchEngines;
}
}PK ! - 0 app/Common/WritingAssistant/SeoBoost/Service.phpnu [ doRequest( 'waAddNewReport', [
'params' => [
'keyword' => $keyword,
'country' => $country,
'language' => $language
]
] );
if ( is_wp_error( $reportRequest ) ) {
return $reportRequest;
}
if ( empty( $reportRequest ) || empty( $reportRequest['status'] ) ) {
return new \WP_Error( 'service-error', __( 'Empty response from service', 'all-in-one-seo-pack' ) );
}
if ( 'success' !== $reportRequest['status'] ) {
return new \WP_Error( 'service-error', $reportRequest['msg'] );
}
return $reportRequest;
}
/**
* Sends a post content to be analyzed.
*
* @since 4.7.4
*
* @param string $title The title.
* @param string $description The description.
* @param string $content The content.
* @param string $reportSlug The report slug.
* @return array|\WP_Error The response.
*/
public function getContentAnalysis( $title, $description, $content, $reportSlug ) {
return $this->doRequest( 'waAnalyzeContent', [
'title' => $title,
'description' => $description,
'content' => $content,
'slug' => $reportSlug
] );
}
/**
* Gets the progress for a keyword.
*
* @since 4.7.4
*
* @param string $uuid The uuid.
* @return array|\WP_Error The progress.
*/
public function getProgressAndResult( $uuid ) {
$response = $this->doRequest( 'waGetReport', [ 'slug' => $uuid ] );
if ( is_wp_error( $response ) ) {
return $response;
}
if ( empty( $response ) ) {
return new \WP_Error( 'empty-progress-and-result', __( 'Empty progress and result.', 'all-in-one-seo-pack' ) );
}
return $response;
}
/**
* Gets the user options.
*
* @since 4.7.4
*
* @return array|\WP_Error The user options.
*/
public function getUserOptions() {
return $this->doRequest( 'waGetUserOptions' );
}
/**
* Gets the user information.
*
* @since 4.7.4
*
* @return array|\WP_Error The user information.
*/
public function getUserInfo() {
return $this->doRequest( 'waGetUserInfo' );
}
/**
* Gets the access token.
*
* @since 4.7.4
*
* @param string $authToken The auth token.
* @return array|\WP_Error The response.
*/
public function getAccessToken( $authToken ) {
return $this->doRequest( 'oauthaccess', [ 'token' => $authToken ] );
}
/**
* Refreshes the access token.
*
* @since 4.7.4
*
* @return bool Was the token refreshed?
*/
private function refreshAccessToken() {
$newAccessToken = $this->doRequest( 'waRefreshAccessToken' );
if (
is_wp_error( $newAccessToken ) ||
'success' !== $newAccessToken['status']
) {
aioseo()->writingAssistant->seoBoost->setAccessToken( '' );
return false;
}
aioseo()->writingAssistant->seoBoost->setAccessToken( $newAccessToken['token'] );
return true;
}
/**
* Sends a POST request to the microservice.
*
* @since 4.7.4
*
* @param string $path The path.
* @param array $requestBody The request body.
* @return array|\WP_Error Returns the response body or WP_Error if the request failed.
*/
private function doRequest( $path, $requestBody = [] ) {
// Prevent API requests if no access token is present.
if (
'oauthaccess' !== $path && // Except if we're getting the access token.
empty( aioseo()->writingAssistant->seoBoost->getAccessToken() )
) {
return new \WP_Error( 'service-error', __( 'Missing access token', 'all-in-one-seo-pack' ) );
}
$requestData = [
'headers' => [
'X-SeoBoost-Access-Token' => aioseo()->writingAssistant->seoBoost->getAccessToken(),
'X-SeoBoost-Domain' => aioseo()->helpers->getMultiSiteDomain(),
'Content-Type' => 'application/json'
],
'timeout' => 60,
'method' => 'GET'
];
if ( ! empty( $requestBody ) ) {
$requestData['method'] = 'POST';
$requestData['body'] = wp_json_encode( $requestBody );
}
$path = trailingslashit( $this->getUrl() ) . trailingslashit( $path );
$response = wp_remote_request( $path, $requestData );
$responseBody = json_decode( wp_remote_retrieve_body( $response ), true );
if ( ! $responseBody ) {
$response = new \WP_Error( 'service-failed', __( 'Error in the SeoBoost service. Please contact support.', 'all-in-one-seo-pack' ) );
}
if ( is_wp_error( $response ) ) {
return $response;
}
// Refresh access token if expired and redo the request.
if (
isset( $responseBody['error'] ) &&
'invalid-access-token' === $responseBody['error']
) {
if ( $this->refreshAccessToken() ) {
return $this->doRequest( $path, $requestBody );
}
}
return $responseBody;
}
/**
* Returns the URL for the Writing Assistant service.
*
* @since 4.7.4
*
* @return string The URL.
*/
public function getUrl() {
$url = $this->baseUrl;
if ( defined( 'AIOSEO_WRITING_ASSISTANT_SERVICE_URL' ) ) {
$url = AIOSEO_WRITING_ASSISTANT_SERVICE_URL;
}
return $url;
}
/**
* Gets the report history.
*
* @since 4.7.4
*
* @return array|\WP_Error
*/
public function getReportHistory() {
return $this->doRequest( 'waGetReportHistory' );
}
}PK ! )B B 0 app/Common/WritingAssistant/WritingAssistant.phpnu [ helpers = new Utils\Helpers();
$this->seoBoost = new SeoBoost\SeoBoost();
}
}PK ! gT& :R :R &