Skip to content

Commit 95f07ca

Browse files
committed
4.8.4.1 Release
1 parent ac20257 commit 95f07ca

File tree

254 files changed

+17395
-5317
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

254 files changed

+17395
-5317
lines changed

all_in_one_seo_pack.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Description: SEO for WordPress. Features like XML Sitemaps, SEO for custom post types, SEO for blogs, business sites, ecommerce sites, and much more. More than 100 million downloads since 2007.
66
* Author: All in One SEO Team
77
* Author URI: https://aioseo.com/
8-
* Version: 4.8.3.2
8+
* Version: 4.8.4.1
99
* Text Domain: all-in-one-seo-pack
1010
* Domain Path: /languages
1111
* License: GPL-3.0+

app/AIOSEO.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -328,13 +328,14 @@ public function load() {
328328
$this->schema = $this->pro ? new Pro\Schema\Schema() : new Common\Schema\Schema();
329329
$this->actionScheduler = new Common\Utils\ActionScheduler();
330330
$this->seoRevisions = $this->pro ? new Pro\SeoRevisions\SeoRevisions() : new Common\SeoRevisions\SeoRevisions();
331-
$this->ai = $this->pro ? new Pro\Ai\Ai() : null;
331+
$this->ai = $this->pro ? new Pro\Ai\Ai() : new Common\Ai\Ai();
332332
$this->filters = $this->pro ? new Pro\Main\Filters() : new Lite\Main\Filters();
333333
$this->crawlCleanup = new Common\QueryArgs\CrawlCleanup();
334334
$this->searchCleanup = new Common\SearchCleanup\SearchCleanup();
335335
$this->emailReports = new Common\EmailReports\EmailReports();
336336
$this->thirdParty = new Common\ThirdParty\ThirdParty();
337337
$this->writingAssistant = new Common\WritingAssistant\WritingAssistant();
338+
$this->llms = new Common\Llms\Llms();
338339

339340
if ( ! wp_doing_ajax() && ! wp_doing_cron() ) {
340341
$this->rss = new Common\Rss();

app/AIOSEOAbstract.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,4 +598,13 @@ abstract class AIOSEOAbstract {
598598
* @var \AIOSEO\Plugin\Common\WritingAssistant\WritingAssistant
599599
*/
600600
public $writingAssistant = null;
601+
602+
/**
603+
* Llms class instance.
604+
*
605+
* @since 4.8.4
606+
*
607+
* @var \AIOSEO\Plugin\Common\Llms\Llms
608+
*/
609+
public $llms = null;
601610
}

app/Common/Admin/Admin.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1178,7 +1178,7 @@ public function getFirstAvailablePageSlug() {
11781178
*/
11791179
public function appendTrashedMessage( $messages ) {
11801180
// Let advanced users override this.
1181-
1181+
// https://github.com/awesomemotive/aioseo/issues/2331
11821182
if ( apply_filters( 'aioseo_redirects_disable_trashed_posts_suggestions', false ) ) {
11831183
return $messages;
11841184
}

app/Common/Admin/ConflictingPlugins.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ public function __construct() {
5757
* @return void
5858
*/
5959
public function init() {
60-
// Only do this for users who can install/deactivate plugins.
61-
if ( ! current_user_can( 'install_plugins' ) ) {
60+
if ( ! current_user_can( 'activate_plugins' ) ) {
6261
return;
6362
}
6463

app/Common/Admin/PostSettings.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,7 @@ public function canAddPostSettingsMetabox( $postType ) {
114114
$generalSettingsCapability = aioseo()->access->hasCapability( 'aioseo_page_general_settings' );
115115
$socialSettingsCapability = aioseo()->access->hasCapability( 'aioseo_page_social_settings' );
116116
$schemaSettingsCapability = aioseo()->access->hasCapability( 'aioseo_page_schema_settings' );
117+
$aiContentSettingsCapability = aioseo()->access->hasCapability( 'aioseo_page_ai_content_settings' );
117118
$linkAssistantCapability = aioseo()->access->hasCapability( 'aioseo_page_link_assistant_settings' );
118119
$redirectsCapability = aioseo()->access->hasCapability( 'aioseo_page_redirects_manage' );
119120
$advancedSettingsCapability = aioseo()->access->hasCapability( 'aioseo_page_advanced_settings' );
@@ -127,6 +128,7 @@ public function canAddPostSettingsMetabox( $postType ) {
127128
empty( $generalSettingsCapability ) &&
128129
empty( $socialSettingsCapability ) &&
129130
empty( $schemaSettingsCapability ) &&
131+
empty( $aiContentSettingsCapability ) &&
130132
empty( $linkAssistantCapability ) &&
131133
empty( $redirectsCapability ) &&
132134
empty( $advancedSettingsCapability ) &&
@@ -240,7 +242,7 @@ public function saveSettingsMetabox( $postId ) {
240242

241243
// If there is no data, there likely was an error, e.g. if the hidden field wasn't populated on load and the user saved the post without making changes in the metabox.
242244
// In that case we should return to prevent a complete reset of the data.
243-
245+
// https://github.com/awesomemotive/aioseo/issues/2254
244246
if ( empty( $currentPost ) ) {
245247
return;
246248
}

app/Common/Admin/Usage.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,10 +239,6 @@ private function generateStartDate() {
239239
* @return array The altered settings.
240240
*/
241241
private function filterPrivateSettings( $settings ) {
242-
if ( ! empty( $settings['advanced']['openAiKey'] ) ) {
243-
$settings['advanced']['openAiKey'] = true;
244-
}
245-
246242
if ( ! empty( $settings['localBusiness']['maps']['apiKey'] ) ) {
247243
$settings['localBusiness']['maps']['apiKey'] = true;
248244
}

app/Common/Ai/Ai.php

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
<?php
2+
3+
namespace AIOSEO\Plugin\Common\Ai;
4+
5+
// Exit if accessed directly.
6+
if ( ! defined( 'ABSPATH' ) ) {
7+
exit;
8+
}
9+
10+
/**
11+
* AI class.
12+
*
13+
* @since 4.8.4
14+
*/
15+
class Ai {
16+
/**
17+
* The base URL for the licensing server.
18+
*
19+
* @since 4.8.4
20+
*
21+
* @var string
22+
*/
23+
private $licensingUrl = 'https://licensing.aioseo.com/v1/';
24+
25+
/**
26+
* The action name for fetching credits.
27+
*
28+
* @since 4.8.4
29+
*
30+
* @var string
31+
*/
32+
protected $creditFetchAction = 'aioseo_ai_update_credits';
33+
34+
/**
35+
* Class constructor.
36+
*
37+
* @since 4.8.4
38+
*/
39+
public function __construct() {
40+
add_action( 'init', [ $this, 'getAccessToken' ] );
41+
42+
add_action( 'init', [ $this, 'scheduleCreditFetchAction' ] );
43+
add_action( $this->creditFetchAction, [ $this, 'updateCredits' ] );
44+
45+
// If param is set, fetch credits but just once per 5 minutes to prevent abuse.
46+
if ( isset( $_REQUEST['aioseo-ai-credits'] ) && ! aioseo()->core->cache->get( 'ai_get_credits' ) ) { // phpcs:ignore HM.Security.NonceVerification.Recommended
47+
add_action( 'init', [ $this, 'updateCredits' ] );
48+
49+
aioseo()->core->cache->update( 'ai_get_credits', true, 5 * MINUTE_IN_SECONDS );
50+
}
51+
}
52+
53+
/**
54+
* Gets an access token from the server.
55+
* This is the one-time access token that includes 50 free credits.
56+
*
57+
* @since 4.8.4
58+
*
59+
* @param bool $refresh Whether to refresh the access token.
60+
* @return void
61+
*/
62+
public function getAccessToken( $refresh = false ) {
63+
// Check if user has an access token. If not, get one from the server.
64+
if ( aioseo()->internalOptions->internal->ai->accessToken && ! $refresh ) {
65+
return;
66+
}
67+
68+
if ( aioseo()->cache->get( 'ai-access-token-error' ) ) {
69+
return;
70+
}
71+
72+
$response = wp_remote_post( $this->getApiUrl() . 'ai/auth/', [
73+
'body' => [
74+
'domain' => aioseo()->helpers->getSiteDomain()
75+
]
76+
] );
77+
78+
if ( is_wp_error( $response ) ) {
79+
aioseo()->cache->update( 'ai-access-token-error', true, 1 * HOUR_IN_SECONDS );
80+
81+
// Schedule another, one-time event in approx. 1 hour from now.
82+
aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, 1 * ( HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ) ), [] );
83+
84+
return;
85+
}
86+
87+
$body = wp_remote_retrieve_body( $response );
88+
$data = json_decode( $body );
89+
if ( empty( $data->accessToken ) ) {
90+
aioseo()->cache->update( 'ai-access-token-error', true, 1 * HOUR_IN_SECONDS );
91+
92+
// Schedule another, one-time event in approx. 1 hour from now.
93+
aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, 1 * ( HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ) ), [] );
94+
95+
return;
96+
}
97+
98+
aioseo()->internalOptions->internal->ai->accessToken = sanitize_text_field( $data->accessToken );
99+
aioseo()->internalOptions->internal->ai->isTrialAccessToken = $data->isFree ?? false;
100+
101+
// Fetch the credit totals.
102+
$this->updateCredits( true );
103+
}
104+
105+
/**
106+
* Schedules the credit fetch action.
107+
*
108+
* @since 4.8.4
109+
*
110+
* @return void
111+
*/
112+
public function scheduleCreditFetchAction() {
113+
// If not set up, create a scheduled action to refresh the credits each day.
114+
if ( ! aioseo()->actionScheduler->isScheduled( $this->creditFetchAction ) ) {
115+
aioseo()->actionScheduler->scheduleRecurrent( $this->creditFetchAction, DAY_IN_SECONDS, DAY_IN_SECONDS, [] );
116+
}
117+
}
118+
119+
/**
120+
* Gets the credit data from the server and updates our options.
121+
*
122+
* @since 4.8.4
123+
*
124+
* @param bool $refresh Whether to refresh the credits forcefully.
125+
* @return void
126+
*/
127+
public function updateCredits( $refresh = false ) {
128+
if ( aioseo()->cache->get( 'ai-credits-error' ) && ! $refresh ) {
129+
return;
130+
}
131+
132+
if ( ! aioseo()->internalOptions->internal->ai->accessToken ) {
133+
return;
134+
}
135+
136+
$response = aioseo()->helpers->wpRemoteGet( $this->getApiUrl() . 'ai/credits/', [
137+
'headers' => $this->getRequestHeaders()
138+
] );
139+
140+
if ( is_wp_error( $response ) ) {
141+
aioseo()->cache->update( 'ai-credits-error', true, HOUR_IN_SECONDS );
142+
143+
// Schedule another, one-time event in approx. 1 hour from now.
144+
aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, 1 * ( HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ) ), [] );
145+
146+
return;
147+
}
148+
149+
$body = wp_remote_retrieve_body( $response );
150+
$data = json_decode( $body );
151+
if ( empty( $data->success ) ) {
152+
aioseo()->cache->update( 'ai-credits-error', true, HOUR_IN_SECONDS );
153+
154+
// Schedule another, one-time event in approx. 1 hour from now.
155+
aioseo()->actionScheduler->scheduleSingle( $this->creditFetchAction, 1 * ( HOUR_IN_SECONDS + wp_rand( 0, 30 * MINUTE_IN_SECONDS ) ), [] );
156+
157+
return;
158+
}
159+
160+
$orders = [];
161+
if ( ! empty( $data->orders ) ) {
162+
foreach ( $data->orders as $order ) {
163+
if (
164+
empty( $order->total ) ||
165+
! isset( $order->remaining ) ||
166+
! isset( $order->expires )
167+
) {
168+
continue;
169+
}
170+
171+
$orders[] = [
172+
'total' => intval( $order->total ),
173+
'remaining' => intval( $order->remaining ),
174+
'expires' => intval( $order->expires )
175+
];
176+
}
177+
}
178+
179+
aioseo()->internalOptions->internal->ai->credits->orders = $orders;
180+
aioseo()->internalOptions->internal->ai->credits->total = isset( $data->total ) ? intval( $data->total ) : 0;
181+
aioseo()->internalOptions->internal->ai->credits->remaining = isset( $data->remaining ) ? intval( $data->remaining ) : 0;
182+
183+
if ( ! empty( $data->license ) ) {
184+
aioseo()->internalOptions->internal->ai->credits->license->total = intval( $data->license->total );
185+
aioseo()->internalOptions->internal->ai->credits->license->remaining = intval( $data->license->remaining );
186+
aioseo()->internalOptions->internal->ai->credits->license->expires = intval( $data->license->expires );
187+
} else {
188+
aioseo()->internalOptions->internal->ai->credits->license->reset();
189+
}
190+
}
191+
192+
/**
193+
* Returns the default request headers.
194+
*
195+
* @since 4.8.4
196+
*
197+
* @return array The default request headers.
198+
*/
199+
protected function getRequestHeaders() {
200+
$headers = [
201+
'X-AIOSEO-Ai-Token' => aioseo()->internalOptions->internal->ai->accessToken,
202+
'X-AIOSEO-Ai-Domain' => aioseo()->helpers->getSiteDomain()
203+
];
204+
205+
return $headers;
206+
}
207+
208+
/**
209+
* Returns the API URL of the licensing server.
210+
*
211+
* @since 4.8.4
212+
*
213+
* @return string The URL.
214+
*/
215+
protected function getApiUrl() {
216+
if ( defined( 'AIOSEO_LICENSING_URL' ) ) {
217+
return AIOSEO_LICENSING_URL;
218+
}
219+
220+
return $this->licensingUrl;
221+
}
222+
}

0 commit comments

Comments
 (0)