| @@ -9,14 +9,21 @@ | ||
| 9 | 9 | defined('ABSPATH') || die('No direct access.'); |
| 10 | 10 | |
| 11 | 11 | use Extendify\Config; |
| 12 | 12 | use Extendify\PartnerData; |
| 13 | +use Extendify\Notifications\Availability; | |
| 13 | 14 | use Extendify\Shared\Controllers\UserSelectionController; |
| 15 | +use Extendify\Shared\DataProvider\NotificationData; | |
| 14 | 16 | use Extendify\Shared\DataProvider\ResourceData; |
| 15 | 17 | use Extendify\Shared\Services\AdminMenuList; |
| 16 | 18 | use Extendify\Shared\Services\ApexDomain\ApexDomain; |
| 17 | 19 | use Extendify\Shared\Services\Escaper; |
| 18 | 20 | use Extendify\Shared\Services\PluginDependencies\SimplyBook; |
| 21 | +use Extendify\Shared\Services\PluginsActivation\Imagify as ImagifyActivation; | |
| 22 | +use Extendify\Shared\Services\PluginsActivation\Metricool as MetricoolActivation; | |
| 23 | +use Extendify\Shared\Services\PluginsActivation\SimplyBook as SimplyBookActivation; | |
| 24 | +use Extendify\Shared\Services\PluginsActivation\TranslatePress as TranslatePressActivation; | |
| 25 | +use Extendify\Shared\Services\SiteImages; | |
| 19 | 26 | use Extendify\SiteSettings; |
| 20 | 27 | use Extendify\Shared\Controllers\ImageGenerationController; |
| 21 | 28 | use Extendify\Shared\DataProvider\ProductsData; |
| 22 | 29 | |
| @@ -153,8 +160,41 @@ | ||
| 153 | 160 | return in_array($plugin['slug'], $activePluginSlugs); |
| 154 | 161 | } |
| 155 | 162 | ); |
| 156 | 163 | |
| 164 | + $activations = [ | |
| 165 | + ImagifyActivation::class, | |
| 166 | + MetricoolActivation::class, | |
| 167 | + SimplyBookActivation::class, | |
| 168 | + TranslatePressActivation::class, | |
| 169 | + ]; | |
| 170 | + | |
| 171 | + $productActivationPlugins = array_map(function ($plugin) use ($activations) { | |
| 172 | + foreach ($activations as $activation) { | |
| 173 | + if ($plugin['slug'] === $activation::slug()) { | |
| 174 | + return array_merge($plugin, [ | |
| 175 | + 'scriptData' => $activation::scriptData(), | |
| 176 | + 'eligible' => $activation::isEligible(), | |
| 177 | + 'endpoint' => Config::$slug . '/' . Config::$apiVersion | |
| 178 | + . $activation::createAccountRoute(), | |
| 179 | + ]); | |
| 180 | + } | |
| 181 | + } | |
| 182 | + | |
| 183 | + return $plugin; | |
| 184 | + }, $productActivationPlugins); | |
| 185 | + | |
| 186 | + // Visitors read the stamp and the alt text, so both resolve in the site's locale. | |
| 187 | + $switchedLocale = \switch_to_locale(\get_locale()); | |
| 188 | + // translators: Short label stamped onto an image marking it as AI-generated. | |
| 189 | + // Give the all-caps form your language uses. | |
| 190 | + $aiImageLabel = \_x('AI GENERATED', 'uppercase', 'extendify-local'); | |
| 191 | + // translators: %s is the image description. Alt text prefix marking an image as AI-generated. | |
| 192 | + $aiImageAltPattern = \__('AI Generated: %s', 'extendify-local'); | |
| 193 | + if ($switchedLocale) { | |
| 194 | + \restore_previous_locale(); | |
| 195 | + } | |
| 196 | + | |
| 157 | 197 | $extendifyCodeData = (array) PartnerData::setting('extendifyCodeData'); |
| 158 | 198 | |
| 159 | 199 | // esc_url() strips the {DESCRIPTION} braces; shield the placeholder across it. |
| 160 | 200 | $extendifyCodeLink = str_replace( |
| @@ -181,9 +221,13 @@ | ||
| 181 | 221 | 'themeSlug' => \esc_attr(\get_option('stylesheet')), |
| 182 | 222 | 'version' => \esc_attr(Config::$version), |
| 183 | 223 | 'siteTitle' => \esc_attr(\get_bloginfo('name')), |
| 184 | 224 | 'siteProfile' => \get_option('extendify_site_profile', []), |
| 225 | + // Empty when the launch-time image fetch failed. | |
| 226 | + 'siteImages' => SiteImages::normalize(\get_option('extendify_site_images', [])), | |
| 185 | 227 | 'wpLanguage' => \esc_attr(\get_locale()), |
| 228 | + 'aiImageLabel' => $aiImageLabel, | |
| 229 | + 'aiImageAltPattern' => $aiImageAltPattern, | |
| 186 | 230 | 'wpVersion' => \esc_attr(\get_bloginfo('version')), |
| 187 | 231 | 'isBlockTheme' => function_exists('wp_is_block_theme') ? (bool) wp_is_block_theme() : false, |
| 188 | 232 | 'userId' => \esc_attr(\get_current_user_id()), |
| 189 | 233 | // phpcs:ignore WordPress.Security.NonceVerification |
| @@ -194,8 +238,16 @@ | ||
| 194 | 238 | 'partnerId' => \esc_attr(PartnerData::$id), |
| 195 | 239 | 'partnerName' => \esc_attr(PartnerData::$name), |
| 196 | 240 | 'launchDataLegacy' => \wp_json_encode((UserSelectionController::get()->get_data() ?? [])), |
| 197 | 241 | 'resourceData' => \wp_json_encode((new ResourceData())->getData()), |
| 242 | + 'notifications' => \wp_json_encode( | |
| 243 | + Availability::available(NotificationData::get()) | |
| 244 | + ), | |
| 245 | + 'notificationState' => \get_user_meta( | |
| 246 | + \get_current_user_id(), | |
| 247 | + 'extendify_notification_state', | |
| 248 | + true | |
| 249 | + ) ?: ['cards' => []], | |
| 198 | 250 | 'showAIConsent' => isset($partnerData['showAIConsent']) ? (bool) $partnerData['showAIConsent'] : false, |
| 199 | 251 | 'showChat' => (bool) (PartnerData::setting('showChat') || constant('EXTENDIFY_DEVMODE')), |
| 200 | 252 | 'useAgentOnboarding' => (bool) ( |
| 201 | 253 | PartnerData::setting('useAgentOnboarding') || |
| @@ -207,10 +259,12 @@ | ||
| 207 | 259 | ), |
| 208 | 260 | 'showAILogo' => (bool) PartnerData::setting('showAILogo'), |
| 209 | 261 | 'showImprint' => array_map('esc_attr', (array) PartnerData::setting('showImprint')), |
| 210 | 262 | 'showProductActivation' => array_values($productActivationPlugins), |
| 211 | - 'consentTermsCustom' => \wp_kses((html_entity_decode(($partnerData['consentTermsCustom'] ?? '')) | |
| 212 | - ?? ''), $htmlAllowlist), | |
| 263 | + 'consentTermsCustom' => \wp_kses((html_entity_decode( | |
| 264 | + ($partnerData['consentTermsCustom'] ?? ''), | |
| 265 | + ENT_QUOTES | ENT_SUBSTITUTE | ENT_HTML401 | |
| 266 | + ) ?? ''), $htmlAllowlist), | |
| 213 | 267 | 'userGaveConsent' => $userConsent ? (bool) $userConsent : false, |
| 214 | 268 | 'installedPlugins' => array_map('esc_attr', array_keys(\get_plugins())), |
| 215 | 269 | 'activePlugins' => $activePlugins, |
| 216 | 270 | 'installedPluginsSlugs' => array_values(array_filter(array_map(function ($p) { |
| @@ -283,8 +337,15 @@ | ||
| 283 | 337 | 'type' => 'boolean', |
| 284 | 338 | 'show_in_rest' => true, |
| 285 | 339 | ]); |
| 286 | 340 | register_post_meta('post', 'made_with_extendify_launch', [ |
| 341 | + 'single' => true, | |
| 342 | + 'type' => 'boolean', | |
| 343 | + 'show_in_rest' => true, | |
| 344 | + ]); | |
| 345 | + | |
| 346 | + // Marks AI-generated images for EU AI Act disclosure. | |
| 347 | + register_post_meta('attachment', 'extendify_ai_generated', [ | |
| 287 | 348 | 'single' => true, |
| 288 | 349 | 'type' => 'boolean', |
| 289 | 350 | 'show_in_rest' => true, |
| 290 | 351 | ]); |