Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
wp-content
/
plugins
/
woocommerce
/
src
/
Internal
/
Admin
/
Notes
:
ExtensionsWithoutSubscription.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php declare( strict_types = 1 ); namespace Automattic\WooCommerce\Internal\Admin\Notes; defined( 'ABSPATH' ) || exit; use Automattic\WooCommerce\Admin\Notes\Note; use Automattic\WooCommerce\Admin\Notes\NoteTraits; use Automattic\WooCommerce\Admin\Notes\Notes; use Automattic\WooCommerce\Admin\PageController; /** * Inbox note for active WooCommerce.com extensions that have no subscription on this store. */ class ExtensionsWithoutSubscription { use NoteTraits; /** * Name of the note for use in the database. */ const NOTE_NAME = 'wc-admin-extensions-without-subscription'; /** * Option holding when the note last fetched the subscription list from WooCommerce.com. */ const LAST_FETCH_OPTION_KEY = 'woocommerce_admin-extensions-without-subscription-last-fetch'; /** * Option holding the plugin files the note was last refreshed for, so unchanged page loads skip the notes table. */ const LAST_PLUGINS_OPTION_KEY = 'woocommerce_admin-extensions-without-subscription-last-plugins'; /** * Hook the note refresh. * * @since 11.3.0 */ public function __construct() { add_action( 'admin_head', array( $this, 'refresh_note' ) ); } /** * Add, update or remove the note on WooCommerce admin pages, so it follows the installed extensions. * * Runs on every WooCommerce admin page, so it only touches the notes table when the set of * extensions without a subscription differs from the last refresh. * * @since 11.3.0 */ public function refresh_note(): void { if ( ! PageController::is_admin_or_embed_page() ) { return; } // Try the cached subscription list first, so a store with nothing to check never reads the fetch budget. $plugins = self::get_plugins( false ); if ( null === $plugins && self::may_fetch() ) { $plugins = self::get_plugins( true ); } // Leave the note as it is while the subscription list can't be trusted. if ( null === $plugins ) { return; } $plugin_files = array_keys( $plugins ); sort( $plugin_files ); if ( get_option( self::LAST_PLUGINS_OPTION_KEY ) === $plugin_files ) { return; } if ( empty( $plugins ) ) { self::delete_note_unless_dismissed_or_actioned(); } elseif ( self::note_exists() ) { self::possibly_update_note(); } else { self::possibly_add_note(); } update_option( self::LAST_PLUGINS_OPTION_KEY, $plugin_files, true ); } /** * Get the note. * * @since 11.3.0 * * @return Note|null */ public static function get_note() { $plugins = self::get_plugins(); if ( empty( $plugins ) ) { return null; } if ( 1 === count( $plugins ) ) { $title = sprintf( /* translators: %s: extension name */ __( '%s doesn\'t have an active subscription', 'woocommerce' ), wp_strip_all_tags( current( $plugins )['Name'] ) ); $content = __( 'Without one, it won\'t receive security updates, product improvements, or support. Subscribe on WooCommerce.com to keep it protected.', 'woocommerce' ); } else { $title = __( 'Some of your extensions don\'t have an active subscription', 'woocommerce' ); $content = __( 'Without one, they won\'t receive security updates, product improvements, or support. Subscribe on WooCommerce.com to keep them protected.', 'woocommerce' ); } $note = new Note(); $note->set_title( $title ); $note->set_content( $content ); $note->set_content_data( (object) array( 'plugins' => array_keys( $plugins ) ) ); $note->set_type( Note::E_WC_ADMIN_NOTE_WARNING ); $note->set_name( self::NOTE_NAME ); $note->set_source( 'woocommerce-admin' ); $note->add_action( 'subscribe', __( 'Subscribe', 'woocommerce' ), add_query_arg( array( 'page' => 'wc-admin', 'tab' => 'my-subscriptions', 'path' => rawurlencode( '/extensions' ), 'utm_source' => 'inbox_notification', 'utm_campaign' => 'pu_inbox_purchase', ), admin_url( 'admin.php' ) ) ); return $note; } /** * Delete the note now that nothing is missing a subscription, unless the merchant already dealt with it. * * A dismissed or actioned note is hidden anyway, and keeping it means it stays that way if the * extensions come back, for example after deactivating every plugin to find a conflict. * * @return void */ private static function delete_note_unless_dismissed_or_actioned(): void { $note = Notes::get_note_by_name( self::NOTE_NAME ); if ( ! $note instanceof Note ) { return; } if ( $note->get_is_deleted() || Note::E_WC_ADMIN_NOTE_ACTIONED === $note->get_status() ) { return; } self::possibly_delete_note(); } /** * Whether the note should exist. * * The note follows the installed extensions through refresh_note(), so it's always * applicable once added. * * @return bool */ public static function is_applicable(): bool { return true; } /** * Whether this page load may fetch the subscription list from WooCommerce.com. * * The fetch blocks the page, so only a connected store without a cached list fetches: once a day, * or right after it connects. * * @return bool */ private static function may_fetch(): bool { if ( ! class_exists( 'WC_Helper' ) ) { return false; } // Nothing to fetch: a store that isn't connected has no list, and a cached one is already in use. if ( ! \WC_Helper::is_site_connected() || \WC_Helper::has_cached_subscriptions() ) { return false; } // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Read only, the same signal WooSubscriptionsNotes uses. if ( isset( $_GET['wc-helper-status'] ) ) { return true; } $now = time(); if ( (int) get_option( self::LAST_FETCH_OPTION_KEY, 0 ) + DAY_IN_SECONDS > $now ) { return false; } update_option( self::LAST_FETCH_OPTION_KEY, $now, false ); return true; } /** * Active WooCommerce.com extensions without a subscription, or null when that can't be known. * * @param bool $fetch Whether the subscription list may be fetched from WooCommerce.com when it isn't cached. * @return array|null */ private static function get_plugins( bool $fetch = true ): ?array { if ( ! class_exists( 'WC_Helper_Updater' ) ) { return null; } return \WC_Helper_Updater::get_plugins_without_subscription( $fetch ); } }